--- a/.hgtags Fri Sep 06 09:55:59 2013 +0100
+++ b/.hgtags Sat Sep 14 20:43:34 2013 +0100
@@ -228,3 +228,4 @@
b5ed503c26ad38869c247c5e32debec217fd056b jdk8-b104
589f4fdc584e373a47cde0162e9eceec9165c381 jdk8-b105
514b0b69fb9683ef52062fd962a3e0644431f64d jdk8-b106
+892889f445755790ae90e61775bfb59ddc6182b5 jdk8-b107
--- a/.hgtags-top-repo Fri Sep 06 09:55:59 2013 +0100
+++ b/.hgtags-top-repo Sat Sep 14 20:43:34 2013 +0100
@@ -228,3 +228,4 @@
96c1b9b7524b52c3fcefc90ffad4c767396727c8 jdk8-b104
5166118c59178b5d31001bc4058e92486ee07d9b jdk8-b105
8e7b4d9fb00fdf1334376aeac050c9bca6d1b383 jdk8-b106
+0874bb4707b723d5bb108d379c557cf41529d1a7 jdk8-b107
--- a/Makefile Fri Sep 06 09:55:59 2013 +0100
+++ b/Makefile Sat Sep 14 20:43:34 2013 +0100
@@ -404,7 +404,6 @@
CACERTS_FILE.desc = Location of certificates file
DEVTOOLS_PATH.desc = Directory containing zip and gnumake
CUPS_HEADERS_PATH.desc = Include directory location for CUPS header files
-DXSDK_PATH.desc = Root directory of DirectX SDK
# Make variables to print out (description and value)
VARIABLE_PRINTVAL_LIST += \
@@ -429,17 +428,6 @@
VARIABLE_CHECKFIL_LIST += \
CACERTS_FILE
-# Some are windows specific
-ifeq ($(PLATFORM), windows)
-
-VARIABLE_PRINTVAL_LIST += \
- DXSDK_PATH
-
-VARIABLE_CHECKDIR_LIST += \
- DXSDK_PATH
-
-endif
-
# For pattern rules below, so all are treated the same
DO_PRINTVAL_LIST=$(VARIABLE_PRINTVAL_LIST:%=%.printval)
DO_CHECKDIR_LIST=$(VARIABLE_CHECKDIR_LIST:%=%.checkdir)
--- a/README-builds.html Fri Sep 06 09:55:59 2013 +0100
+++ b/README-builds.html Sat Sep 14 20:43:34 2013 +0100
@@ -444,10 +444,6 @@
Install
<a href="#vs2010">Visual Studio 2010</a>
</li>
- <li>
- Install the
- <a href="#dxsdk">Microsoft DirectX SDK</a>
- </li>
</ul>
</td>
<td>
@@ -972,25 +968,6 @@
</td>
</tr>
<tr>
- <td><b><code>--with-dxsdk=</code></b><i>path</i></td>
- <td>
- select location of the Windows Direct X SDK install
- <br>
- The <a name="dxsdk">Microsoft DirectX 9.0 SDK</a>
- header files and libraries
- from the Summer 2004 edition
- are required for building OpenJDK.
- This SDK can be downloaded from
- <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=FD044A42-9912-42A3-9A9E-D857199F888E&displaylang=en" target="_blank">
- Microsoft DirectX 9.0 SDK (Summer 2004)</a>.
- If the link above becomes obsolete, the SDK can be found from
- <a href="http://download.microsoft.com" target="_blank">the Microsoft Download Site</a>
- (search with "DirectX 9.0 SDK Update Summer 2004").
- Installation usually will set the environment variable
- <code>DXSDK_DIR</code> to it's install location.
- </td>
- </tr>
- <tr>
<td><b><code>--with-freetype=</code></b><i>path</i></td>
<td>
select the freetype files to use.
--- a/common/autoconf/basics.m4 Fri Sep 06 09:55:59 2013 +0100
+++ b/common/autoconf/basics.m4 Sat Sep 14 20:43:34 2013 +0100
@@ -203,6 +203,15 @@
fi
])
+# Register a --with argument but mark it as deprecated
+# $1: The name of the with argument to deprecate, not including --with-
+AC_DEFUN([BASIC_DEPRECATED_ARG_WITH],
+[
+ AC_ARG_WITH($1, [AS_HELP_STRING([--with-$1],
+ [Deprecated. Option is kept for backwards compatibility and is ignored])],
+ [AC_MSG_WARN([Option --with-$1 is deprecated and will be ignored.])])
+])
+
AC_DEFUN_ONCE([BASIC_INIT],
[
# Save the original command line. This is passed to us by the wrapper configure script.
--- a/common/autoconf/basics_windows.m4 Fri Sep 06 09:55:59 2013 +0100
+++ b/common/autoconf/basics_windows.m4 Sat Sep 14 20:43:34 2013 +0100
@@ -211,7 +211,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
--- a/common/autoconf/build-aux/autoconf-config.guess Fri Sep 06 09:55:59 2013 +0100
+++ b/common/autoconf/build-aux/autoconf-config.guess Sat Sep 14 20:43:34 2013 +0100
@@ -26,10 +26,10 @@
# Attempt to guess a canonical system name.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
-# Free Software Foundation, Inc.
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+# 2011, 2012 Free Software Foundation, Inc.
-timestamp='2008-01-23'
+timestamp='2012-02-10'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -42,9 +42,7 @@
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-# 02110-1301, USA.
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
@@ -52,16 +50,16 @@
# the same distribution terms that you use for the rest of that program.
-# Originally written by Per Bothner <per@bothner.com>.
-# Please send patches to <config-patches@gnu.org>. Submit a context
-# diff and a properly formatted ChangeLog entry.
+# Originally written by Per Bothner. Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
#
# This script attempts to guess a canonical system name similar to
# config.sub. If it succeeds, it prints the system name on stdout, and
# exits with 0. Otherwise, it exits with 1.
#
-# The plan is that this can be called by configure scripts if you
-# don't specify an explicit build system type.
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
me=`echo "$0" | sed -e 's,.*/,,'`
@@ -81,8 +79,9 @@
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -169,7 +168,7 @@
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:NetBSD:*:*)
# NetBSD (nbsd) targets should (where applicable) match one or
- # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
# *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
# switched to ELF, *-*-netbsd* would select the old
# object file format. This provides both forward
@@ -195,7 +194,7 @@
arm*|i386|m68k|ns32k|sh3*|sparc|vax)
eval $set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
- | grep __ELF__ >/dev/null
+ | grep -q __ELF__
then
# Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
# Return netbsd for either. FIX?
@@ -205,7 +204,7 @@
fi
;;
*)
- os=netbsd
+ os=netbsd
;;
esac
# The OS release
@@ -248,7 +247,7 @@
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
;;
*5.*)
- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
;;
esac
# According to Compaq, /usr/sbin/psrinfo has been available on
@@ -294,7 +293,10 @@
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- exit ;;
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ exitcode=$?
+ trap '' 0
+ exit $exitcode ;;
Alpha\ *:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# Should we change UNAME_MACHINE based on the output of uname instead
@@ -320,7 +322,7 @@
echo s390-ibm-zvmoe
exit ;;
*:OS400:*:*)
- echo powerpc-ibm-os400
+ echo powerpc-ibm-os400
exit ;;
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
echo arm-acorn-riscix${UNAME_RELEASE}
@@ -349,14 +351,33 @@
case `/usr/bin/uname -p` in
sparc) echo sparc-icl-nx7; exit ;;
esac ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
sun4H:SunOS:5.*:*)
echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux${UNAME_RELEASE}
+ exit ;;
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
- echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ eval $set_cc_for_build
+ SUN_ARCH="i386"
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH="x86_64"
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
@@ -400,23 +421,23 @@
# MiNT. But MiNT is downward compatible to TOS, so this should
# be no problem.
atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
+ echo m68k-atari-mint${UNAME_RELEASE}
exit ;;
atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
- exit ;;
+ exit ;;
*falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
+ echo m68k-atari-mint${UNAME_RELEASE}
exit ;;
milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
- echo m68k-milan-mint${UNAME_RELEASE}
- exit ;;
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
- echo m68k-hades-mint${UNAME_RELEASE}
- exit ;;
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
*:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
- echo m68k-unknown-mint${UNAME_RELEASE}
- exit ;;
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
m68k:machten:*:*)
echo m68k-apple-machten${UNAME_RELEASE}
exit ;;
@@ -486,8 +507,8 @@
echo m88k-motorola-sysv3
exit ;;
AViiON:dgux:*:*)
- # DG/UX returns AViiON for all architectures
- UNAME_PROCESSOR=`/usr/bin/uname -p`
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
then
if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
@@ -500,7 +521,7 @@
else
echo i586-dg-dgux${UNAME_RELEASE}
fi
- exit ;;
+ exit ;;
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
echo m88k-dolphin-sysv3
exit ;;
@@ -557,7 +578,7 @@
echo rs6000-ibm-aix3.2
fi
exit ;;
- *:AIX:*:[456])
+ *:AIX:*:[4567])
IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
IBM_ARCH=rs6000
@@ -600,52 +621,52 @@
9000/[678][0-9][0-9])
if [ -x /usr/bin/getconf ]; then
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
- sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
- case "${sc_cpu_version}" in
- 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
- 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
- 532) # CPU_PA_RISC2_0
- case "${sc_kernel_bits}" in
- 32) HP_ARCH="hppa2.0n" ;;
- 64) HP_ARCH="hppa2.0w" ;;
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
'') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
- esac ;;
- esac
+ esac ;;
+ esac
fi
if [ "${HP_ARCH}" = "" ]; then
eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
+ sed 's/^ //' << EOF >$dummy.c
- #define _HPUX_SOURCE
- #include <stdlib.h>
- #include <unistd.h>
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
- int main ()
- {
- #if defined(_SC_KERNEL_BITS)
- long bits = sysconf(_SC_KERNEL_BITS);
- #endif
- long cpu = sysconf (_SC_CPU_VERSION);
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
- switch (cpu)
- {
- case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
- case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
- case CPU_PA_RISC2_0:
- #if defined(_SC_KERNEL_BITS)
- switch (bits)
- {
- case 64: puts ("hppa2.0w"); break;
- case 32: puts ("hppa2.0n"); break;
- default: puts ("hppa2.0"); break;
- } break;
- #else /* !defined(_SC_KERNEL_BITS) */
- puts ("hppa2.0"); break;
- #endif
- default: puts ("hppa1.0"); break;
- }
- exit (0);
- }
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
EOF
(CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
test -z "$HP_ARCH" && HP_ARCH=hppa
@@ -665,7 +686,7 @@
# => hppa64-hp-hpux11.23
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
- grep __LP64__ >/dev/null
+ grep -q __LP64__
then
HP_ARCH="hppa2.0w"
else
@@ -736,22 +757,22 @@
exit ;;
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
echo c1-convex-bsd
- exit ;;
+ exit ;;
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
else echo c2-convex-bsd
fi
- exit ;;
+ exit ;;
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
echo c34-convex-bsd
- exit ;;
+ exit ;;
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
echo c38-convex-bsd
- exit ;;
+ exit ;;
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
echo c4-convex-bsd
- exit ;;
+ exit ;;
CRAY*Y-MP:*:*:*)
echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
@@ -775,14 +796,14 @@
exit ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
- echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
5000:UNIX_System_V:4.*:*)
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
- echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
@@ -794,13 +815,12 @@
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
exit ;;
*:FreeBSD:*:*)
- case ${UNAME_MACHINE} in
- pc98)
- echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ case ${UNAME_PROCESSOR} in
amd64)
echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
*)
- echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
esac
exit ;;
i*:CYGWIN*:*)
@@ -809,19 +829,22 @@
*:MINGW*:*)
echo ${UNAME_MACHINE}-pc-mingw32
exit ;;
+ i*:MSYS*:*)
+ echo ${UNAME_MACHINE}-pc-msys
+ exit ;;
i*:windows32*:*)
- # uname -m includes "-pc" on this system.
- echo ${UNAME_MACHINE}-mingw32
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
exit ;;
i*:PW*:*)
echo ${UNAME_MACHINE}-pc-pw32
exit ;;
- *:Interix*:[3456]*)
- case ${UNAME_MACHINE} in
+ *:Interix*:*)
+ case ${UNAME_MACHINE} in
x86)
echo i586-pc-interix${UNAME_RELEASE}
exit ;;
- EM64T | authenticamd)
+ authenticamd | genuineintel | EM64T)
echo x86_64-unknown-interix${UNAME_RELEASE}
exit ;;
IA64)
@@ -831,6 +854,9 @@
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
echo i${UNAME_MACHINE}-pc-mks
exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
@@ -860,91 +886,12 @@
i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix
exit ;;
- arm*:Linux:*:*)
- eval $set_cc_for_build
- if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
- | grep -q __ARM_EABI__
- then
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- else
- echo ${UNAME_MACHINE}-unknown-linux-gnueabi
- fi
- exit ;;
- avr32*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- cris:Linux:*:*)
- echo cris-axis-linux-gnu
- exit ;;
- crisv32:Linux:*:*)
- echo crisv32-axis-linux-gnu
- exit ;;
- frv:Linux:*:*)
- echo frv-unknown-linux-gnu
- exit ;;
- ia64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- m32r*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- m68*:Linux:*:*)
+ aarch64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
- mips:Linux:*:*)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #undef CPU
- #undef mips
- #undef mipsel
- #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
- CPU=mipsel
- #else
- #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
- CPU=mips
- #else
- CPU=
- #endif
- #endif
-EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^CPU/{
- s: ::g
- p
- }'`"
- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
- ;;
- mips64:Linux:*:*)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #undef CPU
- #undef mips64
- #undef mips64el
- #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
- CPU=mips64el
- #else
- #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
- CPU=mips64
- #else
- CPU=
- #endif
- #endif
-EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^CPU/{
- s: ::g
- p
- }'`"
- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
- ;;
- or32:Linux:*:*)
- echo or32-unknown-linux-gnu
- exit ;;
- ppc:Linux:*:*)
- echo powerpc-unknown-linux-gnu
- exit ;;
- ppc64:Linux:*:*)
- echo powerpc64-unknown-linux-gnu
+ aarch64_be:Linux:*:*)
+ UNAME_MACHINE=aarch64_be
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
@@ -955,11 +902,90 @@
EV6) UNAME_MACHINE=alphaev6 ;;
EV67) UNAME_MACHINE=alphaev67 ;;
EV68*) UNAME_MACHINE=alphaev68 ;;
- esac
- objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
exit ;;
+ arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ else
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+ else
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabihf
+ fi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo ${UNAME_MACHINE}-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo ${UNAME_MACHINE}-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ hexagon:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ LIBC=gnu
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-gnu
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
@@ -968,14 +994,17 @@
*) echo hppa-unknown-linux-gnu ;;
esac
exit ;;
- parisc64:Linux:*:* | hppa64:Linux:*:*)
- echo hppa64-unknown-linux-gnu
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux
exit ;;
sh64*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
sh*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
@@ -983,78 +1012,18 @@
sparc:Linux:*:* | sparc64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
+ tile*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
vax:Linux:*:*)
echo ${UNAME_MACHINE}-dec-linux-gnu
exit ;;
x86_64:Linux:*:*)
- echo x86_64-unknown-linux-gnu
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
xtensa*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
- i*86:Linux:*:*)
- # The BFD linker knows what the default object file format is, so
- # first see if it will tell us. cd to the root directory to prevent
- # problems with other programs or directories called `ld' in the path.
- # Set LC_ALL=C to ensure ld outputs messages in English.
- ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
- | sed -ne '/supported targets:/!d
- s/[ ][ ]*/ /g
- s/.*supported targets: *//
- s/ .*//
- p'`
- case "$ld_supported_targets" in
- elf32-i386)
- TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
- ;;
- a.out-i386-linux)
- echo "${UNAME_MACHINE}-pc-linux-gnuaout"
- exit ;;
- coff-i386)
- echo "${UNAME_MACHINE}-pc-linux-gnucoff"
- exit ;;
- "")
- # Either a pre-BFD a.out linker (linux-gnuoldld) or
- # one that does not give us useful --help.
- echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
- exit ;;
- esac
- # Determine whether the default compiler is a.out or elf
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #include <features.h>
- #ifdef __ELF__
- # ifdef __GLIBC__
- # if __GLIBC__ >= 2
- LIBC=gnu
- # else
- LIBC=gnulibc1
- # endif
- # else
- LIBC=gnulibc1
- # endif
- #else
- #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
- LIBC=gnu
- #else
- LIBC=gnuaout
- #endif
- #endif
- #ifdef __dietlibc__
- LIBC=dietlibc
- #endif
-EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^LIBC/{
- s: ::g
- p
- }'`"
- test x"${LIBC}" != x && {
- echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
- exit
- }
- test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
- ;;
i*86:DYNIX/ptx:4*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
# earlier versions are messed up and put the nodename in both
@@ -1062,11 +1031,11 @@
echo i386-sequent-sysv4
exit ;;
i*86:UNIX_SV:4.2MP:2.*)
- # Unixware is an offshoot of SVR4, but it has its own version
- # number series starting with 2...
- # I am not positive that other SVR4 systems won't match this,
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
# I just have to hope. -- rms.
- # Use sysv4.2uw... so that sysv4* matches it.
+ # Use sysv4.2uw... so that sysv4* matches it.
echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
exit ;;
i*86:OS/2:*:*)
@@ -1083,7 +1052,7 @@
i*86:syllable:*:*)
echo ${UNAME_MACHINE}-pc-syllable
exit ;;
- i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
echo i386-unknown-lynxos${UNAME_RELEASE}
exit ;;
i*86:*DOS:*:*)
@@ -1098,7 +1067,7 @@
fi
exit ;;
i*86:*:5:[678]*)
- # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
case `/bin/uname -X | grep "^Machine"` in
*486*) UNAME_MACHINE=i486 ;;
*Pentium) UNAME_MACHINE=i586 ;;
@@ -1126,10 +1095,13 @@
exit ;;
pc:*:*:*)
# Left here for compatibility:
- # uname -m prints for DJGPP always 'pc', but it prints nothing about
- # the processor, so we play safe by assuming i386.
- echo i386-pc-msdosdjgpp
- exit ;;
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
Intel:Mach:3*:*)
echo i386-pc-mach3
exit ;;
@@ -1164,8 +1136,18 @@
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && { echo i486-ncr-sysv4; exit; } ;;
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
echo m68k-unknown-lynxos${UNAME_RELEASE}
exit ;;
@@ -1178,7 +1160,7 @@
rs6000:LynxOS:2.*:*)
echo rs6000-unknown-lynxos${UNAME_RELEASE}
exit ;;
- PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
echo powerpc-unknown-lynxos${UNAME_RELEASE}
exit ;;
SM[BE]S:UNIX_SV:*:*)
@@ -1198,10 +1180,10 @@
echo ns32k-sni-sysv
fi
exit ;;
- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
- # says <Richard.M.Bartel@ccMail.Census.GOV>
- echo i586-unisys-sysv4
- exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
*:UNIX_System_V:4*:FTX*)
# From Gerald Hewes <hewes@openmarket.com>.
# How about differentiating between stratus architectures? -djm
@@ -1227,11 +1209,11 @@
exit ;;
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
if [ -d /usr/nec ]; then
- echo mips-nec-sysv${UNAME_RELEASE}
+ echo mips-nec-sysv${UNAME_RELEASE}
else
- echo mips-unknown-sysv${UNAME_RELEASE}
+ echo mips-unknown-sysv${UNAME_RELEASE}
fi
- exit ;;
+ exit ;;
BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
echo powerpc-be-beos
exit ;;
@@ -1241,6 +1223,9 @@
BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
echo i586-pc-beos
exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
SX-4:SUPER-UX:*:*)
echo sx4-nec-superux${UNAME_RELEASE}
exit ;;
@@ -1267,12 +1252,17 @@
exit ;;
*:Darwin:*:*)
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
- eval $set_cc_for_build
- echo "int main(){}" > $dummy.c
- if test "`$CC_FOR_BUILD -o $dummy $dummy.c; file $dummy | grep -c x86_64`" = 1 ; then
- UNAME_PROCESSOR=x86_64
- fi
case $UNAME_PROCESSOR in
+ i386)
+ eval $set_cc_for_build
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ UNAME_PROCESSOR="x86_64"
+ fi
+ fi ;;
unknown) UNAME_PROCESSOR=powerpc ;;
esac
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
@@ -1288,6 +1278,9 @@
*:QNX:*:4*)
echo i386-pc-qnx
exit ;;
+ NEO-?:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk${UNAME_RELEASE}
+ exit ;;
NSE-?:NONSTOP_KERNEL:*:*)
echo nse-tandem-nsk${UNAME_RELEASE}
exit ;;
@@ -1333,13 +1326,13 @@
echo pdp10-unknown-its
exit ;;
SEI:*:*:SEIUX)
- echo mips-sei-seiux${UNAME_RELEASE}
+ echo mips-sei-seiux${UNAME_RELEASE}
exit ;;
*:DragonFly:*:*)
echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
exit ;;
*:*VMS:*:*)
- UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
case "${UNAME_MACHINE}" in
A*) echo alpha-dec-vms ; exit ;;
I*) echo ia64-dec-vms ; exit ;;
@@ -1354,6 +1347,12 @@
i*86:rdos:*:*)
echo ${UNAME_MACHINE}-pc-rdos
exit ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+ x86_64:VMkernel:*:*)
+ echo ${UNAME_MACHINE}-unknown-esx
+ exit ;;
esac
#echo '(No uname command or uname output not recognized.)' 1>&2
@@ -1376,11 +1375,11 @@
#include <sys/param.h>
printf ("m68k-sony-newsos%s\n",
#ifdef NEWSOS4
- "4"
+ "4"
#else
- ""
+ ""
#endif
- ); exit (0);
+ ); exit (0);
#endif
#endif
--- a/common/autoconf/configure Fri Sep 06 09:55:59 2013 +0100
+++ b/common/autoconf/configure Sat Sep 14 20:43:34 2013 +0100
@@ -219,9 +219,4 @@
echo configure exiting with result code $conf_result_code
fi
-# Move the log file to the output root, if this was successfully created
-if test -d "$OUTPUT_ROOT"; then
- mv -f config.log "$OUTPUT_ROOT" 2> /dev/null
-fi
-
exit $conf_result_code
--- a/common/autoconf/configure.ac Fri Sep 06 09:55:59 2013 +0100
+++ b/common/autoconf/configure.ac Sat Sep 14 20:43:34 2013 +0100
@@ -232,9 +232,15 @@
# We're messing a bit with internal autoconf variables to put the config.status
# in the output directory instead of the current directory.
CONFIG_STATUS="$OUTPUT_ROOT/config.status"
+
# Create the actual output files. Now the main work of configure is done.
AC_OUTPUT
+# Try to move the config.log file to the output directory.
+if test -e ./config.log; then
+ $MV -f ./config.log "$OUTPUT_ROOT/config.log" 2> /dev/null
+fi
+
# Make the compare script executable
$CHMOD +x $OUTPUT_ROOT/compare.sh
--- a/common/autoconf/generated-configure.sh Fri Sep 06 09:55:59 2013 +0100
+++ b/common/autoconf/generated-configure.sh Sat Sep 14 20:43:34 2013 +0100
@@ -709,7 +709,6 @@
SHARED_LIBRARY
OBJ_SUFFIX
COMPILER_NAME
-TARGET_BITS_FLAG
JT_HOME
JTREGEXE
LIPO
@@ -766,8 +765,6 @@
BUILD_CXX
BUILD_CC
MSVCR_DLL
-DXSDK_INCLUDE_PATH
-DXSDK_LIB_PATH
VS_PATH
VS_LIB
VS_INCLUDE
@@ -1031,6 +1028,7 @@
with_override_jaxp
with_override_jaxws
with_override_hotspot
+with_override_nashorn
with_override_jdk
with_import_hotspot
with_msvcr_dll
@@ -1784,17 +1782,19 @@
--with-override-jaxp use this jaxp dir for the build
--with-override-jaxws use this jaxws dir for the build
--with-override-hotspot use this hotspot dir for the build
+ --with-override-nashorn use this nashorn dir for the build
--with-override-jdk use this jdk dir for the build
--with-import-hotspot import hotspot binaries from this jdk image or
hotspot build dist dir instead of building from
source
--with-msvcr-dll copy this msvcr100.dll into the built JDK (Windows
only) [probed]
- --with-dxsdk the DirectX SDK (Windows only) [probed]
- --with-dxsdk-lib the DirectX SDK lib directory (Windows only)
- [probed]
- --with-dxsdk-include the DirectX SDK include directory (Windows only)
- [probed]
+ --with-dxsdk Deprecated. Option is kept for backwards
+ compatibility and is ignored
+ --with-dxsdk-lib Deprecated. Option is kept for backwards
+ compatibility and is ignored
+ --with-dxsdk-include Deprecated. Option is kept for backwards
+ compatibility and is ignored
--with-jtreg Regression Test Harness [probed]
--with-extra-cflags extra flags to be used when compiling jdk c-files
--with-extra-cxxflags extra flags to be used when compiling jdk c++-files
@@ -3144,6 +3144,10 @@
+# Register a --with argument but mark it as deprecated
+# $1: The name of the with argument to deprecate, not including --with-
+
+
# Test that variable $1 denoting a program is not empty. If empty, exit with an error.
@@ -3805,10 +3809,6 @@
-# Setup the DXSDK paths
-
-
-
@@ -3818,7 +3818,7 @@
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1378914658
+DATE_WHEN_GENERATED=1379504921
###############################################################################
#
@@ -8352,7 +8352,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -8709,7 +8709,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -9063,7 +9063,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -9422,7 +9422,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -9775,7 +9775,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -11075,7 +11075,7 @@
else
BUILD_DATE=`date '+%Y_%m_%d_%H_%M'`
# Avoid [:alnum:] since it depends on the locale.
- CLEAN_USERNAME=`echo "$USER" | $TR -d -c 'abcdefghijklmnopqrstuvqxyz0123456789'`
+ CLEAN_USERNAME=`echo "$USER" | $TR -d -c 'abcdefghijklmnopqrstuvqxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'`
USER_RELEASE_SUFFIX=`echo "${CLEAN_USERNAME}_${BUILD_DATE}" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
fi
@@ -16102,6 +16102,10 @@
test -f $with_add_source_root/hotspot/make/Makefile; then
as_fn_error $? "Your add source root seems to contain a full hotspot repo! An add source root should only contain additional sources." "$LINENO" 5
fi
+ if test -f $with_add_source_root/nashorn/makefiles/Makefile || \
+ test -f $with_add_source_root/nashorn/make/Makefile; then
+ as_fn_error $? "Your add source root seems to contain a full nashorn repo! An add source root should only contain additional sources." "$LINENO" 5
+ fi
if test -f $with_add_source_root/jdk/makefiles/Makefile || \
test -f $with_add_source_root/jdk/make/Makefile; then
as_fn_error $? "Your add source root seems to contain a full JDK repo! An add source root should only contain additional sources." "$LINENO" 5
@@ -16137,6 +16141,10 @@
test -f $with_override_source_root/hotspot/make/Makefile; then
as_fn_error $? "Your override source root seems to contain a full hotspot repo! An override source root should only contain sources that override." "$LINENO" 5
fi
+ if test -f $with_override_source_root/nashorn/makefiles/Makefile || \
+ test -f $with_override_source_root/nashorn/make/Makefile; then
+ as_fn_error $? "Your override source root seems to contain a full nashorn repo! An override source root should only contain sources that override." "$LINENO" 5
+ fi
if test -f $with_override_source_root/jdk/makefiles/Makefile || \
test -f $with_override_source_root/jdk/make/Makefile; then
as_fn_error $? "Your override source root seems to contain a full JDK repo! An override source root should only contain sources that override." "$LINENO" 5
@@ -16199,6 +16207,13 @@
+# Check whether --with-override-nashorn was given.
+if test "${with_override_nashorn+set}" = set; then :
+ withval=$with_override_nashorn;
+fi
+
+
+
# Check whether --with-override-jdk was given.
if test "${with_override_jdk+set}" = set; then :
withval=$with_override_jdk;
@@ -16276,7 +16291,7 @@
cd "$with_override_nashorn"
NASHORN_TOPDIR="`pwd`"
cd "$CURDIR"
- if ! test -f $NASHORN_TOPDIR/makefiles/BuildNashorn.gmk; then
+ if ! test -f $NASHORN_TOPDIR/makefiles/Makefile; then
as_fn_error $? "You have to override nashorn with a full nashorn repo!" "$LINENO" 5
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if nashorn should be overridden" >&5
@@ -17086,7 +17101,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -17586,436 +17601,28 @@
# Check whether --with-dxsdk was given.
if test "${with_dxsdk+set}" = set; then :
- withval=$with_dxsdk;
-fi
+ withval=$with_dxsdk; { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Option --with-dxsdk is deprecated and will be ignored." >&5
+$as_echo "$as_me: WARNING: Option --with-dxsdk is deprecated and will be ignored." >&2;}
+fi
+
+
# Check whether --with-dxsdk-lib was given.
if test "${with_dxsdk_lib+set}" = set; then :
- withval=$with_dxsdk_lib;
-fi
+ withval=$with_dxsdk_lib; { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Option --with-dxsdk-lib is deprecated and will be ignored." >&5
+$as_echo "$as_me: WARNING: Option --with-dxsdk-lib is deprecated and will be ignored." >&2;}
+fi
+
+
# Check whether --with-dxsdk-include was given.
if test "${with_dxsdk_include+set}" = set; then :
- withval=$with_dxsdk_include;
-fi
-
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DirectX SDK" >&5
-$as_echo_n "checking for DirectX SDK... " >&6; }
-
- if test "x$with_dxsdk" != x; then
- dxsdk_path="$with_dxsdk"
- elif test "x$DXSDK_DIR" != x; then
- dxsdk_path="$DXSDK_DIR"
- elif test -d "C:/DXSDK"; then
- dxsdk_path="C:/DXSDK"
- else
- as_fn_error $? "Could not find the DirectX SDK" "$LINENO" 5
- fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dxsdk_path" >&5
-$as_echo "$dxsdk_path" >&6; }
-
- if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
-
- # Input might be given as Windows format, start by converting to
- # unix format.
- path="$dxsdk_path"
- new_path=`$CYGPATH -u "$path"`
-
- # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
- # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
- # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
- # "foo.exe" is OK but "foo" is an error.
- #
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
- # It is also a way to make sure we got the proper file name for the real test later on.
- test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
- if test "x$test_shortpath" = x; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: The path of dxsdk_path, which resolves as \"$path\", is invalid." >&5
-$as_echo "$as_me: The path of dxsdk_path, which resolves as \"$path\", is invalid." >&6;}
- as_fn_error $? "Cannot locate the the path of dxsdk_path" "$LINENO" 5
- fi
-
- # Call helper function which possibly converts this using DOS-style short mode.
- # If so, the updated path is stored in $new_path.
-
- input_path="$new_path"
- # Check if we need to convert this using DOS-style short mode. If the path
- # contains just simple characters, use it. Otherwise (spaces, weird characters),
- # take no chances and rewrite it.
- # Note: m4 eats our [], so we need to use [ and ] instead.
- has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
- if test "x$has_forbidden_chars" != x; then
- # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
- shortmode_path=`$CYGPATH -s -m -a "$input_path"`
- path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
- if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
- # Going to short mode and back again did indeed matter. Since short mode is
- # case insensitive, let's make it lowercase to improve readability.
- shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- # Now convert it back to Unix-stile (cygpath)
- input_path=`$CYGPATH -u "$shortmode_path"`
- new_path="$input_path"
- fi
- fi
-
- test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
- if test "x$test_cygdrive_prefix" = x; then
- # As a simple fix, exclude /usr/bin since it's not a real path.
- if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
- # The path is in a Cygwin special directory (e.g. /home). We need this converted to
- # a path prefixed by /cygdrive for fixpath to work.
- new_path="$CYGWIN_ROOT_PATH$input_path"
- fi
- fi
-
-
- if test "x$path" != "x$new_path"; then
- dxsdk_path="$new_path"
- { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting dxsdk_path to \"$new_path\"" >&5
-$as_echo "$as_me: Rewriting dxsdk_path to \"$new_path\"" >&6;}
- fi
-
- elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
-
- path="$dxsdk_path"
- has_colon=`$ECHO $path | $GREP ^.:`
- new_path="$path"
- if test "x$has_colon" = x; then
- # Not in mixed or Windows style, start by that.
- new_path=`cmd //c echo $path`
- fi
-
-
- input_path="$new_path"
- # Check if we need to convert this using DOS-style short mode. If the path
- # contains just simple characters, use it. Otherwise (spaces, weird characters),
- # take no chances and rewrite it.
- # Note: m4 eats our [], so we need to use [ and ] instead.
- has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
- if test "x$has_forbidden_chars" != x; then
- # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
- new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- fi
-
-
- windows_path="$new_path"
- if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
- unix_path=`$CYGPATH -u "$windows_path"`
- new_path="$unix_path"
- elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
- unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
- new_path="$unix_path"
- fi
-
- if test "x$path" != "x$new_path"; then
- dxsdk_path="$new_path"
- { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting dxsdk_path to \"$new_path\"" >&5
-$as_echo "$as_me: Rewriting dxsdk_path to \"$new_path\"" >&6;}
- fi
-
- # Save the first 10 bytes of this path to the storage, so fixpath can work.
- all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
-
- else
- # We're on a posix platform. Hooray! :)
- path="$dxsdk_path"
- has_space=`$ECHO "$path" | $GREP " "`
- if test "x$has_space" != x; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: The path of dxsdk_path, which resolves as \"$path\", is invalid." >&5
-$as_echo "$as_me: The path of dxsdk_path, which resolves as \"$path\", is invalid." >&6;}
- as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
- fi
-
- # Use eval to expand a potential ~
- eval path="$path"
- if test ! -f "$path" && test ! -d "$path"; then
- as_fn_error $? "The path of dxsdk_path, which resolves as \"$path\", is not found." "$LINENO" 5
- fi
-
- dxsdk_path="`cd "$path"; $THEPWDCMD -L`"
- fi
-
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DirectX SDK lib dir" >&5
-$as_echo_n "checking for DirectX SDK lib dir... " >&6; }
- if test "x$with_dxsdk_lib" != x; then
- DXSDK_LIB_PATH="$with_dxsdk_lib"
- elif test "x$OPENJDK_TARGET_CPU" = "xx86_64"; then
- DXSDK_LIB_PATH="$dxsdk_path/Lib/x64"
- else
- DXSDK_LIB_PATH="$dxsdk_path/Lib"
- fi
- # dsound.lib is linked to in jsoundds
- if test ! -f "$DXSDK_LIB_PATH/dsound.lib"; then
- as_fn_error $? "Invalid DirectX SDK lib dir" "$LINENO" 5
- fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DXSDK_LIB_PATH" >&5
-$as_echo "$DXSDK_LIB_PATH" >&6; }
-
- if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
-
- # Input might be given as Windows format, start by converting to
- # unix format.
- path="$DXSDK_LIB_PATH"
- new_path=`$CYGPATH -u "$path"`
-
- # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
- # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
- # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
- # "foo.exe" is OK but "foo" is an error.
- #
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
- # It is also a way to make sure we got the proper file name for the real test later on.
- test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
- if test "x$test_shortpath" = x; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: The path of DXSDK_LIB_PATH, which resolves as \"$path\", is invalid." >&5
-$as_echo "$as_me: The path of DXSDK_LIB_PATH, which resolves as \"$path\", is invalid." >&6;}
- as_fn_error $? "Cannot locate the the path of DXSDK_LIB_PATH" "$LINENO" 5
- fi
-
- # Call helper function which possibly converts this using DOS-style short mode.
- # If so, the updated path is stored in $new_path.
-
- input_path="$new_path"
- # Check if we need to convert this using DOS-style short mode. If the path
- # contains just simple characters, use it. Otherwise (spaces, weird characters),
- # take no chances and rewrite it.
- # Note: m4 eats our [], so we need to use [ and ] instead.
- has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
- if test "x$has_forbidden_chars" != x; then
- # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
- shortmode_path=`$CYGPATH -s -m -a "$input_path"`
- path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
- if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
- # Going to short mode and back again did indeed matter. Since short mode is
- # case insensitive, let's make it lowercase to improve readability.
- shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- # Now convert it back to Unix-stile (cygpath)
- input_path=`$CYGPATH -u "$shortmode_path"`
- new_path="$input_path"
- fi
- fi
-
- test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
- if test "x$test_cygdrive_prefix" = x; then
- # As a simple fix, exclude /usr/bin since it's not a real path.
- if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
- # The path is in a Cygwin special directory (e.g. /home). We need this converted to
- # a path prefixed by /cygdrive for fixpath to work.
- new_path="$CYGWIN_ROOT_PATH$input_path"
- fi
- fi
-
-
- if test "x$path" != "x$new_path"; then
- DXSDK_LIB_PATH="$new_path"
- { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting DXSDK_LIB_PATH to \"$new_path\"" >&5
-$as_echo "$as_me: Rewriting DXSDK_LIB_PATH to \"$new_path\"" >&6;}
- fi
-
- elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
-
- path="$DXSDK_LIB_PATH"
- has_colon=`$ECHO $path | $GREP ^.:`
- new_path="$path"
- if test "x$has_colon" = x; then
- # Not in mixed or Windows style, start by that.
- new_path=`cmd //c echo $path`
- fi
-
-
- input_path="$new_path"
- # Check if we need to convert this using DOS-style short mode. If the path
- # contains just simple characters, use it. Otherwise (spaces, weird characters),
- # take no chances and rewrite it.
- # Note: m4 eats our [], so we need to use [ and ] instead.
- has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
- if test "x$has_forbidden_chars" != x; then
- # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
- new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- fi
-
-
- windows_path="$new_path"
- if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
- unix_path=`$CYGPATH -u "$windows_path"`
- new_path="$unix_path"
- elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
- unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
- new_path="$unix_path"
- fi
-
- if test "x$path" != "x$new_path"; then
- DXSDK_LIB_PATH="$new_path"
- { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting DXSDK_LIB_PATH to \"$new_path\"" >&5
-$as_echo "$as_me: Rewriting DXSDK_LIB_PATH to \"$new_path\"" >&6;}
- fi
-
- # Save the first 10 bytes of this path to the storage, so fixpath can work.
- all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
-
- else
- # We're on a posix platform. Hooray! :)
- path="$DXSDK_LIB_PATH"
- has_space=`$ECHO "$path" | $GREP " "`
- if test "x$has_space" != x; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: The path of DXSDK_LIB_PATH, which resolves as \"$path\", is invalid." >&5
-$as_echo "$as_me: The path of DXSDK_LIB_PATH, which resolves as \"$path\", is invalid." >&6;}
- as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
- fi
-
- # Use eval to expand a potential ~
- eval path="$path"
- if test ! -f "$path" && test ! -d "$path"; then
- as_fn_error $? "The path of DXSDK_LIB_PATH, which resolves as \"$path\", is not found." "$LINENO" 5
- fi
-
- DXSDK_LIB_PATH="`cd "$path"; $THEPWDCMD -L`"
- fi
-
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DirectX SDK include dir" >&5
-$as_echo_n "checking for DirectX SDK include dir... " >&6; }
- if test "x$with_dxsdk_include" != x; then
- DXSDK_INCLUDE_PATH="$with_dxsdk_include"
- else
- DXSDK_INCLUDE_PATH="$dxsdk_path/Include"
- fi
- # dsound.h is included in jsoundds
- if test ! -f "$DXSDK_INCLUDE_PATH/dsound.h"; then
- as_fn_error $? "Invalid DirectX SDK lib dir" "$LINENO" 5
- fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DXSDK_INCLUDE_PATH" >&5
-$as_echo "$DXSDK_INCLUDE_PATH" >&6; }
-
- if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
-
- # Input might be given as Windows format, start by converting to
- # unix format.
- path="$DXSDK_INCLUDE_PATH"
- new_path=`$CYGPATH -u "$path"`
-
- # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
- # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
- # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
- # "foo.exe" is OK but "foo" is an error.
- #
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
- # It is also a way to make sure we got the proper file name for the real test later on.
- test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
- if test "x$test_shortpath" = x; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: The path of DXSDK_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5
-$as_echo "$as_me: The path of DXSDK_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;}
- as_fn_error $? "Cannot locate the the path of DXSDK_INCLUDE_PATH" "$LINENO" 5
- fi
-
- # Call helper function which possibly converts this using DOS-style short mode.
- # If so, the updated path is stored in $new_path.
-
- input_path="$new_path"
- # Check if we need to convert this using DOS-style short mode. If the path
- # contains just simple characters, use it. Otherwise (spaces, weird characters),
- # take no chances and rewrite it.
- # Note: m4 eats our [], so we need to use [ and ] instead.
- has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
- if test "x$has_forbidden_chars" != x; then
- # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
- shortmode_path=`$CYGPATH -s -m -a "$input_path"`
- path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
- if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
- # Going to short mode and back again did indeed matter. Since short mode is
- # case insensitive, let's make it lowercase to improve readability.
- shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- # Now convert it back to Unix-stile (cygpath)
- input_path=`$CYGPATH -u "$shortmode_path"`
- new_path="$input_path"
- fi
- fi
-
- test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
- if test "x$test_cygdrive_prefix" = x; then
- # As a simple fix, exclude /usr/bin since it's not a real path.
- if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
- # The path is in a Cygwin special directory (e.g. /home). We need this converted to
- # a path prefixed by /cygdrive for fixpath to work.
- new_path="$CYGWIN_ROOT_PATH$input_path"
- fi
- fi
-
-
- if test "x$path" != "x$new_path"; then
- DXSDK_INCLUDE_PATH="$new_path"
- { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting DXSDK_INCLUDE_PATH to \"$new_path\"" >&5
-$as_echo "$as_me: Rewriting DXSDK_INCLUDE_PATH to \"$new_path\"" >&6;}
- fi
-
- elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
-
- path="$DXSDK_INCLUDE_PATH"
- has_colon=`$ECHO $path | $GREP ^.:`
- new_path="$path"
- if test "x$has_colon" = x; then
- # Not in mixed or Windows style, start by that.
- new_path=`cmd //c echo $path`
- fi
-
-
- input_path="$new_path"
- # Check if we need to convert this using DOS-style short mode. If the path
- # contains just simple characters, use it. Otherwise (spaces, weird characters),
- # take no chances and rewrite it.
- # Note: m4 eats our [], so we need to use [ and ] instead.
- has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
- if test "x$has_forbidden_chars" != x; then
- # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
- new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- fi
-
-
- windows_path="$new_path"
- if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
- unix_path=`$CYGPATH -u "$windows_path"`
- new_path="$unix_path"
- elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
- unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
- new_path="$unix_path"
- fi
-
- if test "x$path" != "x$new_path"; then
- DXSDK_INCLUDE_PATH="$new_path"
- { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting DXSDK_INCLUDE_PATH to \"$new_path\"" >&5
-$as_echo "$as_me: Rewriting DXSDK_INCLUDE_PATH to \"$new_path\"" >&6;}
- fi
-
- # Save the first 10 bytes of this path to the storage, so fixpath can work.
- all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
-
- else
- # We're on a posix platform. Hooray! :)
- path="$DXSDK_INCLUDE_PATH"
- has_space=`$ECHO "$path" | $GREP " "`
- if test "x$has_space" != x; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: The path of DXSDK_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5
-$as_echo "$as_me: The path of DXSDK_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;}
- as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
- fi
-
- # Use eval to expand a potential ~
- eval path="$path"
- if test ! -f "$path" && test ! -d "$path"; then
- as_fn_error $? "The path of DXSDK_INCLUDE_PATH, which resolves as \"$path\", is not found." "$LINENO" 5
- fi
-
- DXSDK_INCLUDE_PATH="`cd "$path"; $THEPWDCMD -L`"
- fi
-
-
-
-
- LDFLAGS_JDK="$LDFLAGS_JDK -libpath:$DXSDK_LIB_PATH"
+ withval=$with_dxsdk_include; { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Option --with-dxsdk-include is deprecated and will be ignored." >&5
+$as_echo "$as_me: WARNING: Option --with-dxsdk-include is deprecated and will be ignored." >&2;}
+fi
+
fi
@@ -18140,7 +17747,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -18451,7 +18058,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -18757,7 +18364,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -19350,7 +18957,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -19786,7 +19393,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -20922,7 +20529,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -21358,7 +20965,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -22259,7 +21866,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -22640,7 +22247,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -22987,7 +22594,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -23324,7 +22931,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -23645,7 +23252,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -24020,7 +23627,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -24326,7 +23933,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -24737,7 +24344,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -25137,7 +24744,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -25466,7 +25073,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -25778,7 +25385,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -26084,7 +25691,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -26390,7 +25997,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -26696,7 +26303,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -27055,7 +26662,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -27415,7 +27022,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -27788,7 +27395,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -28159,7 +27766,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -28468,7 +28075,7 @@
# the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
# "foo.exe" is OK but "foo" is an error.
#
- # This test is therefore slightly more accurate than "test -f" to check for file precense.
+ # This test is therefore slightly more accurate than "test -f" to check for file presence.
# It is also a way to make sure we got the proper file name for the real test later on.
test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
if test "x$test_shortpath" = x; then
@@ -28830,35 +28437,41 @@
if test "x$OPENJDK_TARGET_OS" = xsolaris; then
# Always specify -m flags on Solaris
- # keep track of c/cxx flags that we added outselves...
- # to prevent emitting warning...
- TARGET_BITS_FLAG="-m${OPENJDK_TARGET_CPU_BITS}"
-
-
- CFLAGS="${CFLAGS} ${TARGET_BITS_FLAG}"
- CXXFLAGS="${CXXFLAGS} ${TARGET_BITS_FLAG}"
- LDFLAGS="${LDFLAGS} ${TARGET_BITS_FLAG}"
-
- CFLAGS_JDK="${CFLAGS_JDK} ${TARGET_BITS_FLAG}"
- CXXFLAGS_JDK="${CXXFLAGS_JDK} ${TARGET_BITS_FLAG}"
- LDFLAGS_JDK="${LDFLAGS_JDK} ${TARGET_BITS_FLAG}"
+ # When we add flags to the "official" CFLAGS etc, we need to
+ # keep track of these additions in ADDED_CFLAGS etc. These
+ # will later be checked to make sure only controlled additions
+ # have been made to CFLAGS etc.
+ ADDED_CFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
+ ADDED_CXXFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
+ ADDED_LDFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
+
+ CFLAGS="${CFLAGS}${ADDED_CFLAGS}"
+ CXXFLAGS="${CXXFLAGS}${ADDED_CXXFLAGS}"
+ LDFLAGS="${LDFLAGS}${ADDED_LDFLAGS}"
+
+ CFLAGS_JDK="${CFLAGS_JDK}${ADDED_CFLAGS}"
+ CXXFLAGS_JDK="${CXXFLAGS_JDK}${ADDED_CXXFLAGS}"
+ LDFLAGS_JDK="${LDFLAGS_JDK}${ADDED_LDFLAGS}"
elif test "x$COMPILE_TYPE" = xreduced; then
if test "x$OPENJDK_TARGET_OS" != xwindows; then
# Specify -m if running reduced on other Posix platforms
- # keep track of c/cxx flags that we added outselves...
- # to prevent emitting warning...
- TARGET_BITS_FLAG="-m${OPENJDK_TARGET_CPU_BITS}"
-
-
- CFLAGS="${CFLAGS} ${TARGET_BITS_FLAG}"
- CXXFLAGS="${CXXFLAGS} ${TARGET_BITS_FLAG}"
- LDFLAGS="${LDFLAGS} ${TARGET_BITS_FLAG}"
-
- CFLAGS_JDK="${CFLAGS_JDK} ${TARGET_BITS_FLAG}"
- CXXFLAGS_JDK="${CXXFLAGS_JDK} ${TARGET_BITS_FLAG}"
- LDFLAGS_JDK="${LDFLAGS_JDK} ${TARGET_BITS_FLAG}"
+ # When we add flags to the "official" CFLAGS etc, we need to
+ # keep track of these additions in ADDED_CFLAGS etc. These
+ # will later be checked to make sure only controlled additions
+ # have been made to CFLAGS etc.
+ ADDED_CFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
+ ADDED_CXXFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
+ ADDED_LDFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
+
+ CFLAGS="${CFLAGS}${ADDED_CFLAGS}"
+ CXXFLAGS="${CXXFLAGS}${ADDED_CXXFLAGS}"
+ LDFLAGS="${LDFLAGS}${ADDED_LDFLAGS}"
+
+ CFLAGS_JDK="${CFLAGS_JDK}${ADDED_CFLAGS}"
+ CXXFLAGS_JDK="${CXXFLAGS_JDK}${ADDED_CXXFLAGS}"
+ LDFLAGS_JDK="${LDFLAGS_JDK}${ADDED_LDFLAGS}"
fi
fi
@@ -33618,6 +33231,7 @@
# We're messing a bit with internal autoconf variables to put the config.status
# in the output directory instead of the current directory.
CONFIG_STATUS="$OUTPUT_ROOT/config.status"
+
# Create the actual output files. Now the main work of configure is done.
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -34899,6 +34513,11 @@
fi
+# Try to move the config.log file to the output directory.
+if test -e ./config.log; then
+ $MV -f ./config.log "$OUTPUT_ROOT/config.log" 2> /dev/null
+fi
+
# Make the compare script executable
$CHMOD +x $OUTPUT_ROOT/compare.sh
--- a/common/autoconf/jdk-options.m4 Fri Sep 06 09:55:59 2013 +0100
+++ b/common/autoconf/jdk-options.m4 Sat Sep 14 20:43:34 2013 +0100
@@ -446,7 +446,7 @@
else
BUILD_DATE=`date '+%Y_%m_%d_%H_%M'`
# Avoid [:alnum:] since it depends on the locale.
- CLEAN_USERNAME=`echo "$USER" | $TR -d -c 'abcdefghijklmnopqrstuvqxyz0123456789'`
+ CLEAN_USERNAME=`echo "$USER" | $TR -d -c 'abcdefghijklmnopqrstuvqxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'`
USER_RELEASE_SUFFIX=`echo "${CLEAN_USERNAME}_${BUILD_DATE}" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
fi
AC_SUBST(USER_RELEASE_SUFFIX)
--- a/common/autoconf/platform.m4 Fri Sep 06 09:55:59 2013 +0100
+++ b/common/autoconf/platform.m4 Sat Sep 14 20:43:34 2013 +0100
@@ -422,18 +422,21 @@
# Add -mX to various FLAGS variables.
AC_DEFUN([PLATFORM_SET_COMPILER_TARGET_BITS_FLAGS],
[
- # keep track of c/cxx flags that we added outselves...
- # to prevent emitting warning...
- TARGET_BITS_FLAG="-m${OPENJDK_TARGET_CPU_BITS}"
- AC_SUBST(TARGET_BITS_FLAG)
+ # When we add flags to the "official" CFLAGS etc, we need to
+ # keep track of these additions in ADDED_CFLAGS etc. These
+ # will later be checked to make sure only controlled additions
+ # have been made to CFLAGS etc.
+ ADDED_CFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
+ ADDED_CXXFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
+ ADDED_LDFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
- CFLAGS="${CFLAGS} ${TARGET_BITS_FLAG}"
- CXXFLAGS="${CXXFLAGS} ${TARGET_BITS_FLAG}"
- LDFLAGS="${LDFLAGS} ${TARGET_BITS_FLAG}"
+ CFLAGS="${CFLAGS}${ADDED_CFLAGS}"
+ CXXFLAGS="${CXXFLAGS}${ADDED_CXXFLAGS}"
+ LDFLAGS="${LDFLAGS}${ADDED_LDFLAGS}"
- CFLAGS_JDK="${CFLAGS_JDK} ${TARGET_BITS_FLAG}"
- CXXFLAGS_JDK="${CXXFLAGS_JDK} ${TARGET_BITS_FLAG}"
- LDFLAGS_JDK="${LDFLAGS_JDK} ${TARGET_BITS_FLAG}"
+ CFLAGS_JDK="${CFLAGS_JDK}${ADDED_CFLAGS}"
+ CXXFLAGS_JDK="${CXXFLAGS_JDK}${ADDED_CXXFLAGS}"
+ LDFLAGS_JDK="${LDFLAGS_JDK}${ADDED_LDFLAGS}"
])
AC_DEFUN_ONCE([PLATFORM_SETUP_OPENJDK_TARGET_BITS],
--- a/common/autoconf/source-dirs.m4 Fri Sep 06 09:55:59 2013 +0100
+++ b/common/autoconf/source-dirs.m4 Sat Sep 14 20:43:34 2013 +0100
@@ -101,6 +101,10 @@
test -f $with_add_source_root/hotspot/make/Makefile; then
AC_MSG_ERROR([Your add source root seems to contain a full hotspot repo! An add source root should only contain additional sources.])
fi
+ if test -f $with_add_source_root/nashorn/makefiles/Makefile || \
+ test -f $with_add_source_root/nashorn/make/Makefile; then
+ AC_MSG_ERROR([Your add source root seems to contain a full nashorn repo! An add source root should only contain additional sources.])
+ fi
if test -f $with_add_source_root/jdk/makefiles/Makefile || \
test -f $with_add_source_root/jdk/make/Makefile; then
AC_MSG_ERROR([Your add source root seems to contain a full JDK repo! An add source root should only contain additional sources.])
@@ -136,6 +140,10 @@
test -f $with_override_source_root/hotspot/make/Makefile; then
AC_MSG_ERROR([Your override source root seems to contain a full hotspot repo! An override source root should only contain sources that override.])
fi
+ if test -f $with_override_source_root/nashorn/makefiles/Makefile || \
+ test -f $with_override_source_root/nashorn/make/Makefile; then
+ AC_MSG_ERROR([Your override source root seems to contain a full nashorn repo! An override source root should only contain sources that override.])
+ fi
if test -f $with_override_source_root/jdk/makefiles/Makefile || \
test -f $with_override_source_root/jdk/make/Makefile; then
AC_MSG_ERROR([Your override source root seems to contain a full JDK repo! An override source root should only contain sources that override.])
@@ -177,6 +185,9 @@
AC_ARG_WITH(override-hotspot, [AS_HELP_STRING([--with-override-hotspot],
[use this hotspot dir for the build])])
+AC_ARG_WITH(override-nashorn, [AS_HELP_STRING([--with-override-nashorn],
+ [use this nashorn dir for the build])])
+
AC_ARG_WITH(override-jdk, [AS_HELP_STRING([--with-override-jdk],
[use this jdk dir for the build])])
@@ -241,7 +252,7 @@
cd "$with_override_nashorn"
NASHORN_TOPDIR="`pwd`"
cd "$CURDIR"
- if ! test -f $NASHORN_TOPDIR/makefiles/BuildNashorn.gmk; then
+ if ! test -f $NASHORN_TOPDIR/makefiles/Makefile; then
AC_MSG_ERROR([You have to override nashorn with a full nashorn repo!])
fi
AC_MSG_CHECKING([if nashorn should be overridden])
--- a/common/autoconf/spec.gmk.in Fri Sep 06 09:55:59 2013 +0100
+++ b/common/autoconf/spec.gmk.in Sat Sep 14 20:43:34 2013 +0100
@@ -291,10 +291,6 @@
X_LIBS:=@X_LIBS@
OPENWIN_HOME:=@OPENWIN_HOME@
-# DirectX SDK
-DXSDK_LIB_PATH=@DXSDK_LIB_PATH@
-DXSDK_INCLUDE_PATH=@DXSDK_INCLUDE_PATH@
-
# The lowest required version of macosx to enforce compatiblity for
MACOSX_VERSION_MIN=@MACOSX_VERSION_MIN@
@@ -304,7 +300,6 @@
COMPILER_TYPE:=@COMPILER_TYPE@
COMPILER_NAME:=@COMPILER_NAME@
-TARGET_BITS_FLAG=@TARGET_BITS_FLAG@
COMPILER_SUPPORTS_TARGET_BITS_FLAG=@COMPILER_SUPPORTS_TARGET_BITS_FLAG@
CC_OUT_OPTION:=@CC_OUT_OPTION@
--- a/common/autoconf/toolchain.m4 Fri Sep 06 09:55:59 2013 +0100
+++ b/common/autoconf/toolchain.m4 Sat Sep 14 20:43:34 2013 +0100
@@ -176,7 +176,9 @@
[
if test "x$OPENJDK_TARGET_OS" = "xwindows"; then
TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV
- TOOLCHAIN_SETUP_DXSDK
+ BASIC_DEPRECATED_ARG_WITH([dxsdk])
+ BASIC_DEPRECATED_ARG_WITH([dxsdk-lib])
+ BASIC_DEPRECATED_ARG_WITH([dxsdk-include])
fi
AC_SUBST(MSVCR_DLL)
--- a/common/autoconf/toolchain_windows.m4 Fri Sep 06 09:55:59 2013 +0100
+++ b/common/autoconf/toolchain_windows.m4 Sat Sep 14 20:43:34 2013 +0100
@@ -277,61 +277,3 @@
AC_MSG_RESULT([$MSVCR_DLL])
BASIC_FIXUP_PATH(MSVCR_DLL)
])
-
-
-# Setup the DXSDK paths
-AC_DEFUN([TOOLCHAIN_SETUP_DXSDK],
-[
- AC_ARG_WITH(dxsdk, [AS_HELP_STRING([--with-dxsdk],
- [the DirectX SDK (Windows only) @<:@probed@:>@])])
- AC_ARG_WITH(dxsdk-lib, [AS_HELP_STRING([--with-dxsdk-lib],
- [the DirectX SDK lib directory (Windows only) @<:@probed@:>@])])
- AC_ARG_WITH(dxsdk-include, [AS_HELP_STRING([--with-dxsdk-include],
- [the DirectX SDK include directory (Windows only) @<:@probed@:>@])])
-
- AC_MSG_CHECKING([for DirectX SDK])
-
- if test "x$with_dxsdk" != x; then
- dxsdk_path="$with_dxsdk"
- elif test "x$DXSDK_DIR" != x; then
- dxsdk_path="$DXSDK_DIR"
- elif test -d "C:/DXSDK"; then
- dxsdk_path="C:/DXSDK"
- else
- AC_MSG_ERROR([Could not find the DirectX SDK])
- fi
- AC_MSG_RESULT([$dxsdk_path])
- BASIC_FIXUP_PATH(dxsdk_path)
-
- AC_MSG_CHECKING([for DirectX SDK lib dir])
- if test "x$with_dxsdk_lib" != x; then
- DXSDK_LIB_PATH="$with_dxsdk_lib"
- elif test "x$OPENJDK_TARGET_CPU" = "xx86_64"; then
- DXSDK_LIB_PATH="$dxsdk_path/Lib/x64"
- else
- DXSDK_LIB_PATH="$dxsdk_path/Lib"
- fi
- # dsound.lib is linked to in jsoundds
- if test ! -f "$DXSDK_LIB_PATH/dsound.lib"; then
- AC_MSG_ERROR([Invalid DirectX SDK lib dir])
- fi
- AC_MSG_RESULT([$DXSDK_LIB_PATH])
- BASIC_FIXUP_PATH(DXSDK_LIB_PATH)
-
- AC_MSG_CHECKING([for DirectX SDK include dir])
- if test "x$with_dxsdk_include" != x; then
- DXSDK_INCLUDE_PATH="$with_dxsdk_include"
- else
- DXSDK_INCLUDE_PATH="$dxsdk_path/Include"
- fi
- # dsound.h is included in jsoundds
- if test ! -f "$DXSDK_INCLUDE_PATH/dsound.h"; then
- AC_MSG_ERROR([Invalid DirectX SDK lib dir])
- fi
- AC_MSG_RESULT([$DXSDK_INCLUDE_PATH])
- BASIC_FIXUP_PATH(DXSDK_INCLUDE_PATH)
-
- AC_SUBST(DXSDK_LIB_PATH)
- AC_SUBST(DXSDK_INCLUDE_PATH)
- LDFLAGS_JDK="$LDFLAGS_JDK -libpath:$DXSDK_LIB_PATH"
-])
--- a/common/bin/hgforest.sh Fri Sep 06 09:55:59 2013 +0100
+++ b/common/bin/hgforest.sh Sat Sep 14 20:43:34 2013 +0100
@@ -47,7 +47,7 @@
bpython=""
if [ "#!" = "$has_hash_bang" ] ; then
- python="`head -n 1 ${whichhg} | cut -b 3-`"
+ python="`head -n 1 ${whichhg} | cut -b 3- | sed -e 's/^[ \t]*//;s/[ \t]*$//'`"
bpython="`basename "$python"`"
fi
--- a/corba/.hgtags Fri Sep 06 09:55:59 2013 +0100
+++ b/corba/.hgtags Sat Sep 14 20:43:34 2013 +0100
@@ -228,3 +228,4 @@
d411c60a8c2fe8fdc572af907775e90f7eefd513 jdk8-b104
4e38de7c767e34104fa147b5b346d9fe6b731279 jdk8-b105
2e3a056c84a71eba78945c18b05397858ffd7ad0 jdk8-b106
+23fc34133152692b725db4bd617b4c8dfd6ccb05 jdk8-b107
--- a/corba/src/share/classes/com/sun/corba/se/impl/transport/DefaultSocketFactoryImpl.java Fri Sep 06 09:55:59 2013 +0100
+++ b/corba/src/share/classes/com/sun/corba/se/impl/transport/DefaultSocketFactoryImpl.java Sat Sep 14 20:43:34 2013 +0100
@@ -32,6 +32,7 @@
import java.net.ServerSocket;
import java.nio.channels.SocketChannel;
import java.nio.channels.ServerSocketChannel;
+import java.security.PrivilegedAction;
import com.sun.corba.se.pept.transport.Acceptor;
@@ -44,6 +45,22 @@
implements ORBSocketFactory
{
private ORB orb;
+ private static final boolean keepAlive;
+
+ static {
+ keepAlive = java.security.AccessController.doPrivileged(
+ new PrivilegedAction<Boolean>() {
+ @Override
+ public Boolean run () {
+ String value =
+ System.getProperty("com.sun.CORBA.transport.enableTcpKeepAlive");
+ if (value != null)
+ return new Boolean(!"false".equalsIgnoreCase(value));
+
+ return Boolean.FALSE;
+ }
+ });
+ }
public void setORB(ORB orb)
{
@@ -85,6 +102,9 @@
// Disable Nagle's algorithm (i.e., always send immediately).
socket.setTcpNoDelay(true);
+ if (keepAlive)
+ socket.setKeepAlive(true);
+
return socket;
}
@@ -95,6 +115,8 @@
{
// Disable Nagle's algorithm (i.e., always send immediately).
socket.setTcpNoDelay(true);
+ if (keepAlive)
+ socket.setKeepAlive(true);
}
}
--- a/hotspot/.hgtags Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/.hgtags Sat Sep 14 20:43:34 2013 +0100
@@ -375,3 +375,5 @@
18b4798adbc42c6fa16f5ecb7d5cd3ca130754bf hs25-b48
aed585cafc0d9655726af6d1e1081d1c94cb3b5c jdk8-b106
50794d8ac11c9579b41dec4de23b808fef9f34a1 hs25-b49
+5b7f90aab3ad25a25b75b7b2bb18d5ae23d8231c jdk8-b107
+a09fe9d1e016c285307507a5793bc4fa6215e9c9 hs25-b50
--- a/hotspot/make/hotspot_version Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/make/hotspot_version Sat Sep 14 20:43:34 2013 +0100
@@ -35,7 +35,7 @@
HS_MAJOR_VER=25
HS_MINOR_VER=0
-HS_BUILD_NUMBER=49
+HS_BUILD_NUMBER=50
JDK_MAJOR_VER=1
JDK_MINOR_VER=8
--- a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -57,6 +57,7 @@
define_pd_global(bool, UseTLAB, true);
define_pd_global(bool, ResizeTLAB, true);
define_pd_global(intx, LoopUnrollLimit, 60); // Design center runs on 1.3.1
+define_pd_global(intx, MinJumpTableSize, 5);
// Peephole and CISC spilling both break the graph, and so makes the
// scheduler sick.
--- a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -30,7 +30,6 @@
// Sets the default values for platform dependent flags used by the server compiler.
// (see c2_globals.hpp). Alpha-sorted.
-
define_pd_global(bool, BackgroundCompilation, true);
define_pd_global(bool, UseTLAB, true);
define_pd_global(bool, ResizeTLAB, true);
@@ -52,6 +51,7 @@
define_pd_global(intx, ConditionalMoveLimit, 3);
define_pd_global(intx, FLOATPRESSURE, 6);
define_pd_global(intx, FreqInlineSize, 325);
+define_pd_global(intx, MinJumpTableSize, 10);
#ifdef AMD64
define_pd_global(intx, INTPRESSURE, 13);
define_pd_global(intx, InteriorEntryAlignment, 16);
--- a/hotspot/src/share/vm/ci/ciArray.cpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/ci/ciArray.cpp Sat Sep 14 20:43:34 2013 +0100
@@ -24,13 +24,92 @@
#include "precompiled.hpp"
#include "ci/ciArray.hpp"
+#include "ci/ciArrayKlass.hpp"
+#include "ci/ciConstant.hpp"
#include "ci/ciKlass.hpp"
#include "ci/ciUtilities.hpp"
+#include "oops/objArrayOop.hpp"
+#include "oops/typeArrayOop.hpp"
// ciArray
//
// This class represents an arrayOop in the HotSpot virtual
// machine.
+static BasicType fixup_element_type(BasicType bt) {
+ if (bt == T_ARRAY) return T_OBJECT;
+ if (bt == T_BOOLEAN) return T_BYTE;
+ return bt;
+}
+
+ciConstant ciArray::element_value_impl(BasicType elembt,
+ arrayOop ary,
+ int index) {
+ if (ary == NULL)
+ return ciConstant();
+ assert(ary->is_array(), "");
+ if (index < 0 || index >= ary->length())
+ return ciConstant();
+ ArrayKlass* ak = (ArrayKlass*) ary->klass();
+ BasicType abt = ak->element_type();
+ if (fixup_element_type(elembt) !=
+ fixup_element_type(abt))
+ return ciConstant();
+ switch (elembt) {
+ case T_ARRAY:
+ case T_OBJECT:
+ {
+ assert(ary->is_objArray(), "");
+ objArrayOop objary = (objArrayOop) ary;
+ oop elem = objary->obj_at(index);
+ ciEnv* env = CURRENT_ENV;
+ ciObject* box = env->get_object(elem);
+ return ciConstant(T_OBJECT, box);
+ }
+ }
+ assert(ary->is_typeArray(), "");
+ typeArrayOop tary = (typeArrayOop) ary;
+ jint value = 0;
+ switch (elembt) {
+ case T_LONG: return ciConstant(tary->long_at(index));
+ case T_FLOAT: return ciConstant(tary->float_at(index));
+ case T_DOUBLE: return ciConstant(tary->double_at(index));
+ default: return ciConstant();
+ case T_BYTE: value = tary->byte_at(index); break;
+ case T_BOOLEAN: value = tary->byte_at(index) & 1; break;
+ case T_SHORT: value = tary->short_at(index); break;
+ case T_CHAR: value = tary->char_at(index); break;
+ case T_INT: value = tary->int_at(index); break;
+ }
+ return ciConstant(elembt, value);
+}
+
+// ------------------------------------------------------------------
+// ciArray::element_value
+//
+// Current value of an element.
+// Returns T_ILLEGAL if there is no element at the given index.
+ciConstant ciArray::element_value(int index) {
+ BasicType elembt = element_basic_type();
+ GUARDED_VM_ENTRY(
+ return element_value_impl(elembt, get_arrayOop(), index);
+ )
+}
+
+// ------------------------------------------------------------------
+// ciArray::element_value_by_offset
+//
+// Current value of an element at the specified offset.
+// Returns T_ILLEGAL if there is no element at the given offset.
+ciConstant ciArray::element_value_by_offset(intptr_t element_offset) {
+ BasicType elembt = element_basic_type();
+ intptr_t shift = exact_log2(type2aelembytes(elembt));
+ intptr_t header = arrayOopDesc::base_offset_in_bytes(elembt);
+ intptr_t index = (element_offset - header) >> shift;
+ intptr_t offset = header + ((intptr_t)index << shift);
+ if (offset != element_offset || index != (jint)index)
+ return ciConstant();
+ return element_value((jint) index);
+}
// ------------------------------------------------------------------
// ciArray::print_impl
--- a/hotspot/src/share/vm/ci/ciArray.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/ci/ciArray.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -25,6 +25,8 @@
#ifndef SHARE_VM_CI_CIARRAY_HPP
#define SHARE_VM_CI_CIARRAY_HPP
+#include "ci/ciArrayKlass.hpp"
+#include "ci/ciConstant.hpp"
#include "ci/ciObject.hpp"
#include "oops/arrayOop.hpp"
#include "oops/objArrayOop.hpp"
@@ -45,15 +47,30 @@
ciArray(ciKlass* klass, int len) : ciObject(klass), _length(len) {}
- arrayOop get_arrayOop() { return (arrayOop)get_oop(); }
+ arrayOop get_arrayOop() const { return (arrayOop)get_oop(); }
const char* type_string() { return "ciArray"; }
void print_impl(outputStream* st);
+ ciConstant element_value_impl(BasicType elembt, arrayOop ary, int index);
+
public:
int length() { return _length; }
+ // Convenience routines.
+ ciArrayKlass* array_type() { return klass()->as_array_klass(); }
+ ciType* element_type() { return array_type()->element_type(); }
+ BasicType element_basic_type() { return element_type()->basic_type(); }
+
+ // Current value of an element.
+ // Returns T_ILLEGAL if there is no element at the given index.
+ ciConstant element_value(int index);
+
+ // Current value of an element at the specified offset.
+ // Returns T_ILLEGAL if there is no element at the given offset.
+ ciConstant element_value_by_offset(intptr_t element_offset);
+
// What kind of ciObject is this?
bool is_array() { return true; }
bool is_java_object() { return true; }
--- a/hotspot/src/share/vm/ci/ciConstant.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/ci/ciConstant.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -41,7 +41,6 @@
union {
jint _int;
jlong _long;
- jint _long_half[2];
jfloat _float;
jdouble _double;
ciObject* _object;
@@ -111,6 +110,20 @@
return _value._object;
}
+ bool is_null_or_zero() const {
+ if (!is_java_primitive(basic_type())) {
+ return as_object()->is_null_object();
+ } else if (type2size[basic_type()] == 1) {
+ // treat float bits as int, to avoid comparison with -0 and NaN
+ return (_value._int == 0);
+ } else if (type2size[basic_type()] == 2) {
+ // treat double bits as long, to avoid comparison with -0 and NaN
+ return (_value._long == 0);
+ } else {
+ return false;
+ }
+ }
+
// Debugging output
void print();
};
--- a/hotspot/src/share/vm/ci/ciField.cpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/ci/ciField.cpp Sat Sep 14 20:43:34 2013 +0100
@@ -189,12 +189,14 @@
_holder = CURRENT_ENV->get_instance_klass(fd->field_holder());
// Check to see if the field is constant.
- if (_holder->is_initialized() && this->is_final()) {
+ bool is_final = this->is_final();
+ bool is_stable = FoldStableValues && this->is_stable();
+ if (_holder->is_initialized() && (is_final || is_stable)) {
if (!this->is_static()) {
// A field can be constant if it's a final static field or if
// it's a final non-static field of a trusted class (classes in
// java.lang.invoke and sun.invoke packages and subpackages).
- if (trust_final_non_static_fields(_holder)) {
+ if (is_stable || trust_final_non_static_fields(_holder)) {
_is_constant = true;
return;
}
@@ -227,7 +229,6 @@
Handle mirror = k->java_mirror();
- _is_constant = true;
switch(type()->basic_type()) {
case T_BYTE:
_constant_value = ciConstant(type()->basic_type(), mirror->byte_field(_offset));
@@ -273,6 +274,12 @@
}
}
}
+ if (is_stable && _constant_value.is_null_or_zero()) {
+ // It is not a constant after all; treat it as uninitialized.
+ _is_constant = false;
+ } else {
+ _is_constant = true;
+ }
} else {
_is_constant = false;
}
@@ -373,8 +380,11 @@
tty->print(" signature=");
_signature->print_symbol();
tty->print(" offset=%d type=", _offset);
- if (_type != NULL) _type->print_name();
- else tty->print("(reference)");
+ if (_type != NULL)
+ _type->print_name();
+ else
+ tty->print("(reference)");
+ tty->print(" flags=%04x", flags().as_int());
tty->print(" is_constant=%s", bool_to_str(_is_constant));
if (_is_constant && is_static()) {
tty->print(" constant_value=");
--- a/hotspot/src/share/vm/ci/ciField.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/ci/ciField.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -139,7 +139,10 @@
// non-constant fields. These are java.lang.System.in
// and java.lang.System.out. Abomination.
//
- // Note: the check for case 4 is not yet implemented.
+ // A field is also considered constant if it is marked @Stable
+ // and is non-null (or non-zero, if a primitive).
+ // For non-static fields, the null/zero check must be
+ // arranged by the user, as constant_value().is_null_or_zero().
bool is_constant() { return _is_constant; }
// Get the constant value of this field.
@@ -173,6 +176,7 @@
bool is_protected () { return flags().is_protected(); }
bool is_static () { return flags().is_static(); }
bool is_final () { return flags().is_final(); }
+ bool is_stable () { return flags().is_stable(); }
bool is_volatile () { return flags().is_volatile(); }
bool is_transient () { return flags().is_transient(); }
--- a/hotspot/src/share/vm/ci/ciFlags.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/ci/ciFlags.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -59,6 +59,7 @@
bool is_interface () const { return (_flags & JVM_ACC_INTERFACE ) != 0; }
bool is_abstract () const { return (_flags & JVM_ACC_ABSTRACT ) != 0; }
bool is_strict () const { return (_flags & JVM_ACC_STRICT ) != 0; }
+ bool is_stable () const { return (_flags & JVM_ACC_FIELD_STABLE) != 0; }
// Conversion
jint as_int() { return _flags; }
--- a/hotspot/src/share/vm/ci/ciInstance.cpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/ci/ciInstance.cpp Sat Sep 14 20:43:34 2013 +0100
@@ -127,6 +127,8 @@
ciConstant ciInstance::field_value_by_offset(int field_offset) {
ciInstanceKlass* ik = klass()->as_instance_klass();
ciField* field = ik->get_field_by_offset(field_offset, false);
+ if (field == NULL)
+ return ciConstant(); // T_ILLEGAL
return field_value(field);
}
--- a/hotspot/src/share/vm/ci/ciTypeArray.cpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/ci/ciTypeArray.cpp Sat Sep 14 20:43:34 2013 +0100
@@ -39,5 +39,10 @@
jchar ciTypeArray::char_at(int index) {
VM_ENTRY_MARK;
assert(index >= 0 && index < length(), "out of range");
- return get_typeArrayOop()->char_at(index);
+ jchar c = get_typeArrayOop()->char_at(index);
+#ifdef ASSERT
+ jchar d = element_value(index).as_char();
+ assert(c == d, "");
+#endif //ASSERT
+ return c;
}
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Sat Sep 14 20:43:34 2013 +0100
@@ -1774,6 +1774,10 @@
if (_location != _in_method) break; // only allow for methods
if (!privileged) break; // only allow in privileged code
return _method_LambdaForm_Hidden;
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_invoke_Stable_signature):
+ if (_location != _in_field) break; // only allow for fields
+ if (!privileged) break; // only allow in privileged code
+ return _field_Stable;
case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_misc_Contended_signature):
if (_location != _in_field && _location != _in_class) break; // only allow for fields and classes
if (!EnableContended || (RestrictContended && !privileged)) break; // honor privileges
@@ -1786,6 +1790,8 @@
void ClassFileParser::FieldAnnotationCollector::apply_to(FieldInfo* f) {
if (is_contended())
f->set_contended_group(contended_group());
+ if (is_stable())
+ f->set_stable(true);
}
ClassFileParser::FieldAnnotationCollector::~FieldAnnotationCollector() {
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -125,6 +125,7 @@
_method_LambdaForm_Compiled,
_method_LambdaForm_Hidden,
_sun_misc_Contended,
+ _field_Stable,
_annotation_LIMIT
};
const Location _location;
@@ -143,14 +144,23 @@
assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
_annotations_present |= nth_bit((int)id);
}
+
+ void remove_annotation(ID id) {
+ assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
+ _annotations_present &= ~nth_bit((int)id);
+ }
+
// Report if the annotation is present.
- bool has_any_annotations() { return _annotations_present != 0; }
- bool has_annotation(ID id) { return (nth_bit((int)id) & _annotations_present) != 0; }
+ bool has_any_annotations() const { return _annotations_present != 0; }
+ bool has_annotation(ID id) const { return (nth_bit((int)id) & _annotations_present) != 0; }
void set_contended_group(u2 group) { _contended_group = group; }
- u2 contended_group() { return _contended_group; }
+ u2 contended_group() const { return _contended_group; }
- bool is_contended() { return has_annotation(_sun_misc_Contended); }
+ bool is_contended() const { return has_annotation(_sun_misc_Contended); }
+
+ void set_stable(bool stable) { set_annotation(_field_Stable); }
+ bool is_stable() const { return has_annotation(_field_Stable); }
};
// This class also doubles as a holder for metadata cleanup.
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -270,6 +270,7 @@
template(java_lang_invoke_LambdaForm, "java/lang/invoke/LambdaForm") \
template(java_lang_invoke_ForceInline_signature, "Ljava/lang/invoke/ForceInline;") \
template(java_lang_invoke_DontInline_signature, "Ljava/lang/invoke/DontInline;") \
+ template(sun_invoke_Stable_signature, "Lsun/invoke/Stable;") \
template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \
template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;") \
template(java_lang_invoke_MagicLambdaImpl, "java/lang/invoke/MagicLambdaImpl") \
--- a/hotspot/src/share/vm/oops/fieldInfo.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/oops/fieldInfo.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -240,6 +240,14 @@
return (access_flags() & JVM_ACC_FIELD_INTERNAL) != 0;
}
+ bool is_stable() const {
+ return (access_flags() & JVM_ACC_FIELD_STABLE) != 0;
+ }
+ void set_stable(bool z) {
+ if (z) _shorts[access_flags_offset] |= JVM_ACC_FIELD_STABLE;
+ else _shorts[access_flags_offset] &= ~JVM_ACC_FIELD_STABLE;
+ }
+
Symbol* lookup_symbol(int symbol_index) const {
assert(is_internal(), "only internal fields");
return vmSymbols::symbol_at((vmSymbols::SID)symbol_index);
--- a/hotspot/src/share/vm/opto/c2_globals.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -421,7 +421,7 @@
product(bool, UseDivMod, true, \
"Use combined DivMod instruction if available") \
\
- product(intx, MinJumpTableSize, 18, \
+ product_pd(intx, MinJumpTableSize, \
"Minimum number of targets in a generated jump table") \
\
product(intx, MaxJumpTableSize, 65000, \
@@ -448,6 +448,9 @@
product(bool, EliminateAutoBox, true, \
"Control optimizations for autobox elimination") \
\
+ experimental(bool, UseImplicitStableValues, false, \
+ "Mark well-known stable fields as such (e.g. String.value)") \
+ \
product(intx, AutoBoxCacheMax, 128, \
"Sets max value cached by the java.lang.Integer autobox cache") \
\
--- a/hotspot/src/share/vm/opto/compile.cpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/opto/compile.cpp Sat Sep 14 20:43:34 2013 +0100
@@ -1297,6 +1297,10 @@
// Array pointers need some flattening
const TypeAryPtr *ta = tj->isa_aryptr();
+ if (ta && ta->is_stable()) {
+ // Erase stability property for alias analysis.
+ tj = ta = ta->cast_to_stable(false);
+ }
if( ta && is_known_inst ) {
if ( offset != Type::OffsetBot &&
offset > arrayOopDesc::length_offset_in_bytes() ) {
@@ -1497,6 +1501,7 @@
_index = i;
_adr_type = at;
_field = NULL;
+ _element = NULL;
_is_rewritable = true; // default
const TypeOopPtr *atoop = (at != NULL) ? at->isa_oopptr() : NULL;
if (atoop != NULL && atoop->is_known_instance()) {
@@ -1615,6 +1620,16 @@
&& flat->is_instptr()->klass() == env()->Class_klass())
alias_type(idx)->set_rewritable(false);
}
+ if (flat->isa_aryptr()) {
+#ifdef ASSERT
+ const int header_size_min = arrayOopDesc::base_offset_in_bytes(T_BYTE);
+ // (T_BYTE has the weakest alignment and size restrictions...)
+ assert(flat->offset() < header_size_min, "array body reference must be OffsetBot");
+#endif
+ if (flat->offset() == TypePtr::OffsetBot) {
+ alias_type(idx)->set_element(flat->is_aryptr()->elem());
+ }
+ }
if (flat->isa_klassptr()) {
if (flat->offset() == in_bytes(Klass::super_check_offset_offset()))
alias_type(idx)->set_rewritable(false);
@@ -1677,7 +1692,7 @@
else
t = TypeOopPtr::make_from_klass_raw(field->holder());
AliasType* atp = alias_type(t->add_offset(field->offset_in_bytes()), field);
- assert(field->is_final() == !atp->is_rewritable(), "must get the rewritable bits correct");
+ assert((field->is_final() || field->is_stable()) == !atp->is_rewritable(), "must get the rewritable bits correct");
return atp;
}
--- a/hotspot/src/share/vm/opto/compile.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/opto/compile.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -72,6 +72,7 @@
class StartNode;
class SafePointNode;
class JVMState;
+class Type;
class TypeData;
class TypePtr;
class TypeOopPtr;
@@ -119,6 +120,7 @@
int _index; // unique index, used with MergeMemNode
const TypePtr* _adr_type; // normalized address type
ciField* _field; // relevant instance field, or null if none
+ const Type* _element; // relevant array element type, or null if none
bool _is_rewritable; // false if the memory is write-once only
int _general_index; // if this is type is an instance, the general
// type that this is an instance of
@@ -129,6 +131,7 @@
int index() const { return _index; }
const TypePtr* adr_type() const { return _adr_type; }
ciField* field() const { return _field; }
+ const Type* element() const { return _element; }
bool is_rewritable() const { return _is_rewritable; }
bool is_volatile() const { return (_field ? _field->is_volatile() : false); }
int general_index() const { return (_general_index != 0) ? _general_index : _index; }
@@ -137,7 +140,14 @@
void set_field(ciField* f) {
assert(!_field,"");
_field = f;
- if (f->is_final()) _is_rewritable = false;
+ if (f->is_final() || f->is_stable()) {
+ // In the case of @Stable, multiple writes are possible but may be assumed to be no-ops.
+ _is_rewritable = false;
+ }
+ }
+ void set_element(const Type* e) {
+ assert(_element == NULL, "");
+ _element = e;
}
void print_on(outputStream* st) PRODUCT_RETURN;
--- a/hotspot/src/share/vm/opto/graphKit.cpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/opto/graphKit.cpp Sat Sep 14 20:43:34 2013 +0100
@@ -3825,8 +3825,13 @@
TypeAry::make(TypeInt::CHAR,TypeInt::POS),
ciTypeArrayKlass::make(T_CHAR), true, 0);
int value_field_idx = C->get_alias_index(value_field_type);
- return make_load(ctrl, basic_plus_adr(str, str, value_offset),
- value_type, T_OBJECT, value_field_idx);
+ Node* load = make_load(ctrl, basic_plus_adr(str, str, value_offset),
+ value_type, T_OBJECT, value_field_idx);
+ // String.value field is known to be @Stable.
+ if (UseImplicitStableValues) {
+ load = cast_array_to_stable(load, value_type);
+ }
+ return load;
}
void GraphKit::store_String_offset(Node* ctrl, Node* str, Node* value) {
@@ -3844,9 +3849,6 @@
const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
false, NULL, 0);
const TypePtr* value_field_type = string_type->add_offset(value_offset);
- const TypeAryPtr* value_type = TypeAryPtr::make(TypePtr::NotNull,
- TypeAry::make(TypeInt::CHAR,TypeInt::POS),
- ciTypeArrayKlass::make(T_CHAR), true, 0);
int value_field_idx = C->get_alias_index(value_field_type);
store_to_memory(ctrl, basic_plus_adr(str, value_offset),
value, T_OBJECT, value_field_idx);
@@ -3861,3 +3863,9 @@
store_to_memory(ctrl, basic_plus_adr(str, count_offset),
value, T_INT, count_field_idx);
}
+
+Node* GraphKit::cast_array_to_stable(Node* ary, const TypeAryPtr* ary_type) {
+ // Reify the property as a CastPP node in Ideal graph to comply with monotonicity
+ // assumption of CCP analysis.
+ return _gvn.transform(new(C) CastPPNode(ary, ary_type->cast_to_stable(true)));
+}
--- a/hotspot/src/share/vm/opto/graphKit.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/opto/graphKit.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -836,6 +836,9 @@
// Insert a loop predicate into the graph
void add_predicate(int nargs = 0);
void add_predicate_impl(Deoptimization::DeoptReason reason, int nargs);
+
+ // Produce new array node of stable type
+ Node* cast_array_to_stable(Node* ary, const TypeAryPtr* ary_type);
};
// Helper class to support building of control flow branches. Upon
--- a/hotspot/src/share/vm/opto/library_call.cpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/opto/library_call.cpp Sat Sep 14 20:43:34 2013 +0100
@@ -1280,6 +1280,11 @@
const TypeAry* target_array_type = TypeAry::make(TypeInt::CHAR, TypeInt::make(0, target_length, Type::WidenMin));
const TypeAryPtr* target_type = TypeAryPtr::make(TypePtr::BotPTR, target_array_type, target_array->klass(), true, Type::OffsetBot);
+ // String.value field is known to be @Stable.
+ if (UseImplicitStableValues) {
+ target = cast_array_to_stable(target, target_type);
+ }
+
IdealKit kit(this, false, true);
#define __ kit.
Node* zero = __ ConI(0);
--- a/hotspot/src/share/vm/opto/memnode.cpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/opto/memnode.cpp Sat Sep 14 20:43:34 2013 +0100
@@ -962,6 +962,19 @@
return (uintptr_t)in(Control) + (uintptr_t)in(Memory) + (uintptr_t)in(Address);
}
+static bool skip_through_membars(Compile::AliasType* atp, const TypeInstPtr* tp, bool eliminate_boxing) {
+ if ((atp != NULL) && (atp->index() >= Compile::AliasIdxRaw)) {
+ bool non_volatile = (atp->field() != NULL) && !atp->field()->is_volatile();
+ bool is_stable_ary = FoldStableValues &&
+ (tp != NULL) && (tp->isa_aryptr() != NULL) &&
+ tp->isa_aryptr()->is_stable();
+
+ return (eliminate_boxing && non_volatile) || is_stable_ary;
+ }
+
+ return false;
+}
+
//---------------------------can_see_stored_value------------------------------
// This routine exists to make sure this set of tests is done the same
// everywhere. We need to make a coordinated change: first LoadNode::Ideal
@@ -976,11 +989,9 @@
const TypeInstPtr* tp = phase->type(ld_adr)->isa_instptr();
Compile::AliasType* atp = (tp != NULL) ? phase->C->alias_type(tp) : NULL;
// This is more general than load from boxing objects.
- if (phase->C->eliminate_boxing() && (atp != NULL) &&
- (atp->index() >= Compile::AliasIdxRaw) &&
- (atp->field() != NULL) && !atp->field()->is_volatile()) {
+ if (skip_through_membars(atp, tp, phase->C->eliminate_boxing())) {
uint alias_idx = atp->index();
- bool final = atp->field()->is_final();
+ bool final = !atp->is_rewritable();
Node* result = NULL;
Node* current = st;
// Skip through chains of MemBarNodes checking the MergeMems for
@@ -1015,7 +1026,6 @@
}
}
-
// Loop around twice in the case Load -> Initialize -> Store.
// (See PhaseIterGVN::add_users_to_worklist, which knows about this case.)
for (int trip = 0; trip <= 1; trip++) {
@@ -1577,6 +1587,40 @@
return NULL;
}
+// Try to constant-fold a stable array element.
+static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicType loadbt) {
+ assert(ary->is_stable(), "array should be stable");
+
+ if (ary->const_oop() != NULL) {
+ // Decode the results of GraphKit::array_element_address.
+ ciArray* aobj = ary->const_oop()->as_array();
+ ciConstant con = aobj->element_value_by_offset(off);
+
+ if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) {
+ const Type* con_type = Type::make_from_constant(con);
+ if (con_type != NULL) {
+ if (con_type->isa_aryptr()) {
+ // Join with the array element type, in case it is also stable.
+ int dim = ary->stable_dimension();
+ con_type = con_type->is_aryptr()->cast_to_stable(true, dim-1);
+ }
+ if (loadbt == T_NARROWOOP && con_type->isa_oopptr()) {
+ con_type = con_type->make_narrowoop();
+ }
+#ifndef PRODUCT
+ if (TraceIterativeGVN) {
+ tty->print("FoldStableValues: array element [off=%d]: con_type=", off);
+ con_type->dump(); tty->cr();
+ }
+#endif //PRODUCT
+ return con_type;
+ }
+ }
+ }
+
+ return NULL;
+}
+
//------------------------------Value-----------------------------------------
const Type *LoadNode::Value( PhaseTransform *phase ) const {
// Either input is TOP ==> the result is TOP
@@ -1591,8 +1635,31 @@
Compile* C = phase->C;
// Try to guess loaded type from pointer type
- if (tp->base() == Type::AryPtr) {
- const Type *t = tp->is_aryptr()->elem();
+ if (tp->isa_aryptr()) {
+ const TypeAryPtr* ary = tp->is_aryptr();
+ const Type *t = ary->elem();
+
+ // Determine whether the reference is beyond the header or not, by comparing
+ // the offset against the offset of the start of the array's data.
+ // Different array types begin at slightly different offsets (12 vs. 16).
+ // We choose T_BYTE as an example base type that is least restrictive
+ // as to alignment, which will therefore produce the smallest
+ // possible base offset.
+ const int min_base_off = arrayOopDesc::base_offset_in_bytes(T_BYTE);
+ const bool off_beyond_header = ((uint)off >= (uint)min_base_off);
+
+ // Try to constant-fold a stable array element.
+ if (FoldStableValues && ary->is_stable()) {
+ // Make sure the reference is not into the header
+ if (off_beyond_header && off != Type::OffsetBot) {
+ assert(adr->is_AddP() && adr->in(AddPNode::Offset)->is_Con(), "offset is a constant");
+ const Type* con_type = fold_stable_ary_elem(ary, off, memory_type());
+ if (con_type != NULL) {
+ return con_type;
+ }
+ }
+ }
+
// Don't do this for integer types. There is only potential profit if
// the element type t is lower than _type; that is, for int types, if _type is
// more restrictive than t. This only happens here if one is short and the other
@@ -1613,14 +1680,7 @@
&& Opcode() != Op_LoadKlass && Opcode() != Op_LoadNKlass) {
// t might actually be lower than _type, if _type is a unique
// concrete subclass of abstract class t.
- // Make sure the reference is not into the header, by comparing
- // the offset against the offset of the start of the array's data.
- // Different array types begin at slightly different offsets (12 vs. 16).
- // We choose T_BYTE as an example base type that is least restrictive
- // as to alignment, which will therefore produce the smallest
- // possible base offset.
- const int min_base_off = arrayOopDesc::base_offset_in_bytes(T_BYTE);
- if ((uint)off >= (uint)min_base_off) { // is the offset beyond the header?
+ if (off_beyond_header) { // is the offset beyond the header?
const Type* jt = t->join(_type);
// In any case, do not allow the join, per se, to empty out the type.
if (jt->empty() && !t->empty()) {
--- a/hotspot/src/share/vm/opto/parse.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/opto/parse.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -518,7 +518,7 @@
// loading from a constant field or the constant pool
// returns false if push failed (non-perm field constants only, not ldcs)
- bool push_constant(ciConstant con, bool require_constant = false, bool is_autobox_cache = false);
+ bool push_constant(ciConstant con, bool require_constant = false, bool is_autobox_cache = false, const Type* basic_type = NULL);
// implementation of object creation bytecodes
void emit_guard_for_new(ciInstanceKlass* klass);
--- a/hotspot/src/share/vm/opto/parse3.cpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/opto/parse3.cpp Sat Sep 14 20:43:34 2013 +0100
@@ -147,7 +147,15 @@
void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) {
// Does this field have a constant value? If so, just push the value.
if (field->is_constant()) {
- // final field
+ // final or stable field
+ const Type* stable_type = NULL;
+ if (FoldStableValues && field->is_stable()) {
+ stable_type = Type::get_const_type(field->type());
+ if (field->type()->is_array_klass()) {
+ int stable_dimension = field->type()->as_array_klass()->dimension();
+ stable_type = stable_type->is_aryptr()->cast_to_stable(true, stable_dimension);
+ }
+ }
if (field->is_static()) {
// final static field
if (C->eliminate_boxing()) {
@@ -167,11 +175,10 @@
}
}
}
- if (push_constant(field->constant_value()))
+ if (push_constant(field->constant_value(), false, false, stable_type))
return;
- }
- else {
- // final non-static field
+ } else {
+ // final or stable non-static field
// Treat final non-static fields of trusted classes (classes in
// java.lang.invoke and sun.invoke packages and subpackages) as
// compile time constants.
@@ -179,8 +186,12 @@
const TypeOopPtr* oop_ptr = obj->bottom_type()->isa_oopptr();
ciObject* constant_oop = oop_ptr->const_oop();
ciConstant constant = field->constant_value_of(constant_oop);
- if (push_constant(constant, true))
- return;
+ if (FoldStableValues && field->is_stable() && constant.is_null_or_zero()) {
+ // fall through to field load; the field is not yet initialized
+ } else {
+ if (push_constant(constant, true, false, stable_type))
+ return;
+ }
}
}
}
@@ -301,7 +312,8 @@
// Note the presence of writes to final non-static fields, so that we
// can insert a memory barrier later on to keep the writes from floating
// out of the constructor.
- if (is_field && field->is_final()) {
+ // Any method can write a @Stable field; insert memory barriers after those also.
+ if (is_field && (field->is_final() || field->is_stable())) {
set_wrote_final(true);
// Preserve allocation ptr to create precedent edge to it in membar
// generated on exit from constructor.
@@ -314,35 +326,21 @@
}
-bool Parse::push_constant(ciConstant constant, bool require_constant, bool is_autobox_cache) {
+
+bool Parse::push_constant(ciConstant constant, bool require_constant, bool is_autobox_cache, const Type* stable_type) {
+ const Type* con_type = Type::make_from_constant(constant, require_constant, is_autobox_cache);
switch (constant.basic_type()) {
- case T_BOOLEAN: push( intcon(constant.as_boolean()) ); break;
- case T_INT: push( intcon(constant.as_int()) ); break;
- case T_CHAR: push( intcon(constant.as_char()) ); break;
- case T_BYTE: push( intcon(constant.as_byte()) ); break;
- case T_SHORT: push( intcon(constant.as_short()) ); break;
- case T_FLOAT: push( makecon(TypeF::make(constant.as_float())) ); break;
- case T_DOUBLE: push_pair( makecon(TypeD::make(constant.as_double())) ); break;
- case T_LONG: push_pair( longcon(constant.as_long()) ); break;
case T_ARRAY:
- case T_OBJECT: {
+ case T_OBJECT:
// cases:
// can_be_constant = (oop not scavengable || ScavengeRootsInCode != 0)
// should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2)
// An oop is not scavengable if it is in the perm gen.
- ciObject* oop_constant = constant.as_object();
- if (oop_constant->is_null_object()) {
- push( zerocon(T_OBJECT) );
- break;
- } else if (require_constant || oop_constant->should_be_constant()) {
- push( makecon(TypeOopPtr::make_from_constant(oop_constant, require_constant, is_autobox_cache)) );
- break;
- } else {
- // we cannot inline the oop, but we can use it later to narrow a type
- return false;
- }
- }
- case T_ILLEGAL: {
+ if (stable_type != NULL && con_type != NULL && con_type->isa_oopptr())
+ con_type = con_type->join(stable_type);
+ break;
+
+ case T_ILLEGAL:
// Invalid ciConstant returned due to OutOfMemoryError in the CI
assert(C->env()->failing(), "otherwise should not see this");
// These always occur because of object types; we are going to
@@ -350,17 +348,16 @@
push( zerocon(T_OBJECT) );
return false;
}
- default:
- ShouldNotReachHere();
+
+ if (con_type == NULL)
+ // we cannot inline the oop, but we can use it later to narrow a type
return false;
- }
- // success
+ push_node(constant.basic_type(), makecon(con_type));
return true;
}
-
//=============================================================================
void Parse::do_anewarray() {
bool will_link;
--- a/hotspot/src/share/vm/opto/type.cpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/opto/type.cpp Sat Sep 14 20:43:34 2013 +0100
@@ -189,6 +189,38 @@
}
+//-----------------------make_from_constant------------------------------------
+const Type* Type::make_from_constant(ciConstant constant,
+ bool require_constant, bool is_autobox_cache) {
+ switch (constant.basic_type()) {
+ case T_BOOLEAN: return TypeInt::make(constant.as_boolean());
+ case T_CHAR: return TypeInt::make(constant.as_char());
+ case T_BYTE: return TypeInt::make(constant.as_byte());
+ case T_SHORT: return TypeInt::make(constant.as_short());
+ case T_INT: return TypeInt::make(constant.as_int());
+ case T_LONG: return TypeLong::make(constant.as_long());
+ case T_FLOAT: return TypeF::make(constant.as_float());
+ case T_DOUBLE: return TypeD::make(constant.as_double());
+ case T_ARRAY:
+ case T_OBJECT:
+ {
+ // cases:
+ // can_be_constant = (oop not scavengable || ScavengeRootsInCode != 0)
+ // should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2)
+ // An oop is not scavengable if it is in the perm gen.
+ ciObject* oop_constant = constant.as_object();
+ if (oop_constant->is_null_object()) {
+ return Type::get_zero_type(T_OBJECT);
+ } else if (require_constant || oop_constant->should_be_constant()) {
+ return TypeOopPtr::make_from_constant(oop_constant, require_constant, is_autobox_cache);
+ }
+ }
+ }
+ // Fall through to failure
+ return NULL;
+}
+
+
//------------------------------make-------------------------------------------
// Create a simple Type, with default empty symbol sets. Then hashcons it
// and look for an existing copy in the type dictionary.
@@ -1824,12 +1856,12 @@
}
//------------------------------make-------------------------------------------
-const TypeAry *TypeAry::make( const Type *elem, const TypeInt *size) {
+const TypeAry* TypeAry::make(const Type* elem, const TypeInt* size, bool stable) {
if (UseCompressedOops && elem->isa_oopptr()) {
elem = elem->make_narrowoop();
}
size = normalize_array_size(size);
- return (TypeAry*)(new TypeAry(elem,size))->hashcons();
+ return (TypeAry*)(new TypeAry(elem,size,stable))->hashcons();
}
//------------------------------meet-------------------------------------------
@@ -1850,7 +1882,8 @@
case Array: { // Meeting 2 arrays?
const TypeAry *a = t->is_ary();
return TypeAry::make(_elem->meet(a->_elem),
- _size->xmeet(a->_size)->is_int());
+ _size->xmeet(a->_size)->is_int(),
+ _stable & a->_stable);
}
case Top:
break;
@@ -1863,7 +1896,7 @@
const Type *TypeAry::xdual() const {
const TypeInt* size_dual = _size->dual()->is_int();
size_dual = normalize_array_size(size_dual);
- return new TypeAry( _elem->dual(), size_dual);
+ return new TypeAry(_elem->dual(), size_dual, !_stable);
}
//------------------------------eq---------------------------------------------
@@ -1871,13 +1904,14 @@
bool TypeAry::eq( const Type *t ) const {
const TypeAry *a = (const TypeAry*)t;
return _elem == a->_elem &&
+ _stable == a->_stable &&
_size == a->_size;
}
//------------------------------hash-------------------------------------------
// Type-specific hashing function.
int TypeAry::hash(void) const {
- return (intptr_t)_elem + (intptr_t)_size;
+ return (intptr_t)_elem + (intptr_t)_size + (_stable ? 43 : 0);
}
//----------------------interface_vs_oop---------------------------------------
@@ -1894,6 +1928,7 @@
//------------------------------dump2------------------------------------------
#ifndef PRODUCT
void TypeAry::dump2( Dict &d, uint depth, outputStream *st ) const {
+ if (_stable) st->print("stable:");
_elem->dump2(d, depth, st);
st->print("[");
_size->dump2(d, depth, st);
@@ -3457,11 +3492,39 @@
assert(new_size != NULL, "");
new_size = narrow_size_type(new_size);
if (new_size == size()) return this;
- const TypeAry* new_ary = TypeAry::make(elem(), new_size);
+ const TypeAry* new_ary = TypeAry::make(elem(), new_size, is_stable());
return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id);
}
+//------------------------------cast_to_stable---------------------------------
+const TypeAryPtr* TypeAryPtr::cast_to_stable(bool stable, int stable_dimension) const {
+ if (stable_dimension <= 0 || (stable_dimension == 1 && stable == this->is_stable()))
+ return this;
+
+ const Type* elem = this->elem();
+ const TypePtr* elem_ptr = elem->make_ptr();
+
+ if (stable_dimension > 1 && elem_ptr != NULL && elem_ptr->isa_aryptr()) {
+ // If this is widened from a narrow oop, TypeAry::make will re-narrow it.
+ elem = elem_ptr = elem_ptr->is_aryptr()->cast_to_stable(stable, stable_dimension - 1);
+ }
+
+ const TypeAry* new_ary = TypeAry::make(elem, size(), stable);
+
+ return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id);
+}
+
+//-----------------------------stable_dimension--------------------------------
+int TypeAryPtr::stable_dimension() const {
+ if (!is_stable()) return 0;
+ int dim = 1;
+ const TypePtr* elem_ptr = elem()->make_ptr();
+ if (elem_ptr != NULL && elem_ptr->isa_aryptr())
+ dim += elem_ptr->is_aryptr()->stable_dimension();
+ return dim;
+}
+
//------------------------------eq---------------------------------------------
// Structural equality check for Type representations
bool TypeAryPtr::eq( const Type *t ) const {
@@ -3570,7 +3633,7 @@
// Something like byte[int+] meets char[int+].
// This must fall to bottom, not (int[-128..65535])[int+].
instance_id = InstanceBot;
- tary = TypeAry::make(Type::BOTTOM, tary->_size);
+ tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
}
} else // Non integral arrays.
// Must fall to bottom if exact klasses in upper lattice
@@ -3584,7 +3647,7 @@
(tap ->_klass_is_exact && !tap->klass()->is_subtype_of(klass())) ||
// 'this' is exact and super or unrelated:
(this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) {
- tary = TypeAry::make(Type::BOTTOM, tary->_size);
+ tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
return make( NotNull, NULL, tary, lazy_klass, false, off, InstanceBot );
}
--- a/hotspot/src/share/vm/opto/type.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/opto/type.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -372,6 +372,10 @@
// Mapping from CI type system to compiler type:
static const Type* get_typeflow_type(ciType* type);
+ static const Type* make_from_constant(ciConstant constant,
+ bool require_constant = false,
+ bool is_autobox_cache = false);
+
private:
// support arrays
static const BasicType _basic_type[];
@@ -588,8 +592,8 @@
//------------------------------TypeAry----------------------------------------
// Class of Array Types
class TypeAry : public Type {
- TypeAry( const Type *elem, const TypeInt *size) : Type(Array),
- _elem(elem), _size(size) {}
+ TypeAry(const Type* elem, const TypeInt* size, bool stable) : Type(Array),
+ _elem(elem), _size(size), _stable(stable) {}
public:
virtual bool eq( const Type *t ) const;
virtual int hash() const; // Type specific hashing
@@ -599,10 +603,11 @@
private:
const Type *_elem; // Element type of array
const TypeInt *_size; // Elements in array
+ const bool _stable; // Are elements @Stable?
friend class TypeAryPtr;
public:
- static const TypeAry *make( const Type *elem, const TypeInt *size);
+ static const TypeAry* make(const Type* elem, const TypeInt* size, bool stable = false);
virtual const Type *xmeet( const Type *t ) const;
virtual const Type *xdual() const; // Compute dual right now.
@@ -988,6 +993,7 @@
const TypeAry* ary() const { return _ary; }
const Type* elem() const { return _ary->_elem; }
const TypeInt* size() const { return _ary->_size; }
+ bool is_stable() const { return _ary->_stable; }
bool is_autobox_cache() const { return _is_autobox_cache; }
@@ -1011,6 +1017,9 @@
virtual const Type *xmeet( const Type *t ) const;
virtual const Type *xdual() const; // Compute dual right now.
+ const TypeAryPtr* cast_to_stable(bool stable, int stable_dimension = 1) const;
+ int stable_dimension() const;
+
// Convenience common pre-built types.
static const TypeAryPtr *RANGE;
static const TypeAryPtr *OOPS;
--- a/hotspot/src/share/vm/runtime/globals.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/runtime/globals.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -3649,6 +3649,9 @@
experimental(bool, TrustFinalNonStaticFields, false, \
"trust final non-static declarations for constant folding") \
\
+ experimental(bool, FoldStableValues, false, \
+ "Private flag to control optimizations for stable variables") \
+ \
develop(bool, TraceInvokeDynamic, false, \
"trace internal invoke dynamic operations") \
\
--- a/hotspot/src/share/vm/runtime/interfaceSupport.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/runtime/interfaceSupport.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -471,16 +471,6 @@
VM_ENTRY_BASE(result_type, header, thread) \
debug_only(VMEntryWrapper __vew;)
-// Another special case for nmethod_entry_point so the nmethod that the
-// interpreter is about to branch to doesn't get flushed before as we
-// branch to it's interpreter_entry_point. Skip stress testing here too.
-// Also we don't allow async exceptions because it is just too painful.
-#define IRT_ENTRY_FOR_NMETHOD(result_type, header) \
- result_type header { \
- nmethodLocker _nmlock(nm); \
- ThreadInVMfromJavaNoAsyncException __tiv(thread); \
- VM_ENTRY_BASE(result_type, header, thread)
-
#define IRT_END }
--- a/hotspot/src/share/vm/utilities/accessFlags.hpp Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/src/share/vm/utilities/accessFlags.hpp Sat Sep 14 20:43:34 2013 +0100
@@ -78,11 +78,13 @@
JVM_ACC_FIELD_ACCESS_WATCHED = 0x00002000, // field access is watched by JVMTI
JVM_ACC_FIELD_MODIFICATION_WATCHED = 0x00008000, // field modification is watched by JVMTI
JVM_ACC_FIELD_INTERNAL = 0x00000400, // internal field, same as JVM_ACC_ABSTRACT
+ JVM_ACC_FIELD_STABLE = 0x00000020, // @Stable field, same as JVM_ACC_SYNCHRONIZED
JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE = 0x00000800, // field has generic signature
JVM_ACC_FIELD_INTERNAL_FLAGS = JVM_ACC_FIELD_ACCESS_WATCHED |
JVM_ACC_FIELD_MODIFICATION_WATCHED |
JVM_ACC_FIELD_INTERNAL |
+ JVM_ACC_FIELD_STABLE |
JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE,
// flags accepted by set_field_flags()
@@ -148,6 +150,7 @@
{ return (_flags & JVM_ACC_FIELD_MODIFICATION_WATCHED) != 0; }
bool on_stack() const { return (_flags & JVM_ACC_ON_STACK) != 0; }
bool is_internal() const { return (_flags & JVM_ACC_FIELD_INTERNAL) != 0; }
+ bool is_stable() const { return (_flags & JVM_ACC_FIELD_STABLE) != 0; }
bool field_has_generic_signature() const
{ return (_flags & JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE) != 0; }
--- a/hotspot/test/gc/TestVerifyDuringStartup.java Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/test/gc/TestVerifyDuringStartup.java Sat Sep 14 20:43:34 2013 +0100
@@ -48,7 +48,7 @@
"-XX:+VerifyDuringStartup",
"-version"});
- System.out.print("Testing:\n" + JDKToolFinder.getJDKTool("java"));
+ System.out.print("Testing:\n" + JDKToolFinder.getCurrentJDKTool("java"));
for (int i = 0; i < vmOpts.size(); i += 1) {
System.out.print(" " + vmOpts.get(i));
}
--- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/JDKToolFinder.java Fri Sep 06 09:55:59 2013 +0100
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/JDKToolFinder.java Sat Sep 14 20:43:34 2013 +0100
@@ -27,24 +27,43 @@
public final class JDKToolFinder {
- private JDKToolFinder() {
- }
-
- /**
- * Returns the full path to an executable in jdk/bin based on System property
- * test.jdk (set by jtreg test suite)
- *
- * @return Full path to an executable in jdk/bin
- */
- public static String getJDKTool(String tool) {
- String binPath = System.getProperty("test.jdk");
- if (binPath == null) {
- throw new RuntimeException("System property 'test.jdk' not set. This property is normally set by jtreg. "
- + "When running test separately, set this property using '-Dtest.jdk=/path/to/jdk'.");
+ private JDKToolFinder() {
}
- binPath += File.separatorChar + "bin" + File.separatorChar + tool;
+ /**
+ * Returns the full path to an executable in jdk/bin based on System
+ * property {@code compile.jdk} (set by jtreg test suite)
+ *
+ * @return Full path to an executable in jdk/bin
+ */
+ public static String getJDKTool(String tool) {
+ String binPath = System.getProperty("compile.jdk");
+ if (binPath == null) {
+ throw new RuntimeException("System property 'compile.jdk' not set. "
+ + "This property is normally set by jtreg. "
+ + "When running test separately, set this property using "
+ + "'-Dcompile.jdk=/path/to/jdk'.");
+ }
+ binPath += File.separatorChar + "bin" + File.separatorChar + tool;
- return binPath;
- }
+ return binPath;
+ }
+ /**
+ * Returns the full path to an executable in <current jdk>/bin based
+ * on System property {@code test.jdk} (set by jtreg test suite)
+ *
+ * @return Full path to an executable in jdk/bin
+ */
+ public static String getCurrentJDKTool(String tool) {
+ String binPath = System.getProperty("test.jdk");
+ if (binPath == null) {
+ throw new RuntimeException("System property 'test.jdk' not set. "
+ + "This property is normally set by jtreg. "
+ + "When running test separately, set this property using "
+ + "'-Dtest.jdk=/path/to/jdk'.");
+ }
+ binPath += File.separatorChar + "bin" + File.separatorChar + tool;
+
+ return binPath;
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/Makefile Sat Sep 14 20:43:34 2013 +0100
@@ -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.
+#
+#
+
+ifneq "x$(ALT_BOOTDIR)" "x"
+ BOOTDIR := $(ALT_BOOTDIR)
+endif
+
+ifeq "x$(BOOTDIR)" "x"
+ JDK_HOME := $(shell dirname $(shell which java))/..
+else
+ JDK_HOME := $(BOOTDIR)
+endif
+
+SRC_DIR = src
+BUILD_DIR = build
+OUTPUT_DIR = $(BUILD_DIR)/classes
+WHITEBOX_DIR = ../whitebox
+
+JAVAC = $(JDK_HOME)/bin/javac
+JAR = $(JDK_HOME)/bin/jar
+
+SRC_FILES = $(shell find $(SRC_DIR) -name '*.java')
+
+MAIN_CLASS = sun.hotspot.tools.ctw.CompileTheWorld
+
+.PHONY: clean cleantmp
+
+all: ctw.jar cleantmp
+
+clean: cleantmp
+ @rm -rf ctw.jar wb.jar
+
+cleantmp:
+ @rm -rf filelist manifest.mf
+ @rm -rf $(BUILD_DIR)
+
+ctw.jar: filelist wb.jar manifest.mf
+ @mkdir -p $(OUTPUT_DIR)
+ $(JAVAC) -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) -cp wb.jar @filelist
+ $(JAR) cfm ctw.jar manifest.mf -C $(OUTPUT_DIR) .
+
+wb.jar:
+ make -C ${WHITEBOX_DIR} wb.jar
+ cp ${WHITEBOX_DIR}/wb.jar ./
+ make -C ${WHITEBOX_DIR} clean
+
+filelist: $(SRC_FILES)
+ @rm -f $@
+ @echo $(SRC_FILES) > $@
+
+manifest.mf:
+ @echo "Main-Class: ${MAIN_CLASS}" > manifest.mf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/README Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,93 @@
+#
+# 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.
+#
+#
+
+DESCRIPTION
+
+This is replacement for CompileTheWorld (CTW) written on java. Its purpose is
+to make possible the use of CTW in product builds.
+
+DEPENDENCES
+
+The tool depends on Whitebox API. Assumed, that the sources of whitebox are
+located in '../whitebox' directory.
+
+BUILDING
+
+Simple way to build, just type 'make'.
+
+Makefile uses environment variables 'ALT_BOOTDIR', 'BOOTDIR' as root-dir of jdk
+that will be used for compilation and creating jar.
+
+On successful building 'ctw.jar' will be created.
+
+RUNNING
+
+Since the tool uses WhiteBox API, options 'UnlockDiagnosticVMOptions' and
+'WhiteBoxAPI' should be specified, and 'wb.jar' should be added to
+boot-classpath:
+ $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar
+
+Arguments can be paths to '.jar, '.zip', '.lst' files or directories with
+classes, that define which classes will be compiled:
+ - '.jar', '.zip' files and directories are interpreted like in classpath
+(including '<dir>/*' syntax)
+ - '.lst' files -- files with class names (in java notation) to compile.
+CTW will try to find these classes with default class loader, so they should
+be located in classpath.
+
+Without arguments it would work as old version of CTW: all classes in
+boot-classpath will be compiled, excluding classes in 'rt.jar' if 'rt.jar' isn't
+first in boot-classpath.
+
+Due CTW's flags also are not available in product builds, the tool uses
+properties with the same names:
+ - 'CompileTheWorldPreloadClasses' -- type:boolean, default:true, description:
+Preload all classes used by a class before start loading
+ - 'CompileTheWorldStartAt' -- type:long, default:1, description: First class
+to consider
+ - 'CompileTheWorldStopAt' -- type:long, default:Long.MAX_VALUE, description:
+Last class to consider
+
+Also it uses additional properties:
+ - 'sun.hotspot.tools.ctw.verbose' -- type:boolean, default:false,
+description: Verbose output, adds additional information about compilation
+ - 'sun.hotspot.tools.ctw.logfile' -- type:string, default:null,
+description: Path to logfile, if it's null, cout will be used.
+
+EXAMPLES
+
+compile classes from 'rt.jar':
+ $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar ${JAVA_HOME}/jre/lib/rt.jar
+
+compile classes from all '.jar' in './testjars' directory:
+ $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar ./testjars/*
+
+compile classes from './build/classes' directory:
+ $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar ./build/classes
+
+compile only java.lang.String, java.lang.Object classes:
+ $ echo java.lang.String > classes.lst
+ $ echo java.lang.Object >> classes.lst
+ $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar classes.lst
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathDirEntry.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,117 @@
+/*
+ * 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 sun.hotspot.tools.ctw;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Set;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.concurrent.Executor;
+
+import java.io.*;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+
+/**
+ * * Handler for dirs containing classes to compile.
+ * @author igor.ignatyev@oracle.com
+ */
+public class ClassPathDirEntry extends PathHandler {
+
+ private final int rootLength = root.toString().length();
+
+ public ClassPathDirEntry(Path root, Executor executor) {
+ super(root, executor);
+ try {
+ URL url = root.toUri().toURL();
+ setLoader(new URLClassLoader(new URL[]{url}));
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void process() {
+ System.out.println("# dir: " + root);
+ if (!Files.exists(root)) {
+ return;
+ }
+ try {
+ Files.walkFileTree(root, EnumSet.of(FileVisitOption.FOLLOW_LINKS),
+ Integer.MAX_VALUE, new CompileFileVisitor());
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ }
+
+ private void processFile(Path file) {
+ if (Utils.isClassFile(file.toString())) {
+ processClass(pathToClassName(file));
+ }
+ }
+
+ private String pathToClassName(Path file) {
+ String fileString;
+ if (root == file) {
+ fileString = file.normalize().toString();
+ } else {
+ fileString = file.normalize().toString().substring(rootLength + 1);
+ }
+ return Utils.fileNameToClassName(fileString);
+ }
+
+ private class CompileFileVisitor extends SimpleFileVisitor<Path> {
+
+ private final Set<Path> ready = new HashSet<>();
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir,
+ BasicFileAttributes attrs) throws IOException {
+ if (ready.contains(dir)) {
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ ready.add(dir);
+ return super.preVisitDirectory(dir, attrs);
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file,
+ BasicFileAttributes attrs) throws IOException {
+ if (!ready.contains(file)) {
+ processFile(file);
+ }
+ return isFinished() ? FileVisitResult.TERMINATE
+ : FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path file,
+ IOException exc) throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarEntry.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,81 @@
+/*
+ * 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 sun.hotspot.tools.ctw;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.*;
+import java.util.jar.*;
+import java.util.concurrent.Executor;
+
+import java.io.*;
+import java.nio.file.*;
+
+/**
+ * Handler for jar-files containing classes to compile.
+ * @author igor.ignatyev@oracle.com
+ */
+public class ClassPathJarEntry extends PathHandler {
+
+ public ClassPathJarEntry(Path root, Executor executor) {
+ super(root, executor);
+ try {
+ URL url = root.toUri().toURL();
+ setLoader(new URLClassLoader(new URL[]{url}));
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void process() {
+ System.out.println("# jar: " + root);
+ if (!Files.exists(root)) {
+ return;
+ }
+ try {
+ JarFile jarFile = new JarFile(root.toFile());
+ JarEntry entry;
+ for (Enumeration<JarEntry> e = jarFile.entries();
+ e.hasMoreElements(); ) {
+ entry = e.nextElement();
+ processJarEntry(entry);
+ if (isFinished()) {
+ return;
+ }
+ }
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ }
+
+ private void processJarEntry(JarEntry entry) {
+ String filename = entry.getName();
+ if (Utils.isClassFile(filename)) {
+ processClass(Utils.fileNameToClassName(filename));
+ }
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarInDirEntry.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,62 @@
+/*
+ * 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 sun.hotspot.tools.ctw;
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.Executor;
+
+/**
+ * Handler for dirs containing jar-files with classes to compile.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public class ClassPathJarInDirEntry extends PathHandler {
+
+ public ClassPathJarInDirEntry(Path root, Executor executor) {
+ super(root, executor);
+ }
+
+ @Override
+ public void process() {
+ System.out.println("# jar_in_dir: " + root);
+ if (!Files.exists(root)) {
+ return;
+ }
+ try (DirectoryStream<Path> ds
+ = Files.newDirectoryStream(root, "*.jar")) {
+ for (Path p : ds) {
+ new ClassPathJarEntry(p, executor).process();
+ if (isFinished()) {
+ return;
+ }
+ }
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassesListInFile.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,61 @@
+/*
+ * 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 sun.hotspot.tools.ctw;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.Executor;
+
+/**
+ * Handler for files containing a list of classes to compile.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public class ClassesListInFile extends PathHandler {
+ public ClassesListInFile(Path root, Executor executor) {
+ super(root, executor);
+ }
+
+ @Override
+ public void process() {
+ System.out.println("# list: " + root);
+ if (!Files.exists(root)) {
+ return;
+ }
+ try {
+ try (BufferedReader reader = Files.newBufferedReader(root,
+ StandardCharsets.UTF_8)) {
+ String line;
+ while (!isFinished() && ((line = reader.readLine()) != null)) {
+ processClass(line);
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,175 @@
+/*
+ * 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 sun.hotspot.tools.ctw;
+
+import sun.management.ManagementFactoryHelper;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * @author igor.ignatyev@oracle.com
+ */
+public class CompileTheWorld {
+ /**
+ * Entry point. Compiles classes in {@code args}, or all classes in
+ * boot-classpath if args is empty
+ *
+ * @param args paths to jar/zip, dir contains classes, or to .lst file
+ * contains list of classes to compile
+ */
+ public static void main(String[] args) {
+ String logfile = Utils.LOG_FILE;
+ PrintStream os = null;
+ if (logfile != null) {
+ try {
+ os = new PrintStream(Files.newOutputStream(Paths.get(logfile)));
+ } catch (IOException io) {
+ }
+ }
+ if (os != null) {
+ System.setOut(os);
+ }
+
+ try {
+ try {
+ if (ManagementFactoryHelper.getCompilationMXBean() == null) {
+ throw new RuntimeException(
+ "CTW can not work in interpreted mode");
+ }
+ } catch (java.lang.NoClassDefFoundError e) {
+ // compact1, compact2 support
+ }
+ String[] paths = args;
+ boolean skipRtJar = false;
+ if (args.length == 0) {
+ paths = getDefaultPaths();
+ skipRtJar = true;
+ }
+ ExecutorService executor = createExecutor();
+ long start = System.currentTimeMillis();
+ try {
+ String path;
+ for (int i = 0, n = paths.length; i < n
+ && !PathHandler.isFinished(); ++i) {
+ path = paths[i];
+ if (skipRtJar && i > 0 && isRtJar(path)) {
+ // rt.jar is not first, so skip it
+ continue;
+ }
+ PathHandler.create(path, executor).process();
+ }
+ } finally {
+ await(executor);
+ }
+ System.out.printf("Done (%d classes, %d methods, %d ms)%n",
+ Compiler.getClassCount(),
+ Compiler.getMethodCount(),
+ System.currentTimeMillis() - start);
+ } finally {
+ if (os != null) {
+ os.close();
+ }
+ }
+ }
+
+ private static ExecutorService createExecutor() {
+ final int threadsCount = Math.min(
+ Runtime.getRuntime().availableProcessors(),
+ Utils.CI_COMPILER_COUNT);
+ ExecutorService result;
+ if (threadsCount > 1) {
+ result = new ThreadPoolExecutor(threadsCount, threadsCount,
+ /* keepAliveTime */ 0L, TimeUnit.MILLISECONDS,
+ new ArrayBlockingQueue<>(threadsCount),
+ new ThreadPoolExecutor.CallerRunsPolicy());
+ } else {
+ result = new CurrentThreadExecutor();
+ }
+ return result;
+ }
+
+ private static String[] getDefaultPaths() {
+ String property = System.getProperty("sun.boot.class.path");
+ System.out.println(
+ "# use 'sun.boot.class.path' as args: " + property);
+ return Utils.PATH_SEPARATOR.split(property);
+ }
+
+ private static void await(ExecutorService executor) {
+ executor.shutdown();
+ while (!executor.isTerminated()) {
+ try {
+ executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
+ } catch (InterruptedException ie) {
+ Thread.currentThread().interrupt();
+ break;
+ }
+ }
+ }
+
+ private static boolean isRtJar(String path) {
+ return Utils.endsWithIgnoreCase(path, File.separator + "rt.jar");
+ }
+
+ private static class CurrentThreadExecutor extends AbstractExecutorService {
+ private boolean isShutdown;
+
+ @Override
+ public void shutdown() {
+ this.isShutdown = true;
+ }
+
+ @Override
+ public List<Runnable> shutdownNow() {
+ return null;
+ }
+
+ @Override
+ public boolean isShutdown() {
+ return isShutdown;
+ }
+
+ @Override
+ public boolean isTerminated() {
+ return isShutdown;
+ }
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit)
+ throws InterruptedException {
+ return isShutdown;
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ command.run();
+ }
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,235 @@
+/*
+ * 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 sun.hotspot.tools.ctw;
+
+import sun.hotspot.WhiteBox;
+import sun.misc.SharedSecrets;
+import sun.reflect.ConstantPool;
+
+import java.lang.reflect.Executable;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Provide method to compile whole class.
+ * Also contains compiled methods and classes counters.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public class Compiler {
+ private Compiler() { }
+ private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+ private static final AtomicLong CLASS_COUNT = new AtomicLong(0L);
+ private static final AtomicLong METHOD_COUNT = new AtomicLong(0L);
+ private static volatile boolean CLASSES_LIMIT_REACHED = false;
+
+ /**
+ * @return count of processed classes
+ */
+ public static long getClassCount() {
+ return CLASS_COUNT.get();
+ }
+
+ /**
+ * @return count of processed methods
+ */
+ public static long getMethodCount() {
+ return METHOD_COUNT.get();
+ }
+
+ /**
+ * @return {@code true} if classes limit is reached
+ */
+ public static boolean isLimitReached() {
+ return CLASSES_LIMIT_REACHED;
+ }
+
+ /**
+ * Compiles all methods and constructors.
+ *
+ * @param aClass class to compile
+ * @param executor executor used for compile task invocation
+ * @throws NullPointerException if {@code class} or {@code executor}
+ * is {@code null}
+ */
+ public static void compileClass(Class aClass, Executor executor) {
+ Objects.requireNonNull(aClass);
+ Objects.requireNonNull(executor);
+ long id = CLASS_COUNT.incrementAndGet();
+ if (id > Utils.COMPILE_THE_WORLD_STOP_AT) {
+ CLASS_COUNT.decrementAndGet();
+ CLASSES_LIMIT_REACHED = true;
+ return;
+ }
+
+ if (id >= Utils.COMPILE_THE_WORLD_START_AT) {
+ String name = aClass.getName();
+ try {
+ System.out.printf("[%d]\t%s%n", id, name);
+ ConstantPool constantPool = SharedSecrets.getJavaLangAccess().
+ getConstantPool(aClass);
+ if (Utils.COMPILE_THE_WORLD_PRELOAD_CLASSES) {
+ preloadClasses(name, id, constantPool);
+ }
+ long methodCount = 0;
+ for (Executable e : aClass.getDeclaredConstructors()) {
+ ++methodCount;
+ executor.execute(new CompileMethodCommand(id, name, e));
+ }
+ for (Executable e : aClass.getDeclaredMethods()) {
+ ++methodCount;
+ executor.execute(new CompileMethodCommand(id, name, e));
+ }
+ METHOD_COUNT.addAndGet(methodCount);
+
+ if (Utils.DEOPTIMIZE_ALL_CLASSES_RATE > 0
+ && (id % Utils.DEOPTIMIZE_ALL_CLASSES_RATE == 0)) {
+ WHITE_BOX.deoptimizeAll();
+ }
+ } catch (Throwable t) {
+ System.out.printf("[%d]\t%s\tskipping %s%n", id, name, t);
+ t.printStackTrace();
+ }
+ }
+ }
+
+ private static void preloadClasses(String className, long id,
+ ConstantPool constantPool) {
+ try {
+ for (int i = 0, n = constantPool.getSize(); i < n; ++i) {
+ try {
+ constantPool.getClassAt(i);
+ } catch (IllegalArgumentException ignore) {
+ }
+ }
+ } catch (Throwable t) {
+ System.out.printf("[%d]\t%s\tpreloading failed : %s%n", id,
+ className, t);
+ }
+ }
+
+
+
+ /**
+ * Compilation of method.
+ * Will compile method on all available comp levels.
+ */
+ private static class CompileMethodCommand implements Runnable {
+ private final long classId;
+ private final String className;
+ private final Executable method;
+
+ /**
+ * @param classId id of class
+ * @param className name of class
+ * @param method compiled for compilation
+ */
+ public CompileMethodCommand(long classId, String className,
+ Executable method) {
+ this.classId = classId;
+ this.className = className;
+ this.method = method;
+ }
+
+ @Override
+ public final void run() {
+ int compLevel = Utils.INITIAL_COMP_LEVEL;
+ if (Utils.TIERED_COMPILATION) {
+ for (int i = compLevel; i <= Utils.TIERED_STOP_AT_LEVEL; ++i) {
+ WHITE_BOX.deoptimizeMethod(method);
+ compileMethod(method, i);
+ }
+ } else {
+ compileMethod(method, compLevel);
+ }
+ }
+
+ private void waitCompilation() {
+ if (!Utils.BACKGROUND_COMPILATION) {
+ return;
+ }
+ final Object obj = new Object();
+ synchronized (obj) {
+ for (int i = 0;
+ i < 10 && WHITE_BOX.isMethodQueuedForCompilation(method);
+ ++i) {
+ try {
+ obj.wait(1000);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+
+ private void compileMethod(Executable method, int compLevel) {
+ if (WHITE_BOX.isMethodCompilable(method, compLevel)) {
+ try {
+ WHITE_BOX.enqueueMethodForCompilation(method, compLevel);
+ waitCompilation();
+ int tmp = WHITE_BOX.getMethodCompilationLevel(method);
+ if (tmp != compLevel) {
+ logMethod(method, "compilation level = " + tmp
+ + ", but not " + compLevel);
+ } else if (Utils.IS_VERBOSE) {
+ logMethod(method, "compilation level = " + tmp + ". OK");
+ }
+ } catch (Throwable t) {
+ logMethod(method, "error on compile at " + compLevel
+ + " level");
+ t.printStackTrace();
+ }
+ } else if (Utils.IS_VERBOSE) {
+ logMethod(method, "not compilable at " + compLevel);
+ }
+ }
+
+ private void logMethod(Executable method, String message) {
+ StringBuilder builder = new StringBuilder("[");
+ builder.append(classId);
+ builder.append("]\t");
+ builder.append(className);
+ builder.append("::");
+ builder.append(method.getName());
+ builder.append('(');
+ Class[] params = method.getParameterTypes();
+ for (int i = 0, n = params.length - 1; i < n; ++i) {
+ builder.append(params[i].getName());
+ builder.append(", ");
+ }
+ if (params.length != 0) {
+ builder.append(params[params.length - 1].getName());
+ }
+ builder.append(')');
+ if (message != null) {
+ builder.append('\t');
+ builder.append(message);
+ }
+ System.err.println(builder);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/PathHandler.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,149 @@
+/*
+ * 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 sun.hotspot.tools.ctw;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.io.File;
+
+import java.util.Objects;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.concurrent.Executor;
+
+/**
+ * Abstract handler for path.
+ * <p/>
+ * Concrete subclasses should implement method {@link #process()}.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public abstract class PathHandler {
+ private static final Pattern JAR_IN_DIR_PATTERN
+ = Pattern.compile("^(.*[/\\\\])?\\*$");
+ protected final Path root;
+ protected final Executor executor;
+ private ClassLoader loader;
+
+ /**
+ * @param root root path to process
+ * @param executor executor used for process task invocation
+ * @throws NullPointerException if {@code root} or {@code executor} is
+ * {@code null}
+ */
+ protected PathHandler(Path root, Executor executor) {
+ Objects.requireNonNull(root);
+ Objects.requireNonNull(executor);
+ this.root = root.normalize();
+ this.executor = executor;
+ this.loader = ClassLoader.getSystemClassLoader();
+ }
+
+ /**
+ * Factory method. Construct concrete handler in depends from {@code path}.
+ *
+ * @param path the path to process
+ * @param executor executor used for compile task invocation
+ * @throws NullPointerException if {@code path} or {@code executor} is
+ * {@code null}
+ */
+ public static PathHandler create(String path, Executor executor) {
+ Objects.requireNonNull(path);
+ Objects.requireNonNull(executor);
+ Matcher matcher = JAR_IN_DIR_PATTERN.matcher(path);
+ if (matcher.matches()) {
+ path = matcher.group(1);
+ path = path.isEmpty() ? "." : path;
+ return new ClassPathJarInDirEntry(Paths.get(path), executor);
+ } else {
+ path = path.isEmpty() ? "." : path;
+ Path p = Paths.get(path);
+ if (isJarFile(p)) {
+ return new ClassPathJarEntry(p, executor);
+ } else if (isListFile(p)) {
+ return new ClassesListInFile(p, executor);
+ } else {
+ return new ClassPathDirEntry(p, executor);
+ }
+ }
+ }
+
+ private static boolean isJarFile(Path path) {
+ if (Files.isRegularFile(path)) {
+ String name = path.toString();
+ return Utils.endsWithIgnoreCase(name, ".zip")
+ || Utils.endsWithIgnoreCase(name, ".jar");
+ }
+ return false;
+ }
+
+ private static boolean isListFile(Path path) {
+ if (Files.isRegularFile(path)) {
+ String name = path.toString();
+ return Utils.endsWithIgnoreCase(name, ".lst");
+ }
+ return false;
+ }
+
+ /**
+ * Processes all classes in specified path.
+ */
+ public abstract void process();
+
+ /**
+ * Sets class loader, that will be used to define class at
+ * {@link #processClass(String)}.
+ *
+ * @param loader class loader
+ * @throws NullPointerException if {@code loader} is {@code null}
+ */
+ protected final void setLoader(ClassLoader loader) {
+ Objects.requireNonNull(loader);
+ this.loader = loader;
+ }
+
+ /**
+ * Processes specificed class.
+ * @param name fully qualified name of class to process
+ */
+ protected final void processClass(String name) {
+ try {
+ Class aClass = Class.forName(name, true, loader);
+ Compiler.compileClass(aClass, executor);
+ } catch (ClassNotFoundException | LinkageError e) {
+ System.out.printf("Class %s loading failed : %s%n", name,
+ e.getMessage());
+ }
+ }
+
+ /**
+ * @return {@code true} if processing should be stopped
+ */
+ public static boolean isFinished() {
+ return Compiler.isLimitReached();
+ }
+
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,215 @@
+/*
+ * 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 sun.hotspot.tools.ctw;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import sun.management.ManagementFactoryHelper;
+
+import java.io.File;
+import java.util.regex.Pattern;
+
+/**
+ * Auxiliary methods.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public class Utils {
+ /**
+ * Value of {@code -XX:CompileThreshold}
+ */
+ public static final boolean TIERED_COMPILATION
+ = Boolean.parseBoolean(getVMOption("TieredCompilation", "false"));
+ /**
+ * Value of {@code -XX:BackgroundCompilation}
+ */
+ public static final boolean BACKGROUND_COMPILATION
+ = Boolean.parseBoolean(getVMOption("BackgroundCompilation",
+ "false"));
+ /**
+ * Value of {@code -XX:TieredStopAtLevel}
+ */
+ public static final int TIERED_STOP_AT_LEVEL;
+ /**
+ * Value of {@code -XX:CICompilerCount}
+ */
+ public static final Integer CI_COMPILER_COUNT
+ = Integer.valueOf(getVMOption("CICompilerCount", "1"));
+ /**
+ * Initial compilation level.
+ */
+ public static final int INITIAL_COMP_LEVEL;
+ /**
+ * Compiled path-separator regexp.
+ */
+ public static final Pattern PATH_SEPARATOR = Pattern.compile(
+ File.pathSeparator, Pattern.LITERAL);
+ /**
+ * Value of {@code -DDeoptimizeAllClassesRate}. Frequency of
+ * {@code WB.deoptimizeAll()} invocation If it less that {@code 0},
+ * {@code WB.deoptimizeAll()} will not be invoked.
+ */
+ public static final int DEOPTIMIZE_ALL_CLASSES_RATE
+ = Integer.getInteger("DeoptimizeAllClassesRate", -1);
+ /**
+ * Value of {@code -DCompileTheWorldStopAt}. Last class to consider.
+ */
+ public static final long COMPILE_THE_WORLD_STOP_AT
+ = Long.getLong("CompileTheWorldStopAt", Long.MAX_VALUE);
+ /**
+ * Value of {@code -DCompileTheWorldStartAt}. First class to consider.
+ */
+ public static final long COMPILE_THE_WORLD_START_AT
+ = Long.getLong("CompileTheWorldStartAt", 1);
+ /**
+ * Value of {@code -DCompileTheWorldPreloadClasses}. Preload all classes
+ * used by a class before start loading.
+ */
+ public static final boolean COMPILE_THE_WORLD_PRELOAD_CLASSES;
+ /**
+ * Value of {@code -Dsun.hotspot.tools.ctw.verbose}. Verbose output,
+ * adds additional information about compilation.
+ */
+ public static final boolean IS_VERBOSE
+ = Boolean.getBoolean("sun.hotspot.tools.ctw.verbose");
+ /**
+ * Value of {@code -Dsun.hotspot.tools.ctw.logfile}.Path to logfile, if
+ * it's null, cout will be used.
+ */
+ public static final String LOG_FILE
+ = System.getProperty("sun.hotspot.tools.ctw.logfile");
+ static {
+ if (Utils.TIERED_COMPILATION) {
+ INITIAL_COMP_LEVEL = 1;
+ } else {
+ String vmName = System.getProperty("java.vm.name");
+ if (Utils.endsWithIgnoreCase(vmName, " Server VM")) {
+ INITIAL_COMP_LEVEL = 4;
+ } else if (Utils.endsWithIgnoreCase(vmName, " Client VM")
+ || Utils.endsWithIgnoreCase(vmName, " Minimal VM")) {
+ INITIAL_COMP_LEVEL = 1;
+ } else {
+ throw new RuntimeException("Unknown VM: " + vmName);
+ }
+ }
+
+ TIERED_STOP_AT_LEVEL = Integer.parseInt(getVMOption("TieredStopAtLevel",
+ String.valueOf(INITIAL_COMP_LEVEL)));
+ }
+
+ static {
+ String tmp = System.getProperty("CompileTheWorldPreloadClasses");
+ if (tmp == null) {
+ COMPILE_THE_WORLD_PRELOAD_CLASSES = true;
+ } else {
+ COMPILE_THE_WORLD_PRELOAD_CLASSES = Boolean.parseBoolean(tmp);
+ }
+ }
+
+ public static final String CLASSFILE_EXT = ".class";
+
+ private Utils() {
+ }
+
+ /**
+ * Tests if the string ends with the suffix, ignoring case
+ * considerations
+ *
+ * @param string the tested string
+ * @param suffix the suffix
+ * @return {@code true} if {@code string} ends with the {@code suffix}
+ * @see String#endsWith(String)
+ */
+ public static boolean endsWithIgnoreCase(String string, String suffix) {
+ if (string == null || suffix == null) {
+ return false;
+ }
+ int length = suffix.length();
+ int toffset = string.length() - length;
+ if (toffset < 0) {
+ return false;
+ }
+ return string.regionMatches(true, toffset, suffix, 0, length);
+ }
+
+ /**
+ * Returns value of VM option.
+ *
+ * @param name option's name
+ * @return value of option or {@code null}, if option doesn't exist
+ * @throws NullPointerException if name is null
+ */
+ public static String getVMOption(String name) {
+ String result;
+ HotSpotDiagnosticMXBean diagnostic
+ = ManagementFactoryHelper.getDiagnosticMXBean();
+ result = diagnostic.getVMOption(name).getValue();
+ return result;
+ }
+
+ /**
+ * Returns value of VM option or default value.
+ *
+ * @param name option's name
+ * @param defaultValue default value
+ * @return value of option or {@code defaultValue}, if option doesn't exist
+ * @throws NullPointerException if name is null
+ * @see #getVMOption(String)
+ */
+ public static String getVMOption(String name, String defaultValue) {
+ String result;
+ try {
+ result = getVMOption(name);
+ } catch (NoClassDefFoundError e) {
+ // compact1, compact2 support
+ result = defaultValue;
+ }
+ return result == null ? defaultValue : result;
+ }
+
+ /**
+ * Tests if the filename is valid filename for class file.
+ *
+ * @param filename tested filename
+ */
+ public static boolean isClassFile(String filename) {
+ // If the filename has a period after removing '.class', it's not valid class file
+ return endsWithIgnoreCase(filename, CLASSFILE_EXT)
+ && (filename.indexOf('.')
+ == (filename.length() - CLASSFILE_EXT.length()));
+ }
+
+ /**
+ * Converts the filename to classname.
+ *
+ * @param filename filename to convert
+ * @return corresponding classname.
+ * @throws AssertionError if filename isn't valid filename for class file -
+ * {@link #isClassFile(String)}
+ */
+ public static String fileNameToClassName(String filename) {
+ assert isClassFile(filename);
+ return filename.substring(0, filename.length() - CLASSFILE_EXT.length())
+ .replace(File.separatorChar, '.');
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/test/Bar.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,5 @@
+public class Bar {
+ private static void staticMethod() { }
+ public void method() { }
+ protected Bar() { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/test/ClassesDirTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test ClassesDirTest
+ * @bug 8012447
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src
+ * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox ClassesDirTest Foo Bar
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * @run main ClassesDirTest prepare
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes
+ * @run main ClassesDirTest check ctw.log
+ * @summary testing of CompileTheWorld :: classes in directory
+ * @author igor.ignatyev@oracle.com
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+
+public class ClassesDirTest extends CtwTest {
+ private static final String[] SHOULD_CONTAIN
+ = {"# dir: classes", "Done (2 classes, 6 methods, "};
+
+ private ClassesDirTest() {
+ super(SHOULD_CONTAIN);
+ }
+
+ public static void main(String[] args) throws Exception {
+ new ClassesDirTest().run(args);
+ }
+
+ protected void prepare() throws Exception {
+ String path = "classes";
+ Files.createDirectory(Paths.get(path));
+ Files.move(Paths.get("Foo.class"), Paths.get(path, "Foo.class"),
+ StandardCopyOption.REPLACE_EXISTING);
+ Files.move(Paths.get("Bar.class"), Paths.get(path, "Bar.class"),
+ StandardCopyOption.REPLACE_EXISTING);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/test/ClassesListTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test ClassesListTest
+ * @bug 8012447
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src
+ * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox ClassesListTest Foo Bar
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * @run main ClassesListTest prepare
+ * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes.lst
+ * @run main ClassesListTest check ctw.log
+ * @summary testing of CompileTheWorld :: list of classes in file
+ * @author igor.ignatyev@oracle.com
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+
+public class ClassesListTest extends CtwTest {
+ private static final String[] SHOULD_CONTAIN
+ = {"# list: classes.lst", "Done (4 classes, "};
+
+ private ClassesListTest() {
+ super(SHOULD_CONTAIN);
+ }
+
+ public static void main(String[] args) throws Exception {
+ new ClassesListTest().run(args);
+ }
+
+ protected void prepare() throws Exception {
+ String path = "classes.lst";
+ Files.copy(Paths.get(System.getProperty("test.src"), path),
+ Paths.get(path), StandardCopyOption.REPLACE_EXISTING);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/test/CtwTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+import java.util.List;
+import java.util.Collections;
+import java.util.ArrayList;
+
+import java.io.File;
+import java.io.Writer;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.BufferedReader;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.nio.charset.Charset;
+
+import com.oracle.java.testlibrary.JDKToolFinder;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+public abstract class CtwTest {
+ protected final String[] shouldContain;
+ protected CtwTest(String[] shouldContain) {
+ this.shouldContain = shouldContain;
+ }
+
+ public void run(String[] args) throws Exception {
+ if (args.length == 0) {
+ throw new Error("args is empty");
+ }
+ switch (args[0]) {
+ case "prepare":
+ prepare();
+ break;
+ case "check":
+ check(args);
+ break;
+ default:
+ throw new Error("unregonized action -- " + args[0]);
+ }
+ }
+
+ protected void prepare() throws Exception { }
+
+ protected void check(String[] args) throws Exception {
+ if (args.length < 2) {
+ throw new Error("logfile isn't specified");
+ }
+ String logfile = args[1];
+ try (BufferedReader r = Files.newBufferedReader(Paths.get(logfile),
+ Charset.defaultCharset())) {
+ OutputAnalyzer output = readOutput(r);
+ for (String test : shouldContain) {
+ output.shouldContain(test);
+ }
+ }
+ }
+
+ private static OutputAnalyzer readOutput(BufferedReader reader)
+ throws IOException {
+ StringBuilder builder = new StringBuilder();
+ String eol = String.format("%n");
+ String line;
+
+ while ((line = reader.readLine()) != null) {
+ builder.append(line);
+ builder.append(eol);
+ }
+ return new OutputAnalyzer(builder.toString(), "");
+ }
+
+ protected void dump(OutputAnalyzer output, String name) {
+ try (Writer w = new FileWriter(name + ".out")) {
+ String s = output.getStdout();
+ w.write(s, s.length(), 0);
+ } catch (IOException io) {
+ io.printStackTrace();
+ }
+ try (Writer w = new FileWriter(name + ".err")) {
+ String s = output.getStderr();
+ w.write(s, s.length(), 0);
+ } catch (IOException io) {
+ io.printStackTrace();
+ }
+ }
+
+ protected ProcessBuilder createJarProcessBuilder(String... command)
+ throws Exception {
+ String javapath = JDKToolFinder.getJDKTool("jar");
+
+ ArrayList<String> args = new ArrayList<>();
+ args.add(javapath);
+ Collections.addAll(args, command);
+
+ return new ProcessBuilder(args.toArray(new String[args.size()]));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/test/Foo.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,5 @@
+public class Foo {
+ private static void staticMethod() { }
+ public void method() { }
+ protected Foo() { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/test/JarDirTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test JarDirTest
+ * @bug 8012447
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src
+ * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox JarDirTest Foo Bar
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * @run main JarDirTest prepare
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld jars/*
+ * @run main JarDirTest check ctw.log
+ * @summary testing of CompileTheWorld :: jars in directory
+ * @author igor.ignatyev@oracle.com
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+public class JarDirTest extends CtwTest {
+ private static final String[] SHOULD_CONTAIN
+ = {"# jar_in_dir: jars",
+ "# jar: jars" + File.separator +"foo.jar",
+ "# jar: jars" + File.separator +"bar.jar",
+ "Done (4 classes, 12 methods, "};
+
+ private JarDirTest() {
+ super(SHOULD_CONTAIN);
+ }
+
+ public static void main(String[] args) throws Exception {
+ new JarDirTest().run(args);
+ }
+
+ protected void prepare() throws Exception {
+ String path = "jars";
+ Files.createDirectory(Paths.get(path));
+
+ ProcessBuilder pb = createJarProcessBuilder("cf", "jars/foo.jar",
+ "Foo.class", "Bar.class");
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ dump(output, "ctw-foo.jar");
+ output.shouldHaveExitValue(0);
+
+ pb = createJarProcessBuilder("cf", "jars/bar.jar", "Foo.class",
+ "Bar.class");
+ output = new OutputAnalyzer(pb.start());
+ dump(output, "ctw-bar.jar");
+ output.shouldHaveExitValue(0);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/test/JarsTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test JarsTest
+ * @bug 8012447
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src
+ * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox JarsTest Foo Bar
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * @run main JarsTest prepare
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld foo.jar bar.jar
+ * @run main JarsTest check ctw.log
+ * @summary testing of CompileTheWorld :: jars
+ * @author igor.ignatyev@oracle.com
+ */
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+public class JarsTest extends CtwTest {
+ private static final String[] SHOULD_CONTAIN
+ = {"# jar: foo.jar", "# jar: bar.jar",
+ "Done (4 classes, 12 methods, "};
+
+ private JarsTest() {
+ super(SHOULD_CONTAIN);
+ }
+
+ public static void main(String[] args) throws Exception {
+ new JarsTest().run(args);
+ }
+
+ protected void prepare() throws Exception {
+ ProcessBuilder pb = createJarProcessBuilder("cf", "foo.jar",
+ "Foo.class", "Bar.class");
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ dump(output, "ctw-foo.jar");
+ output.shouldHaveExitValue(0);
+
+ pb = createJarProcessBuilder("cf", "bar.jar", "Foo.class", "Bar.class");
+ output = new OutputAnalyzer(pb.start());
+ dump(output, "ctw-bar.jar");
+ output.shouldHaveExitValue(0);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/test/classes.lst Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,4 @@
+java.lang.String
+java.lang.Object
+Foo
+Bar
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/whitebox/Makefile Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,63 @@
+#
+# 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.
+#
+#
+
+ifneq "x$(ALT_BOOTDIR)" "x"
+ BOOTDIR := $(ALT_BOOTDIR)
+endif
+
+ifeq "x$(BOOTDIR)" "x"
+ JDK_HOME := $(shell dirname $(shell which java))/..
+else
+ JDK_HOME := $(BOOTDIR)
+endif
+
+SRC_DIR = ./
+BUILD_DIR = build
+OUTPUT_DIR = $(BUILD_DIR)/classes
+
+JAVAC = $(JDK_HOME)/bin/javac
+JAR = $(JDK_HOME)/bin/jar
+
+SRC_FILES = $(shell find $(SRC_DIR) -name '*.java')
+
+.PHONY: filelist clean cleantmp
+
+all: wb.jar cleantmp
+
+wb.jar: filelist
+ @mkdir -p $(OUTPUT_DIR)
+ $(JAVAC) -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) -cp $(OUTPUT_DIR) @filelist
+ $(JAR) cf wb.jar -C $(OUTPUT_DIR) .
+ @rm -rf $(OUTPUT_DIR)
+
+filelist: $(SRC_FILES)
+ @rm -f $@
+ @echo $(SRC_FILES) > $@
+
+clean: cleantmp
+ @rm -rf wb.jar
+
+cleantmp:
+ @rm -rf filelist
+ @rm -rf $(BUILD_DIR)
--- a/jaxp/.hgtags Fri Sep 06 09:55:59 2013 +0100
+++ b/jaxp/.hgtags Sat Sep 14 20:43:34 2013 +0100
@@ -228,3 +228,4 @@
a22fe9bd01e6c7e7ddc7995dfc9471711692b8d1 jdk8-b104
09a46ec11f880154886c70be03aff5ab2ddf0ab7 jdk8-b105
d3be8e3b429df917e72c1c23e7920c651219b587 jdk8-b106
+d6a32e3831aab20a9a3bc78cdc0a60aaad725c6c jdk8-b107
--- a/jaxws/.hgtags Fri Sep 06 09:55:59 2013 +0100
+++ b/jaxws/.hgtags Sat Sep 14 20:43:34 2013 +0100
@@ -228,3 +228,4 @@
42211ab0ab1cca51a050d184634cf1db7ef81fbf jdk8-b104
88390df7ed2cf128298a02c5e6d978f0a603cd58 jdk8-b105
6908370afe834ff01739e8ec992d4246c74b7e6e jdk8-b106
+e3c9328f75638289a342ce15fbe532f05078946e jdk8-b107
--- a/jdk/.hgtags Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/.hgtags Sat Sep 14 20:43:34 2013 +0100
@@ -228,3 +228,4 @@
f1d8d15bfcb5ada858a942f8a31f6598f23214d1 jdk8-b104
1fe211ae3d2b8cc2dfc4f58d9a6eb96418679672 jdk8-b105
c817276bd870dfe1dcc3a3dbbc092436b6907f75 jdk8-b106
+eea685b9ccaa1980e0a7e07d6a3a84bcc7e9ab82 jdk8-b107
--- a/jdk/make/Makefile Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/Makefile Sat Sep 14 20:43:34 2013 +0100
@@ -99,7 +99,6 @@
CACERTS_FILE.desc = Location of certificates file
DEVTOOLS_PATH.desc = Directory containing zip and unzip
CUPS_HEADERS_PATH.desc = Include directory location for CUPS header files
-DXSDK_PATH.desc = Root directory of DirectX SDK
# Make variables to print out (description and value)
VARIABLE_PRINTVAL_LIST += \
@@ -128,17 +127,6 @@
VARIABLE_CHECKFIL_LIST += \
CACERTS_FILE
-# Some are windows specific
-ifeq ($(PLATFORM), windows)
-
-VARIABLE_PRINTVAL_LIST += \
- DXSDK_PATH
-
-VARIABLE_CHECKDIR_LIST += \
- DXSDK_PATH
-
-endif
-
# For pattern rules below, so all are treated the same
DO_PRINTVAL_LIST=$(VARIABLE_PRINTVAL_LIST:%=%.printval)
DO_CHECKDIR_LIST=$(VARIABLE_CHECKDIR_LIST:%=%.checkdir)
--- a/jdk/make/common/Defs-macosx.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/common/Defs-macosx.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -397,12 +397,10 @@
INCLUDE_SA = true
endif
-ifdef CROSS_COMPILE_ARCH
- # X11 headers are not under /usr/include
- OTHER_CFLAGS += -I$(OPENWIN_HOME)/include
- OTHER_CXXFLAGS += -I$(OPENWIN_HOME)/include
- OTHER_CPPFLAGS += -I$(OPENWIN_HOME)/include
-endif
+# X11 headers are not under /usr/include
+OTHER_CFLAGS += -I$(OPENWIN_HOME)/include
+OTHER_CXXFLAGS += -I$(OPENWIN_HOME)/include
+OTHER_CPPFLAGS += -I$(OPENWIN_HOME)/include
LIB_LOCATION ?= $(LIBDIR)
--- a/jdk/make/common/Defs-windows.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/common/Defs-windows.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -78,8 +78,6 @@
MS_RUNTIME_LIBRARIES = $(MSVCRNN_DLL)
endif
-EXTRA_LFLAGS += -LIBPATH:$(DXSDK_LIB_PATH)
-
# Full Debug Symbols has been enabled on Windows since JDK1.4.1.
# The Full Debug Symbols (FDS) default for VARIANT == OPT builds is
# enabled with debug info files ZIP'ed to save space. For VARIANT !=
--- a/jdk/make/common/Sanity.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/common/Sanity.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -65,7 +65,6 @@
sane-libCrun \
sane-unixccs_path \
sane-msdevtools_path \
- sane-dxsdk \
sane-compiler \
sane-cacerts \
sane-ant_version \
--- a/jdk/make/common/shared/Defs-versions.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/common/shared/Defs-versions.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -74,9 +74,6 @@
# REQUIRED_CYGWIN_VER
# Windows only: If CYGWIN is used, the minimum CYGWIN version.
#
-# REQUIRED_DXSDK_VER
-# Windows only: The version of DirectX SDK expected.
-#
# REQUIRED_FREETYPE_VERSION
# If we are using freetype, the freetype version expected.
#
@@ -193,7 +190,6 @@
REQUIRED_OS_VARIANT_VERSION = $(REQUIRED_OS_VERSION)
REQUIRED_CYGWIN_VER = 4.0
REQUIRED_MKS_VER = 6.1
- REQUIRED_DXSDK_VER = 0x0900
ifeq ($(CC_VERSION),msvc)
REQUIRED_COMPILER_NAME = Visual Studio 10
REQUIRED_COMPILER_VERSION = VS2010
--- a/jdk/make/common/shared/Defs-windows.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/common/shared/Defs-windows.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -79,7 +79,7 @@
# The ALT values should never really have spaces or use \.
# Suspect these environment variables to have spaces and/or \ characters:
# SYSTEMROOT, SystemRoot, WINDIR, windir, PROGRAMFILES, ProgramFiles,
-# DXSDK_DIR, MSTOOLS, Mstools, MSSDK, MSSdk, VCnnCOMNTOOLS,
+# MSTOOLS, Mstools, MSSDK, MSSdk, VCnnCOMNTOOLS,
# MSVCDIR, MSVCDir.
# So use $(subst \,/,) on them first adding quotes and placing them in
# their own variable assigned with :=, then use FullPath.
@@ -255,18 +255,6 @@
_program_files:=
endif
-# DirectX SDK
-ifdef ALT_DXSDK_DRIVE
- _dx_sdk_dir =$(ALT_DXSDK_DRIVE):/DXSDK
-else
- ifdef DXSDK_DIR
- xDXSDK_DIR :="$(subst \,/,$(DXSDK_DIR))"
- else
- xDXSDK_DIR :="$(_system_drive)/DXSDK"
- endif
- _dx_sdk_dir :=$(call FullPath,$(xDXSDK_DIR))
-endif
-
# Use of the Visual Studio compilers requires certain env variables be set:
# PATH should include the path to cl.exe
# INCLUDE should be defined
@@ -489,39 +477,6 @@
MSVCRNN_DLL_PATH:=$(call AltCheckValue,MSVCRNN_DLL_PATH)
endif
-# DXSDK_PATH: path to Microsoft DirectX SDK Include and Lib
-ifdef ALT_DXSDK_PATH
- xALT_DXSDK_PATH :="$(subst \,/,$(ALT_DXSDK_PATH))"
- DXSDK_PATH :=$(call FullPath,$(xALT_DXSDK_PATH))
-else
- _DXSDK_PATH1 :=$(_dx_sdk_dir)
- _DXSDK_PATH2 :=$(JDK_DEVTOOLS_DIR)/windows/dxsdk
- DXSDK_PATH :=$(call DirExists,$(_DXSDK_PATH1),$(_DXSDK_PATH2),$(_dx_sdk_dir))
-endif
-DXSDK_PATH :=$(call AltCheckSpaces,DXSDK_PATH)
-DXSDK_PATH:=$(call AltCheckValue,DXSDK_PATH)
-
-# DXSDK_INCLUDE_PATH: path to Microsoft DirectX SDK Include
-ifdef ALT_DXSDK_INCLUDE_PATH
- xALT_DXSDK_INCLUDE_PATH :="$(subst \,/,$(ALT_DXSDK_INCLUDE_PATH))"
- DXSDK_INCLUDE_PATH :=$(call FullPath,$(xALT_DXSDK_INCLUDE_PATH))
-else
- DXSDK_INCLUDE_PATH =$(subst //,/,$(DXSDK_PATH)/Include)
-endif
-
-# DXSDK_LIB_PATH: path to Microsoft DirectX SDK Lib
-ifdef ALT_DXSDK_LIB_PATH
- xALT_DXSDK_LIB_PATH :="$(subst \,/,$(ALT_DXSDK_LIB_PATH))"
- DXSDK_LIB_PATH :=$(call FullPath,$(xALT_DXSDK_LIB_PATH))
-else
- ifeq ($(ARCH_DATA_MODEL), 64)
- # 64bit libs are located in "Lib/x64" subdir
- DXSDK_LIB_PATH =$(subst //,/,$(DXSDK_PATH)/Lib/x64)
- else
- DXSDK_LIB_PATH =$(subst //,/,$(DXSDK_PATH)/Lib)
- endif
-endif
-
# DEPLOY_MSSDK: Microsoft SDK for this platform (for deploy)
ifdef ALT_DEPLOY_MSSDK
xALT_DEPLOY_MSSDK :="$(subst \,/,$(ALT_DEPLOY_MSSDK))"
--- a/jdk/make/common/shared/Sanity-Settings.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/common/shared/Sanity-Settings.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -234,10 +234,6 @@
ALL_SETTINGS+=$(call addAltSetting,HOTSPOT_SERVER_PATH)
ifeq ($(PLATFORM),windows)
ALL_SETTINGS+=$(call addAltSetting,HOTSPOT_LIB_PATH)
- ALL_SETTINGS+=$(call addRequiredSetting,DXSDK_VER)
- ALL_SETTINGS+=$(call addAltSetting,DXSDK_PATH)
- ALL_SETTINGS+=$(call addAltSetting,DXSDK_INCLUDE_PATH)
- ALL_SETTINGS+=$(call addAltSetting,DXSDK_LIB_PATH)
ALL_SETTINGS+=$(call addAltSetting,WINDOWSSDKDIR)
ALL_SETTINGS+=$(call addRequiredSetting,RC)
ALL_SETTINGS+=$(call addRequiredSetting,REBASE)
--- a/jdk/make/common/shared/Sanity.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/common/shared/Sanity.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -143,8 +143,6 @@
_CYGWIN_VER := $(SYSTEM_UNAME)
CYGWIN_VER :=$(call GetVersion,$(_CYGWIN_VER))
endif
- DXSDK_VER := $(shell $(EGREP) DIRECT3D_VERSION $(DXSDK_INCLUDE_PATH)/d3d9.h 2>&1 | \
- $(EGREP) "\#define" | $(NAWK) '{print $$3}')
endif
# Get the version numbers of what we are using
@@ -1301,51 +1299,6 @@
fi
######################################################
-# Check for windows DirectX sdk directory
-######################################################
-sane-dxsdk:
-ifeq ($(PLATFORM), windows)
- @if [ ! -r $(DXSDK_INCLUDE_PATH)/d3d9.h ]; then \
- $(ECHO) "ERROR: You do not have access to a valid DirectX SDK Include dir.\n" \
- " The value of DXSDK_INCLUDE_PATH must point a valid DX SDK dir.\n" \
- " Please check your access to \n" \
- " $(DXSDK_INCLUDE_PATH) \n" \
- " and/or check your value of ALT_DXSDK_PATH or ALT_DXSDK_INCLUDE_PATH.\n" \
- " Microsoft DirectX 9 SDK (Summer 2004 Update or newer) can be downloaded from the following location:\n" \
- " http://msdn.microsoft.com/library/default.asp?url=/downloads/list/directx.asp\n" \
- " Or http://www.microsoft.com/directx\n" \
- "" >> $(ERROR_FILE) ; \
- else \
- if [ ! "$(DXSDK_VER)" = "$(REQUIRED_DXSDK_VER)" ]; then \
- $(ECHO) "ERROR: The DirectX SDK must be version $(REQUIRED_DXSDK_VER).\n" \
- " $(YOU_ARE_USING) DirectX SDK version: $(DXSDK_VER)\n" \
- " The DirectX SDK was obtained from the following location: \n" \
- " $(DXSDK_PATH) \n" \
- " Please change your DirectX SDK. \n" \
- " Microsoft DirectX 9 SDK (Summer 2004 Update or newer) can be downloaded from the following location:\n" \
- " http://msdn.microsoft.com/library/default.asp?url=/downloads/list/directx.asp\n" \
- " Or http://www.microsoft.com/directx\n" \
- "" >> $(ERROR_FILE) ; \
- else \
- if [ -r $(DXSDK_INCLUDE_PATH)/basetsd.h ]; then \
- if [ `$(EGREP) -c __int3264 $(DXSDK_INCLUDE_PATH)/basetsd.h` -ne 0 ]; then \
- $(ECHO) "WARNING: The DirectX SDK Include directory contains a newer basetsd.h,\n" \
- " which may indicate that you're using an incorrect version of DirectX SDK.\n" \
- " This may result in a build failure.\n" \
- " The DirectX SDK Include dir was obtained from the following location:\n" \
- " $(DXSDK_INCLUDE_PATH) \n" \
- " Please change your DirectX SDK to version 9 (Summer 2004 Update or newer).\n" \
- " Microsoft DirectX 9 SDK can be downloaded from the following location:\n" \
- " http://msdn.microsoft.com/library/default.asp?url=/downloads/list/directx.asp\n" \
- " Or http://www.microsoft.com/directx\n" \
- "" >> $(WARNING_FILE) ; \
- fi \
- fi \
- fi \
- fi
-endif
-
-######################################################
# Check the linker version(s)
######################################################
ifeq ($(PLATFORM), windows)
--- a/jdk/make/java/java/Makefile Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/java/java/Makefile Sat Sep 14 20:43:34 2013 +0100
@@ -105,6 +105,7 @@
java/util/prefs/MacOSXPreferencesFactory.java
CFLAGS_$(VARIANT)/java_props_md.o = -Os -x objective-c
+CFLAGS_$(VARIANT)/java_props_macosx.o = -Os -x objective-c
endif
#
--- a/jdk/make/java/java/genlocales.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/java/java/genlocales.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -38,31 +38,31 @@
# only FILES_java and FILES_compiled_properties variables will be picked up
#
# $(BUILDDIR)/java/util/FILES_java.gmk & $(BUILDDIR)/java/util/FILES_properties.gmk
-# contain "sun.util.resources" for US language support
+# contain "sun.util.resources" for EN language support
include $(BUILDDIR)/java/util/FILES_java.gmk
include $(BUILDDIR)/java/util/FILES_properties.gmk
-US_Resources_java := $(FILES_java)
-US_Resources_properties := $(FILES_compiled_properties)
+EN_Resources_java := $(FILES_java)
+EN_Resources_properties := $(FILES_compiled_properties)
# $(BUILDDIR)/java/text/FILES_java.gmk contains the "sun.text.resources" for
-# US language support
+# EN language support
include $(BUILDDIR)/java/text/base/FILES_java.gmk
-US_Resources_java += $(FILES_java)
+EN_Resources_java += $(FILES_java)
FILES_compiled_properties=
# $(BUILDDIR)/sun/text/FILES_java.gmk & $(BUILDDIR)/sun/text/FILES_properties.gmk
-# contain both resources for Non-US language support
+# contain both resources for Non-EN language support
include $(BUILDDIR)/sun/text/FILES_java.gmk
include $(BUILDDIR)/sun/text/FILES_properties.gmk
-NonUS_Resources_java := $(FILES_java)
-NonUS_Resources_properties := $(FILES_compiled_properties)
+NonEN_Resources_java := $(FILES_java)
+NonEN_Resources_properties := $(FILES_compiled_properties)
# Restore the orignal FILES_java & FILES_compiled_properties variables
FILES_java := $(FILES_java_orig)
@@ -80,30 +80,30 @@
ifeq ($(PLATFORM), macosx)
$(LocaleDataMetaInfo_Dest):$(LocaleDataMetaInfo_Src) $(LOCALEGEN_SH)
- @$(RM) $@.tmp.us $@.tmp.nonus;
+ @$(RM) $@.tmp.en $@.tmp.nonen;
@$(prep-target)
- @$(ECHO) $(US_Resources_properties) | $(NAWK) 'gsub(/.properties/,"\n") {print}' > $@.tmp.us;
- @$(ECHO) $(US_Resources_java) | $(NAWK) 'gsub(/.java/,"\n") {print}' >> $@.tmp.us;
- @$(ECHO) $(NonUS_Resources_properties) | $(NAWK) 'gsub(/.properties/,"\n") {print}' > $@.tmp.nonus;
- @$(ECHO) $(NonUS_Resources_java) | $(NAWK) 'gsub(/.java/,"\n") {print}' >> $@.tmp.nonus;
+ @$(ECHO) $(EN_Resources_properties) | $(NAWK) 'gsub(/.properties/,"\n") {print}' > $@.tmp.en;
+ @$(ECHO) $(EN_Resources_java) | $(NAWK) 'gsub(/.java/,"\n") {print}' >> $@.tmp.en;
+ @$(ECHO) $(NonEN_Resources_properties) | $(NAWK) 'gsub(/.properties/,"\n") {print}' > $@.tmp.nonen;
+ @$(ECHO) $(NonEN_Resources_java) | $(NAWK) 'gsub(/.java/,"\n") {print}' >> $@.tmp.nonen;
NAWK="$(NAWK)" SED="$(SED)" SORT="$(SORT)" \
- $(SH) $(LOCALEGEN_SH) $(RESOURCE_NAMES) $@.tmp.us \
- $@.tmp.nonus $< $@
- @$(RM) $@.tmp.us $@.tmp.nonus;
+ $(SH) $(LOCALEGEN_SH) $(RESOURCE_NAMES) $@.tmp.en \
+ $@.tmp.nonen $< $@
+ @$(RM) $@.tmp.en $@.tmp.nonen;
else
$(LocaleDataMetaInfo_Dest):$(LocaleDataMetaInfo_Src) $(LOCALEGEN_SH)
- @$(RM) $@.tmp.us $@.tmp.nonus;
+ @$(RM) $@.tmp.en $@.tmp.nonen;
@$(prep-target)
- @$(ECHO) $(subst .properties,'\n',$(US_Resources_properties)) > $@.tmp.us;
- @$(ECHO) $(subst .java,'\n',$(US_Resources_java)) >> $@.tmp.us;
- @$(ECHO) $(subst .properties,'\n',$(NonUS_Resources_properties)) > $@.tmp.nonus;
- @$(ECHO) $(subst .java,'\n',$(NonUS_Resources_java)) >> $@.tmp.nonus;
+ @$(ECHO) $(subst .properties,'\n',$(EN_Resources_properties)) > $@.tmp.en;
+ @$(ECHO) $(subst .java,'\n',$(EN_Resources_java)) >> $@.tmp.en;
+ @$(ECHO) $(subst .properties,'\n',$(NonEN_Resources_properties)) > $@.tmp.nonen;
+ @$(ECHO) $(subst .java,'\n',$(NonEN_Resources_java)) >> $@.tmp.nonen;
NAWK="$(NAWK)" SED="$(SED)" SORT="$(SORT)" \
- $(SH) $(LOCALEGEN_SH) $(RESOURCE_NAMES) $@.tmp.us \
- $@.tmp.nonus $< $@
- @$(RM) $@.tmp.us $@.tmp.nonus;
+ $(SH) $(LOCALEGEN_SH) $(RESOURCE_NAMES) $@.tmp.en \
+ $@.tmp.nonen $< $@
+ @$(RM) $@.tmp.en $@.tmp.nonen;
endif
genlocales : $(LocaleDataMetaInfo_Dest)
--- a/jdk/make/java/java/localegen.sh Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/java/java/localegen.sh Sat Sep 14 20:43:34 2013 +0100
@@ -35,11 +35,11 @@
# A list of resource base name list;
RESOURCE_NAMES=$1
-# A list of US resources;
-US_FILES_LIST=$2
+# A list of EN resources;
+EN_FILES_LIST=$2
-# A list of non-US resources;
-NONUS_FILES_LIST=$3
+# A list of non-EN resources;
+NONEN_FILES_LIST=$3
INPUT_FILE=$4
OUTPUT_FILE=$5
@@ -53,23 +53,23 @@
sed_script="$SED -e \"s@^#warn .*@// -- This file was mechanically generated: Do not edit! -- //@\" "
# ja-JP-JP and th-TH-TH need to be manually added, as they don't have any resource files.
-nonusall=" ja-JP-JP th-TH-TH "
+nonenall=" ja-JP-JP th-TH-TH "
for FILE in $RESOURCE_NAMES
do
- getlocalelist $FILE $US_FILES_LIST
- sed_script=$sed_script"-e \"s@#"$FILE"_USLocales#@$localelist@g\" "
- usall=$usall" "$localelist
- getlocalelist $FILE $NONUS_FILES_LIST
- sed_script=$sed_script"-e \"s@#"$FILE"_NonUSLocales#@$localelist@g\" "
- nonusall=$nonusall" "$localelist
+ getlocalelist $FILE $EN_FILES_LIST
+ sed_script=$sed_script"-e \"s@#"$FILE"_ENLocales#@$localelist@g\" "
+ enall=$enall" "$localelist
+ getlocalelist $FILE $NONEN_FILES_LIST
+ sed_script=$sed_script"-e \"s@#"$FILE"_NonENLocales#@$localelist@g\" "
+ nonenall=$nonenall" "$localelist
done
-usall=`(for LOC in $usall; do echo $LOC;done) |$SORT -u`
-nonusall=`(for LOC in $nonusall; do echo $LOC;done) |$SORT -u`
+enall=`(for LOC in $enall; do echo $LOC;done) |$SORT -u`
+nonenall=`(for LOC in $nonenall; do echo $LOC;done) |$SORT -u`
-sed_script=$sed_script"-e \"s@#AvailableLocales_USLocales#@$usall@g\" "
-sed_script=$sed_script"-e \"s@#AvailableLocales_NonUSLocales#@$nonusall@g\" "
+sed_script=$sed_script"-e \"s@#AvailableLocales_ENLocales#@$enall@g\" "
+sed_script=$sed_script"-e \"s@#AvailableLocales_NonENLocales#@$nonenall@g\" "
sed_script=$sed_script"$INPUT_FILE > $OUTPUT_FILE"
eval $sed_script
--- a/jdk/make/java/text/base/FILES_java.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/java/text/base/FILES_java.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -107,5 +107,17 @@
sun/text/resources/FormatData.java \
sun/text/resources/JavaTimeSupplementary.java \
sun/text/resources/en/FormatData_en.java \
+ sun/text/resources/en/FormatData_en_AU.java \
+ sun/text/resources/en/FormatData_en_CA.java \
+ sun/text/resources/en/FormatData_en_GB.java \
+ sun/text/resources/en/FormatData_en_IE.java \
+ sun/text/resources/en/FormatData_en_IN.java \
+ sun/text/resources/en/FormatData_en_MT.java \
+ sun/text/resources/en/FormatData_en_NZ.java \
+ sun/text/resources/en/FormatData_en_PH.java \
+ sun/text/resources/en/FormatData_en_SG.java \
sun/text/resources/en/FormatData_en_US.java \
+ sun/text/resources/en/FormatData_en_ZA.java \
sun/text/resources/en/JavaTimeSupplementary_en.java \
+ sun/text/resources/en/JavaTimeSupplementary_en_GB.java \
+ sun/text/resources/en/JavaTimeSupplementary_en_SG.java
--- a/jdk/make/java/util/FILES_java.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/java/util/FILES_java.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -30,4 +30,7 @@
sun/util/resources/LocaleNamesBundle.java \
sun/util/resources/TimeZoneNamesBundle.java \
sun/util/resources/TimeZoneNames.java \
- sun/util/resources/en/TimeZoneNames_en.java
+ sun/util/resources/en/TimeZoneNames_en.java \
+ sun/util/resources/en/TimeZoneNames_en_CA.java \
+ sun/util/resources/en/TimeZoneNames_en_GB.java \
+ sun/util/resources/en/TimeZoneNames_en_IE.java
--- a/jdk/make/java/util/FILES_properties.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/java/util/FILES_properties.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -26,9 +26,25 @@
FILES_compiled_properties = \
sun/util/resources/LocaleNames.properties \
sun/util/resources/en/LocaleNames_en.properties \
+ sun/util/resources/en/LocaleNames_en_MT.properties \
+ sun/util/resources/en/LocaleNames_en_PH.properties \
+ sun/util/resources/en/LocaleNames_en_SG.properties \
\
sun/util/resources/CalendarData.properties \
sun/util/resources/en/CalendarData_en.properties \
+ sun/util/resources/en/CalendarData_en_GB.properties \
+ sun/util/resources/en/CalendarData_en_IE.properties \
+ sun/util/resources/en/CalendarData_en_MT.properties \
\
sun/util/resources/CurrencyNames.properties \
- sun/util/resources/en/CurrencyNames_en_US.properties
+ sun/util/resources/en/CurrencyNames_en_AU.properties \
+ sun/util/resources/en/CurrencyNames_en_CA.properties \
+ sun/util/resources/en/CurrencyNames_en_GB.properties \
+ sun/util/resources/en/CurrencyNames_en_IE.properties \
+ sun/util/resources/en/CurrencyNames_en_IN.properties \
+ sun/util/resources/en/CurrencyNames_en_MT.properties \
+ sun/util/resources/en/CurrencyNames_en_NZ.properties \
+ sun/util/resources/en/CurrencyNames_en_PH.properties \
+ sun/util/resources/en/CurrencyNames_en_SG.properties \
+ sun/util/resources/en/CurrencyNames_en_US.properties \
+ sun/util/resources/en/CurrencyNames_en_ZA.properties
--- a/jdk/make/javax/sound/jsoundds/Makefile Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/javax/sound/jsoundds/Makefile Sat Sep 14 20:43:34 2013 +0100
@@ -55,8 +55,7 @@
LDLIBS += dsound.lib winmm.lib user32.lib ole32.lib
CPPFLAGS += \
-DUSE_DAUDIO=TRUE \
- -I$(SHARE_SRC)/native/com/sun/media/sound \
- -I$(DXSDK_INCLUDE_PATH)
+ -I$(SHARE_SRC)/native/com/sun/media/sound
#
# Add to the ambient VPATH.
--- a/jdk/make/jdk_generic_profile.sh Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/jdk_generic_profile.sh Sat Sep 14 20:43:34 2013 +0100
@@ -80,7 +80,6 @@
# ALT_BOOTDIR
# Windows Only:
# ALT_UNIXCOMMAND_PATH
-# ALT_DXSDK_PATH
# ALT_MSVCRNN_DLL_PATH
#
#############################################################################
--- a/jdk/make/netbeans/awt2d/README Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/netbeans/awt2d/README Sat Sep 14 20:43:34 2013 +0100
@@ -39,7 +39,6 @@
(on Windows):
#>env | grep ALT
ALT_JDK_IMPORT_PATH=c:/devtools/java/jdk1.7.0
- ALT_DXSDK_PATH=c:/devtools/DirectX/DXSDK_Dec06
ALT_BOOTDIR=c:/DevTools/java/jdk1.6.0
If your build is a FASTDEBUG build, don't forget
@@ -50,7 +49,6 @@
accordingly:
make.options=\
ALT_JDK_IMPORT_PATH=c:/devtools/java/jdk1.7.0 \
- ALT_DXSDK_PATH=c:/devtools/DirectX/DXSDK_Dec06 \
ALT_BOOTDIR=c:/DevTools/java/jdk1.6.0 \
FASTDEBUG=true
make=c:/devtools/cygwin/bin/make
@@ -175,7 +173,6 @@
../../build/windows-i586/tmp/sun/sun.awt/splashscreen/CClassHeaders;
../../build/windows-i586/tmp/sun/sun.font/fontmanager/CClassHeaders;
../../build/windows-i586/tmp/sun/sun.font/t2k/CClassHeaders;
- C:/DevTools/DirectX/DXSDK_Dec06/Include;
C:/devtools/VS2003/SDK/v1.1/include;
C:/devtools/VS2003/VC7/ATLMFC/INCLUDE;
C:/devtools/VS2003/VC7/INCLUDE;
@@ -188,7 +185,7 @@
Note that most paths are relative to the native project directory -
this helps if you decide to relocate the workspace later. The ones that
aren't relative are paths to external include directories, like those
- of the Platform SDK, DirectX SDK.
+ of the Platform SDK.
On Unix platforms these may be directories like /usr/include.
The parser must know some defines to correctly parse the source files,
--- a/jdk/make/sun/awt/Makefile Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/sun/awt/Makefile Sat Sep 14 20:43:34 2013 +0100
@@ -564,7 +564,6 @@
-I$(OBJDIR) \
-I$(SHARE_SRC)/native/common \
-I$(WINAWT_native) \
- -I$(DXSDK_INCLUDE_PATH) \
-I$(SHARE_SRC)/native/sun/awt/image/cvutils \
-I$(SHARE_SRC)/native/sun/awt/image \
-I$(SHARE_SRC)/native/sun/java2d/loops \
--- a/jdk/make/sun/cmm/lcms/mapfile-vers Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/sun/cmm/lcms/mapfile-vers Sat Sep 14 20:43:34 2013 +0100
@@ -28,9 +28,8 @@
SUNWprivate_1.1 {
global:
Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative;
- Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative;
- Java_sun_java2d_cmm_lcms_LCMS_getProfileSize;
- Java_sun_java2d_cmm_lcms_LCMS_getProfileData;
+ Java_sun_java2d_cmm_lcms_LCMS_getProfileSizeNative;
+ Java_sun_java2d_cmm_lcms_LCMS_getProfileDataNative;
Java_sun_java2d_cmm_lcms_LCMS_getTagNative;
Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative;
Java_sun_java2d_cmm_lcms_LCMS_colorConvert;
--- a/jdk/make/sun/jawt/Makefile Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/sun/jawt/Makefile Sat Sep 14 20:43:34 2013 +0100
@@ -69,7 +69,6 @@
# Other extra flags needed for compiling.
#
CPPFLAGS += -I$(SHARE_SRC)/native/common \
- -I$(DXSDK_INCLUDE_PATH) \
-I$(PLATFORM_SRC)/native/sun/windows \
-I$(CLASSHDRDIR)/../../awt/CClassHeaders \
-I$(SHARE_SRC)/native/sun/awt/debug \
--- a/jdk/make/sun/text/FILES_java.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/sun/text/FILES_java.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -96,16 +96,6 @@
sun/text/resources/el/FormatData_el.java \
sun/text/resources/el/FormatData_el_CY.java \
sun/text/resources/el/FormatData_el_GR.java \
- sun/text/resources/en/FormatData_en_AU.java \
- sun/text/resources/en/FormatData_en_CA.java \
- sun/text/resources/en/FormatData_en_GB.java \
- sun/text/resources/en/FormatData_en_IE.java \
- sun/text/resources/en/FormatData_en_IN.java \
- sun/text/resources/en/FormatData_en_MT.java \
- sun/text/resources/en/FormatData_en_NZ.java \
- sun/text/resources/en/FormatData_en_PH.java \
- sun/text/resources/en/FormatData_en_SG.java \
- sun/text/resources/en/FormatData_en_ZA.java \
sun/text/resources/es/FormatData_es.java \
sun/text/resources/es/FormatData_es_BO.java \
sun/text/resources/es/FormatData_es_AR.java \
@@ -214,9 +204,6 @@
sun/util/resources/zh/CurrencyNames_zh_SG.java \
sun/util/resources/zh/LocaleNames_zh_HK.java \
sun/util/resources/de/TimeZoneNames_de.java \
- sun/util/resources/en/TimeZoneNames_en_CA.java \
- sun/util/resources/en/TimeZoneNames_en_GB.java \
- sun/util/resources/en/TimeZoneNames_en_IE.java \
sun/util/resources/es/TimeZoneNames_es.java \
sun/util/resources/fr/TimeZoneNames_fr.java \
sun/util/resources/hi/TimeZoneNames_hi.java \
@@ -237,8 +224,6 @@
sun/text/resources/da/JavaTimeSupplementary_da.java \
sun/text/resources/de/JavaTimeSupplementary_de.java \
sun/text/resources/el/JavaTimeSupplementary_el.java \
- sun/text/resources/en/JavaTimeSupplementary_en_GB.java \
- sun/text/resources/en/JavaTimeSupplementary_en_SG.java \
sun/text/resources/es/JavaTimeSupplementary_es.java \
sun/text/resources/et/JavaTimeSupplementary_et.java \
sun/text/resources/fi/JavaTimeSupplementary_fi.java \
--- a/jdk/make/sun/text/FILES_properties.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/sun/text/FILES_properties.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -33,9 +33,6 @@
sun/util/resources/de/LocaleNames_de.properties \
sun/util/resources/el/LocaleNames_el.properties \
sun/util/resources/el/LocaleNames_el_CY.properties \
- sun/util/resources/en/LocaleNames_en_MT.properties \
- sun/util/resources/en/LocaleNames_en_PH.properties \
- sun/util/resources/en/LocaleNames_en_SG.properties \
sun/util/resources/es/LocaleNames_es.properties \
sun/util/resources/es/LocaleNames_es_US.properties \
sun/util/resources/et/LocaleNames_et.properties \
@@ -88,9 +85,6 @@
sun/util/resources/de/CalendarData_de.properties \
sun/util/resources/el/CalendarData_el.properties \
sun/util/resources/el/CalendarData_el_CY.properties \
- sun/util/resources/en/CalendarData_en_GB.properties \
- sun/util/resources/en/CalendarData_en_IE.properties \
- sun/util/resources/en/CalendarData_en_MT.properties \
sun/util/resources/es/CalendarData_es.properties \
sun/util/resources/es/CalendarData_es_ES.properties \
sun/util/resources/es/CalendarData_es_US.properties \
@@ -164,16 +158,6 @@
sun/util/resources/de/CurrencyNames_de_LU.properties \
sun/util/resources/el/CurrencyNames_el_CY.properties \
sun/util/resources/el/CurrencyNames_el_GR.properties \
- sun/util/resources/en/CurrencyNames_en_AU.properties \
- sun/util/resources/en/CurrencyNames_en_CA.properties \
- sun/util/resources/en/CurrencyNames_en_GB.properties \
- sun/util/resources/en/CurrencyNames_en_IE.properties \
- sun/util/resources/en/CurrencyNames_en_IN.properties \
- sun/util/resources/en/CurrencyNames_en_MT.properties \
- sun/util/resources/en/CurrencyNames_en_NZ.properties \
- sun/util/resources/en/CurrencyNames_en_PH.properties \
- sun/util/resources/en/CurrencyNames_en_SG.properties \
- sun/util/resources/en/CurrencyNames_en_ZA.properties \
sun/util/resources/es/CurrencyNames_es.properties \
sun/util/resources/es/CurrencyNames_es_AR.properties \
sun/util/resources/es/CurrencyNames_es_BO.properties \
--- a/jdk/make/tools/src/build/tools/generatecharacter/CharacterName.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/make/tools/src/build/tools/generatecharacter/CharacterName.java Sat Sep 14 20:43:34 2013 +0100
@@ -11,7 +11,7 @@
FileReader reader = null;
try {
if (args.length != 2) {
- System.err.println("Usage: java CharacterName UniocdeData.txt uniName.dat");
+ System.err.println("Usage: java CharacterName UnicodeData.txt uniName.dat");
System.exit(1);
}
--- a/jdk/makefiles/CompileNativeLibraries.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/makefiles/CompileNativeLibraries.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -211,6 +211,7 @@
LIBJAVA_EXCLUDE_FILES += java_props_macosx.c
else
BUILD_LIBJAVA_java_props_md.c_CFLAGS:=-x objective-c
+ BUILD_LIBJAVA_java_props_macosx.c_CFLAGS:=-x objective-c
endif
ifeq ($(OPENJDK_TARGET_OS),windows)
@@ -252,6 +253,7 @@
LDFLAGS_SUFFIX_linux:=$(LIBDL) $(BUILD_LIBFDLIBM),\
LDFLAGS_SUFFIX_macosx:=-L$(JDK_OUTPUTDIR)/objs/ -lfdlibm \
-framework CoreFoundation \
+ -framework Foundation \
-framework Security -framework SystemConfiguration, \
LDFLAGS_SUFFIX_windows:=-export:winFileHandleOpen -export:handleLseek \
jvm.lib $(BUILD_LIBFDLIBM) $(WIN_VERIFY_LIB) \
@@ -472,7 +474,6 @@
$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/windows \
$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/java2d/windows \
$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/java2d/d3d
- LIBAWT_CFLAGS+=-I$(DXSDK_INCLUDE_PATH)
else
LIBAWT_DIRS+=\
$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/java2d/x11
@@ -1482,8 +1483,7 @@
-I$(JDK_TOPDIR)/src/share/native/sun/awt/debug \
-I$(JDK_TOPDIR)/src/share/native/sun/java2d \
-I$(JDK_TOPDIR)/src/share/native/sun/awt/image/cvutils \
- -I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/java2d/windows \
- -I$(DXSDK_INCLUDE_PATH), \
+ -I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/java2d/windows, \
LDFLAGS:=$(LDFLAGS_JDKLIB) $(KERNEL32_LIB) $(LDFLAGS_CXX_JDK) \
advapi32.lib $(WIN_AWT_LIB),\
LDFLAGS_SUFFIX:=$(LDFLAGS_JDKLIB_SUFFIX),\
@@ -2961,8 +2961,7 @@
OPTIMIZATION:=LOW, \
CFLAGS:=$(CFLAGS_JDKLIB) \
$(LIBJSOUND_CFLAGS) \
- -DUSE_DAUDIO=TRUE \
- -I$(DXSDK_INCLUDE_PATH), \
+ -DUSE_DAUDIO=TRUE, \
LDFLAGS:=$(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \
$(call SET_SHARED_LIBRARY_ORIGIN),\
LDFLAGS_SUFFIX:=$(LDFLAGS_JDKLIB_SUFFIX) dsound.lib winmm.lib user32.lib ole32.lib,\
--- a/jdk/makefiles/CreateJars.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/makefiles/CreateJars.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -80,39 +80,6 @@
LOCALEDATA_INCLUDES := $(addprefix sun/text/resources/,$(LOCALEDATA_INCLUDE_LOCALES)) \
$(addprefix sun/util/resources/,$(LOCALEDATA_INCLUDE_LOCALES))
-# For non-US English locale data
-
-LOCALEDATA_INCLUDES += \
- sun/text/resources/en/FormatData_en_AU.class \
- sun/text/resources/en/FormatData_en_CA.class \
- sun/text/resources/en/FormatData_en_GB.class \
- sun/text/resources/en/FormatData_en_IE.class \
- sun/text/resources/en/FormatData_en_IN.class \
- sun/text/resources/en/FormatData_en_MT.class \
- sun/text/resources/en/FormatData_en_NZ.class \
- sun/text/resources/en/FormatData_en_PH.class \
- sun/text/resources/en/FormatData_en_SG.class \
- sun/text/resources/en/FormatData_en_ZA.class \
- sun/util/resources/en/CalendarData_en_GB.class \
- sun/util/resources/en/CalendarData_en_IE.class \
- sun/util/resources/en/CalendarData_en_MT.class \
- sun/util/resources/en/CurrencyNames_en_AU.class \
- sun/util/resources/en/CurrencyNames_en_CA.class \
- sun/util/resources/en/CurrencyNames_en_GB.class \
- sun/util/resources/en/CurrencyNames_en_IE.class \
- sun/util/resources/en/CurrencyNames_en_IN.class \
- sun/util/resources/en/CurrencyNames_en_MT.class \
- sun/util/resources/en/CurrencyNames_en_NZ.class \
- sun/util/resources/en/CurrencyNames_en_PH.class \
- sun/util/resources/en/CurrencyNames_en_SG.class \
- sun/util/resources/en/CurrencyNames_en_ZA.class \
- sun/util/resources/en/LocaleNames_en_MT.class \
- sun/util/resources/en/LocaleNames_en_PH.class \
- sun/util/resources/en/LocaleNames_en_SG.class \
- sun/util/resources/en/TimeZoneNames_en_CA.class \
- sun/util/resources/en/TimeZoneNames_en_GB.class \
- sun/util/resources/en/TimeZoneNames_en_IE.class
-
$(eval $(call SetupArchive,BUILD_LOCALEDATA_JAR,,\
SRCS:=$(JDK_OUTPUTDIR)/classes,\
SUFFIXES:=.class _dict _th,\
--- a/jdk/makefiles/GensrcLocaleDataMetaInfo.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/makefiles/GensrcLocaleDataMetaInfo.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -50,27 +50,27 @@
$(shell $(RM) $(JDK_OUTPUTDIR)/gensrc/sun/util/locale/provider/LocaleDataMetaInfo.java)
endif
-# The US locales
-US_LOCALES:=en en-US
+# The EN locales
+EN_LOCALES:=en%
# ja-JP-JP and th-TH-TH need to be manually added, as they don't have any resource files.
-ALL_NON_US_LOCALES:=ja-JP-JP th-TH-TH
+ALL_NON_EN_LOCALES:=ja-JP-JP th-TH-TH
SED_ARGS:=-e 's|$(HASH)warn This file is preprocessed before being compiled|// -- This file was mechanically generated: Do not edit! -- //|g'
# This macro creates a sed expression that substitues for example:
-# #FormatData_USLocales# with: en and/or en_US.
+# #FormatData_ENLocales# with: en% locales.
define CaptureLocale
$1_LOCALES := $$(subst _,-,$$(filter-out $1,$$(subst $1_,,$$(filter $1_%,$(LOCALE_RESOURCES)))))
- $1_US_LOCALES := $$(filter $(US_LOCALES),$$($1_LOCALES))
- $1_NON_US_LOCALES := $$(filter-out $(US_LOCALES),$$($1_LOCALES))
+ $1_EN_LOCALES := $$(filter $(EN_LOCALES),$$($1_LOCALES))
+ $1_NON_EN_LOCALES := $$(filter-out $(EN_LOCALES),$$($1_LOCALES))
- ALL_US_LOCALES += $$($1_US_LOCALES)
- ALL_NON_US_LOCALES += $$($1_NON_US_LOCALES)
+ ALL_EN_LOCALES += $$($1_EN_LOCALES)
+ ALL_NON_EN_LOCALES += $$($1_NON_EN_LOCALES)
# Don't sed in a space if there are no locales.
- SED_ARGS+= -e 's/$$(HASH)$1_USLocales$$(HASH)/$$(if $$($1_US_LOCALES),$$(SPACE)$$($1_US_LOCALES),)/g'
- SED_ARGS+= -e 's/$$(HASH)$1_NonUSLocales$$(HASH)/$$(if $$($1_NON_US_LOCALES),$$(SPACE)$$($1_NON_US_LOCALES),)/g'
+ SED_ARGS+= -e 's/$$(HASH)$1_ENLocales$$(HASH)/$$(if $$($1_EN_LOCALES),$$(SPACE)$$($1_EN_LOCALES),)/g'
+ SED_ARGS+= -e 's/$$(HASH)$1_NonENLocales$$(HASH)/$$(if $$($1_NON_EN_LOCALES),$$(SPACE)$$($1_NON_EN_LOCALES),)/g'
endef
#sun.text.resources.FormatData
@@ -91,8 +91,8 @@
#sun.util.resources.CalendarData
$(eval $(call CaptureLocale,CalendarData))
-SED_ARGS+= -e 's/$(HASH)AvailableLocales_USLocales$(HASH)/$(sort $(ALL_US_LOCALES))/g'
-SED_ARGS+= -e 's/$(HASH)AvailableLocales_NonUSLocales$(HASH)/$(sort $(ALL_NON_US_LOCALES))/g'
+SED_ARGS+= -e 's/$(HASH)AvailableLocales_ENLocales$(HASH)/$(sort $(ALL_EN_LOCALES))/g'
+SED_ARGS+= -e 's/$(HASH)AvailableLocales_NonENLocales$(HASH)/$(sort $(ALL_NON_EN_LOCALES))/g'
$(JDK_OUTPUTDIR)/gensrc/sun/util/locale/provider/LocaleDataMetaInfo.java: \
$(JDK_TOPDIR)/src/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template
--- a/jdk/makefiles/Setup.gmk Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/makefiles/Setup.gmk Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,10 @@
DISABLE_WARNINGS:=-Xlint:all,-deprecation,-unchecked,-rawtypes,-cast,-serial,-dep-ann,-static,-fallthrough,-try,-varargs,-empty,-finally
+# To build with all warnings enabled, do the following:
+# make JAVAC_WARNINGS="-Xlint:all -Xmaxwarns 10000"
+JAVAC_WARNINGS:=-Xlint:-unchecked,-deprecation,-overrides,classfile,dep-ann,divzero,varargs -Werror
+
# The generate old bytecode javac setup uses the new compiler to compile for the
# boot jdk to generate tools that need to be run with the boot jdk.
# Thus we force the target bytecode to 7.
@@ -41,7 +45,7 @@
JVM:=$(JAVA),\
JAVAC:=$(NEW_JAVAC),\
FLAGS:=-bootclasspath $(JDK_OUTPUTDIR)/classes -source 8 -target 8 \
- -encoding ascii -XDignore.symbol.file=true $(DISABLE_WARNINGS) \
+ -encoding ascii -XDignore.symbol.file=true $(JAVAC_WARNINGS) \
$(GENERATE_JDKBYTECODE_EXTRA_FLAGS),\
SERVER_DIR:=$(SJAVAC_SERVER_DIR),\
SERVER_JVM:=$(SJAVAC_SERVER_JAVA)))
--- a/jdk/makefiles/mapfiles/liblcms/mapfile-vers Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/makefiles/mapfiles/liblcms/mapfile-vers Sat Sep 14 20:43:34 2013 +0100
@@ -28,9 +28,8 @@
SUNWprivate_1.1 {
global:
Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative;
- Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative;
- Java_sun_java2d_cmm_lcms_LCMS_getProfileSize;
- Java_sun_java2d_cmm_lcms_LCMS_getProfileData;
+ Java_sun_java2d_cmm_lcms_LCMS_getProfileSizeNative;
+ Java_sun_java2d_cmm_lcms_LCMS_getProfileDataNative;
Java_sun_java2d_cmm_lcms_LCMS_getTagNative;
Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative;
Java_sun_java2d_cmm_lcms_LCMS_colorConvert;
--- a/jdk/src/macosx/classes/sun/lwawt/LWToolkit.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/macosx/classes/sun/lwawt/LWToolkit.java Sat Sep 14 20:43:34 2013 +0100
@@ -38,6 +38,7 @@
import sun.awt.*;
import sun.lwawt.macosx.*;
import sun.print.*;
+import sun.security.util.SecurityConstants;
public abstract class LWToolkit extends SunToolkit implements Runnable {
@@ -502,7 +503,7 @@
public Clipboard getSystemClipboard() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
- security.checkSystemClipboardAccess();
+ security.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
}
synchronized (this) {
--- a/jdk/src/macosx/native/sun/awt/CTextPipe.m Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/macosx/native/sun/awt/CTextPipe.m Sat Sep 14 20:43:34 2013 +0100
@@ -145,11 +145,6 @@
BOOL saved = false;
- /* Save and restore of graphics context is done before the iteration.
- This seems to work using our test case (see bug ID 7158350) so we are restoring it at
- the end of the for loop. If we find out that save/restore outside the loop
- doesn't work on all cases then we will move the Save/Restore inside the loop.*/
- CGContextSaveGState(cgRef);
CGAffineTransform invTx = CGAffineTransformInvert(strike->fTx);
NSUInteger i;
@@ -226,7 +221,9 @@
}
// reset the font on the context after striking a unicode with CoreText
- CGContextRestoreGState(cgRef);
+ if (saved) {
+ CGContextRestoreGState(cgRef);
+ }
}
// Using the Quartz Surface Data context, draw a hot-substituted character run
--- a/jdk/src/share/classes/com/sun/nio/sctp/Association.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/com/sun/nio/sctp/Association.java Sat Sep 14 20:43:34 2013 +0100
@@ -58,6 +58,13 @@
/**
* Initializes a new instance of this class.
+ *
+ * @param associationID
+ * The association ID
+ * @param maxInStreams
+ * The maximum number of inbound streams
+ * @param maxOutStreams
+ * The maximum number of outbound streams
*/
protected Association(int associationID,
int maxInStreams,
--- a/jdk/src/share/classes/com/sun/nio/sctp/IllegalReceiveException.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/com/sun/nio/sctp/IllegalReceiveException.java Sat Sep 14 20:43:34 2013 +0100
@@ -41,6 +41,9 @@
/**
* Constructs an instance of this class with the specified message.
+ *
+ * @param msg
+ * The String that contains a detailed message
*/
public IllegalReceiveException(String msg) {
super(msg);
--- a/jdk/src/share/classes/com/sun/nio/sctp/IllegalUnbindException.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/com/sun/nio/sctp/IllegalUnbindException.java Sat Sep 14 20:43:34 2013 +0100
@@ -41,6 +41,9 @@
/**
* Constructs an instance of this class with the specified detailed message.
+ *
+ * @param msg
+ * The String that contains a detailed message
*/
public IllegalUnbindException(String msg) {
super(msg);
--- a/jdk/src/share/classes/com/sun/nio/sctp/InvalidStreamException.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/com/sun/nio/sctp/InvalidStreamException.java Sat Sep 14 20:43:34 2013 +0100
@@ -40,6 +40,9 @@
/**
* Constructs an instance of this class with the specified detailed message.
+ *
+ * @param msg
+ * The String that contains a detailed message
*/
public InvalidStreamException(String msg) {
super(msg);
--- a/jdk/src/share/classes/com/sun/nio/sctp/MessageInfo.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/com/sun/nio/sctp/MessageInfo.java Sat Sep 14 20:43:34 2013 +0100
@@ -48,7 +48,7 @@
* longer required to be sent after the time period expires. It is not a hard
* timeout and may be influenced by whether the association supports the partial
* reliability extension, <a href=http://www.ietf.org/rfc/rfc3758.txt>RFC 3758
- * <a>
+ * </a>.
*
* <P> {@code MessageInfo} instances are not safe for use by multiple concurrent
* threads. If a MessageInfo is to be used by more than one thread then access
--- a/jdk/src/share/classes/com/sun/nio/sctp/Notification.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/com/sun/nio/sctp/Notification.java Sat Sep 14 20:43:34 2013 +0100
@@ -40,6 +40,8 @@
public interface Notification {
/**
* Returns the association that this notification is applicable to.
+ *
+ * @return The association
*/
public Association association();
}
--- a/jdk/src/share/classes/com/sun/nio/sctp/SctpChannel.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/com/sun/nio/sctp/SctpChannel.java Sat Sep 14 20:43:34 2013 +0100
@@ -59,7 +59,7 @@
* {@link #setOption(SctpSocketOption,Object) setOption} method. An SCTP
* channel support the following options:
* <blockquote>
- * <table border>
+ * <table border summary="Socket options">
* <tr>
* <th>Option Name</th>
* <th>Description</th>
@@ -636,6 +636,9 @@
/**
* Returns the value of a socket option.
*
+ * @param <T>
+ * The type of the socket option value
+ *
* @param name
* The socket option
*
@@ -659,6 +662,9 @@
/**
* Sets the value of a socket option.
*
+ * @param <T>
+ * The type of the socket option value
+ *
* @param name
* The socket option
*
@@ -752,6 +758,9 @@
* the {@code receive} method of this channel, if it does an
* {@link IllegalReceiveException} will be thrown.
*
+ * @param <T>
+ * The type of the attachment
+ *
* @param dst
* The buffer into which message bytes are to be transferred
*
@@ -831,7 +840,7 @@
* there was insufficient room for the message in the underlying
* output buffer
*
- * @throws InvalidStreamExcepton
+ * @throws InvalidStreamException
* If {@code streamNumner} is negative or greater than or equal to
* the maximum number of outgoing streams
*
--- a/jdk/src/share/classes/com/sun/nio/sctp/SctpMultiChannel.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/com/sun/nio/sctp/SctpMultiChannel.java Sat Sep 14 20:43:34 2013 +0100
@@ -63,7 +63,7 @@
* {@link #setOption(SctpSocketOption,Object,Association) setOption} method. An
* {@code SctpMultiChannel} supports the following options:
* <blockquote>
- * <table border>
+ * <table border summary="Socket options">
* <tr>
* <th>Option Name</th>
* <th>Description</th>
@@ -394,6 +394,9 @@
* Returns all of the remote addresses to which the given association on
* this channel's socket is connected.
*
+ * @param association
+ * The association
+ *
* @return All of the remote addresses for the given association, or
* an empty {@code Set} if the association has been shutdown
*
@@ -431,6 +434,9 @@
* ignored if given. However, if the option is association specific then the
* association must be given.
*
+ * @param <T>
+ * The type of the socket option value
+ *
* @param name
* The socket option
*
@@ -464,6 +470,9 @@
* ignored if given. However, if the option is association specific then the
* association must be given.
*
+ * @param <T>
+ * The type of the socket option value
+ *
* @param name
* The socket option
*
@@ -567,6 +576,9 @@
* the {@code receive} method of this channel, if it does an
* {@link IllegalReceiveException} will be thrown.
*
+ * @param <T>
+ * The type of the attachment
+ *
* @param buffer
* The buffer into which bytes are to be transferred
*
@@ -673,7 +685,7 @@
* there was insufficient room for the message in the underlying
* output buffer
*
- * @throws InvalidStreamExcepton
+ * @throws InvalidStreamException
* If {@code streamNumber} is negative, or if an association already
* exists and {@code streamNumber} is greater than the maximum number
* of outgoing streams
--- a/jdk/src/share/classes/com/sun/nio/sctp/SctpServerChannel.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/com/sun/nio/sctp/SctpServerChannel.java Sat Sep 14 20:43:34 2013 +0100
@@ -47,7 +47,7 @@
* {@link #setOption(SctpSocketOption,Object) setOption} method. SCTP server socket
* channels support the following options:
* <blockquote>
- * <table border>
+ * <table border summary="Socket options">
* <tr>
* <th>Option Name</th>
* <th>Description</th>
@@ -345,6 +345,9 @@
/**
* Returns the value of a socket option.
*
+ * @param <T>
+ * The type of the socket option value
+ *
* @param name
* The socket option
*
@@ -367,6 +370,9 @@
/**
* Sets the value of a socket option.
*
+ * @param <T>
+ * The type of the socket option value
+ *
* @param name
* The socket option
*
--- a/jdk/src/share/classes/java/awt/TextComponent.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/awt/TextComponent.java Sat Sep 14 20:43:34 2013 +0100
@@ -35,6 +35,7 @@
import javax.swing.text.AttributeSet;
import javax.accessibility.*;
import java.awt.im.InputMethodRequests;
+import sun.security.util.SecurityConstants;
/**
* The <code>TextComponent</code> class is the superclass of
@@ -728,7 +729,7 @@
SecurityManager sm = System.getSecurityManager();
if (sm == null) return true;
try {
- sm.checkSystemClipboardAccess();
+ sm.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
return true;
} catch (SecurityException e) {}
return false;
--- a/jdk/src/share/classes/java/awt/Toolkit.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/awt/Toolkit.java Sat Sep 14 20:43:34 2013 +0100
@@ -1270,12 +1270,8 @@
* <p>
* Each actual implementation of this method should first check if there
* is a security manager installed. If there is, the method should call
- * the security manager's <code>checkSystemClipboardAccess</code> method
- * to ensure it's ok to to access the system clipboard. If the default
- * implementation of <code>checkSystemClipboardAccess</code> is used (that
- * is, that method is not overriden), then this results in a call to the
- * security manager's <code>checkPermission</code> method with an <code>
- * AWTPermission("accessClipboard")</code> permission.
+ * the security manager's {@link SecurityManager#checkPermission
+ * checkPermission} method to check {@code AWTPermission("accessClipboard")}.
*
* @return the system Clipboard
* @exception HeadlessException if GraphicsEnvironment.isHeadless()
@@ -1318,14 +1314,9 @@
* system selection <code>Clipboard</code> as described above.
* <p>
* Each actual implementation of this method should first check if there
- * is a <code>SecurityManager</code> installed. If there is, the method
- * should call the <code>SecurityManager</code>'s
- * <code>checkSystemClipboardAccess</code> method to ensure that client
- * code has access the system selection. If the default implementation of
- * <code>checkSystemClipboardAccess</code> is used (that is, if the method
- * is not overridden), then this results in a call to the
- * <code>SecurityManager</code>'s <code>checkPermission</code> method with
- * an <code>AWTPermission("accessClipboard")</code> permission.
+ * is a security manager installed. If there is, the method should call
+ * the security manager's {@link SecurityManager#checkPermission
+ * checkPermission} method to check {@code AWTPermission("accessClipboard")}.
*
* @return the system selection as a <code>Clipboard</code>, or
* <code>null</code> if the native platform does not support a
@@ -1699,25 +1690,20 @@
* therefore not assume that the EventQueue instance returned
* by this method will be shared by other applets or the system.
*
- * <p>First, if there is a security manager, its
- * <code>checkAwtEventQueueAccess</code>
- * method is called.
- * If the default implementation of <code>checkAwtEventQueueAccess</code>
- * is used (that is, that method is not overriden), then this results in
- * a call to the security manager's <code>checkPermission</code> method
- * with an <code>AWTPermission("accessEventQueue")</code> permission.
+ * <p> If there is a security manager then its
+ * {@link SecurityManager#checkPermission checkPermission} method
+ * is called to check {@code AWTPermission("accessEventQueue")}.
*
* @return the <code>EventQueue</code> object
* @throws SecurityException
- * if a security manager exists and its <code>{@link
- * java.lang.SecurityManager#checkAwtEventQueueAccess}</code>
- * method denies access to the <code>EventQueue</code>
+ * if a security manager is set and it denies access to
+ * the {@code EventQueue}
* @see java.awt.AWTPermission
*/
public final EventQueue getSystemEventQueue() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
- security.checkAwtEventQueueAccess();
+ security.checkPermission(SecurityConstants.AWT.CHECK_AWT_EVENTQUEUE_PERMISSION);
}
return getSystemEventQueueImpl();
}
--- a/jdk/src/share/classes/java/awt/Window.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/awt/Window.java Sat Sep 14 20:43:34 2013 +0100
@@ -195,10 +195,9 @@
/**
* This represents the warning message that is
* to be displayed in a non secure window. ie :
- * a window that has a security manager installed for
- * which calling SecurityManager.checkTopLevelWindow()
- * is false. This message can be displayed anywhere in
- * the window.
+ * a window that has a security manager installed that denies
+ * {@code AWTPermission("showWindowWithoutWarningBanner")}.
+ * This message can be displayed anywhere in the window.
*
* @serial
* @see #getWarningString
@@ -417,11 +416,10 @@
* Constructs a new, initially invisible window in default size with the
* specified {@code GraphicsConfiguration}.
* <p>
- * If there is a security manager, this method first calls
- * the security manager's {@code checkTopLevelWindow}
- * method with {@code this}
- * as its argument to determine whether or not the window
- * must be displayed with a warning banner.
+ * If there is a security manager, then it is invoked to check
+ * {@code AWTPermission("showWindowWithoutWarningBanner")}
+ * to determine whether or not the window must be displayed with
+ * a warning banner.
*
* @param gc the {@code GraphicsConfiguration} of the target screen
* device. If {@code gc} is {@code null}, the system default
@@ -432,7 +430,6 @@
* {@code GraphicsEnvironment.isHeadless()} returns {@code true}
*
* @see java.awt.GraphicsEnvironment#isHeadless
- * @see java.lang.SecurityManager#checkTopLevelWindow
*/
Window(GraphicsConfiguration gc) {
init(gc);
@@ -511,25 +508,16 @@
/**
* Constructs a new, initially invisible window in the default size.
- *
- * <p>First, if there is a security manager, its
- * {@code checkTopLevelWindow}
- * method is called with {@code this}
- * as its argument
- * to see if it's ok to display the window without a warning banner.
- * If the default implementation of {@code checkTopLevelWindow}
- * is used (that is, that method is not overriden), then this results in
- * a call to the security manager's {@code checkPermission} method
- * with an {@code AWTPermission("showWindowWithoutWarningBanner")}
- * permission. It that method raises a SecurityException,
- * {@code checkTopLevelWindow} returns false, otherwise it
- * returns true. If it returns false, a warning banner is created.
+ * <p>
+ * If there is a security manager set, it is invoked to check
+ * {@code AWTPermission("showWindowWithoutWarningBanner")}.
+ * If that check fails with a {@code SecurityException} then a warning
+ * banner is created.
*
* @exception HeadlessException when
* {@code GraphicsEnvironment.isHeadless()} returns {@code true}
*
* @see java.awt.GraphicsEnvironment#isHeadless
- * @see java.lang.SecurityManager#checkTopLevelWindow
*/
Window() throws HeadlessException {
GraphicsEnvironment.checkHeadless();
@@ -541,11 +529,10 @@
* {@code Frame} as its owner. The window will not be focusable
* unless its owner is showing on the screen.
* <p>
- * If there is a security manager, this method first calls
- * the security manager's {@code checkTopLevelWindow}
- * method with {@code this}
- * as its argument to determine whether or not the window
- * must be displayed with a warning banner.
+ * If there is a security manager set, it is invoked to check
+ * {@code AWTPermission("showWindowWithoutWarningBanner")}.
+ * If that check fails with a {@code SecurityException} then a warning
+ * banner is created.
*
* @param owner the {@code Frame} to act as owner or {@code null}
* if this window has no owner
@@ -555,7 +542,6 @@
* {@code GraphicsEnvironment.isHeadless} returns {@code true}
*
* @see java.awt.GraphicsEnvironment#isHeadless
- * @see java.lang.SecurityManager#checkTopLevelWindow
* @see #isShowing
*/
public Window(Frame owner) {
@@ -570,11 +556,10 @@
* unless its nearest owning {@code Frame} or {@code Dialog}
* is showing on the screen.
* <p>
- * If there is a security manager, this method first calls
- * the security manager's {@code checkTopLevelWindow}
- * method with {@code this}
- * as its argument to determine whether or not the window
- * must be displayed with a warning banner.
+ * If there is a security manager set, it is invoked to check
+ * {@code AWTPermission("showWindowWithoutWarningBanner")}.
+ * If that check fails with a {@code SecurityException} then a
+ * warning banner is created.
*
* @param owner the {@code Window} to act as owner or
* {@code null} if this window has no owner
@@ -585,7 +570,6 @@
* {@code true}
*
* @see java.awt.GraphicsEnvironment#isHeadless
- * @see java.lang.SecurityManager#checkTopLevelWindow
* @see #isShowing
*
* @since 1.2
@@ -603,11 +587,10 @@
* its nearest owning {@code Frame} or {@code Dialog}
* is showing on the screen.
* <p>
- * If there is a security manager, this method first calls
- * the security manager's {@code checkTopLevelWindow}
- * method with {@code this}
- * as its argument to determine whether or not the window
- * must be displayed with a warning banner.
+ * If there is a security manager set, it is invoked to check
+ * {@code AWTPermission("showWindowWithoutWarningBanner")}. If that
+ * check fails with a {@code SecurityException} then a warning banner
+ * is created.
*
* @param owner the window to act as owner or {@code null}
* if this window has no owner
@@ -621,7 +604,6 @@
* {@code true}
*
* @see java.awt.GraphicsEnvironment#isHeadless
- * @see java.lang.SecurityManager#checkTopLevelWindow
* @see GraphicsConfiguration#getBounds
* @see #isShowing
* @since 1.3
@@ -1362,10 +1344,9 @@
* Gets the warning string that is displayed with this window.
* If this window is insecure, the warning string is displayed
* somewhere in the visible area of the window. A window is
- * insecure if there is a security manager, and the security
- * manager's {@code checkTopLevelWindow} method returns
- * {@code false} when this window is passed to it as an
- * argument.
+ * insecure if there is a security manager and the security
+ * manager denies
+ * {@code AWTPermission("showWindowWithoutWarningBanner")}.
* <p>
* If the window is secure, then {@code getWarningString}
* returns {@code null}. If the window is insecure, this
@@ -1373,7 +1354,6 @@
* {@code awt.appletWarning}
* and returns the string value of that property.
* @return the warning string for this window.
- * @see java.lang.SecurityManager#checkTopLevelWindow(java.lang.Object)
*/
public final String getWarningString() {
return warningString;
@@ -1383,10 +1363,12 @@
warningString = null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
- if (!sm.checkTopLevelWindow(this)) {
+ try {
+ sm.checkPermission(SecurityConstants.AWT.TOPLEVEL_WINDOW_PERMISSION);
+ } catch (SecurityException se) {
// make sure the privileged action is only
// for getting the property! We don't want the
- // above checkTopLevelWindow call to always succeed!
+ // above checkPermission call to always succeed!
warningString = AccessController.doPrivileged(
new GetPropertyAction("awt.appletWarning",
"Java Applet Window"));
--- a/jdk/src/share/classes/java/awt/color/ICC_Profile.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/awt/color/ICC_Profile.java Sat Sep 14 20:43:34 2013 +0100
@@ -37,6 +37,7 @@
import sun.java2d.cmm.PCMM;
import sun.java2d.cmm.CMSManager;
+import sun.java2d.cmm.Profile;
import sun.java2d.cmm.ProfileDataVerifier;
import sun.java2d.cmm.ProfileDeferralMgr;
import sun.java2d.cmm.ProfileDeferralInfo;
@@ -94,7 +95,7 @@
private static final long serialVersionUID = -3938515861990936766L;
- transient long ID;
+ private transient Profile cmmProfile;
private transient ProfileDeferralInfo deferralInfo;
private transient ProfileActivator profileActivator;
@@ -727,8 +728,8 @@
/**
* Constructs an ICC_Profile object with a given ID.
*/
- ICC_Profile(long ID) {
- this.ID = ID;
+ ICC_Profile(Profile p) {
+ this.cmmProfile = p;
}
@@ -751,8 +752,8 @@
* Frees the resources associated with an ICC_Profile object.
*/
protected void finalize () {
- if (ID != 0) {
- CMSManager.getModule().freeProfile(ID);
+ if (cmmProfile != null) {
+ CMSManager.getModule().freeProfile(cmmProfile);
} else if (profileActivator != null) {
ProfileDeferralMgr.unregisterDeferral(profileActivator);
}
@@ -770,7 +771,7 @@
public static ICC_Profile getInstance(byte[] data) {
ICC_Profile thisProfile;
- long theID;
+ Profile p = null;
if (ProfileDeferralMgr.deferring) {
ProfileDeferralMgr.activateProfiles();
@@ -779,32 +780,32 @@
ProfileDataVerifier.verify(data);
try {
- theID = CMSManager.getModule().loadProfile(data);
+ p = CMSManager.getModule().loadProfile(data);
} catch (CMMException c) {
throw new IllegalArgumentException("Invalid ICC Profile Data");
}
try {
- if ((getColorSpaceType (theID) == ColorSpace.TYPE_GRAY) &&
- (getData (theID, icSigMediaWhitePointTag) != null) &&
- (getData (theID, icSigGrayTRCTag) != null)) {
- thisProfile = new ICC_ProfileGray (theID);
+ if ((getColorSpaceType (p) == ColorSpace.TYPE_GRAY) &&
+ (getData (p, icSigMediaWhitePointTag) != null) &&
+ (getData (p, icSigGrayTRCTag) != null)) {
+ thisProfile = new ICC_ProfileGray (p);
}
- else if ((getColorSpaceType (theID) == ColorSpace.TYPE_RGB) &&
- (getData (theID, icSigMediaWhitePointTag) != null) &&
- (getData (theID, icSigRedColorantTag) != null) &&
- (getData (theID, icSigGreenColorantTag) != null) &&
- (getData (theID, icSigBlueColorantTag) != null) &&
- (getData (theID, icSigRedTRCTag) != null) &&
- (getData (theID, icSigGreenTRCTag) != null) &&
- (getData (theID, icSigBlueTRCTag) != null)) {
- thisProfile = new ICC_ProfileRGB (theID);
+ else if ((getColorSpaceType (p) == ColorSpace.TYPE_RGB) &&
+ (getData (p, icSigMediaWhitePointTag) != null) &&
+ (getData (p, icSigRedColorantTag) != null) &&
+ (getData (p, icSigGreenColorantTag) != null) &&
+ (getData (p, icSigBlueColorantTag) != null) &&
+ (getData (p, icSigRedTRCTag) != null) &&
+ (getData (p, icSigGreenTRCTag) != null) &&
+ (getData (p, icSigBlueTRCTag) != null)) {
+ thisProfile = new ICC_ProfileRGB (p);
}
else {
- thisProfile = new ICC_Profile (theID);
+ thisProfile = new ICC_Profile (p);
}
} catch (CMMException c) {
- thisProfile = new ICC_Profile (theID);
+ thisProfile = new ICC_Profile (p);
}
return thisProfile;
}
@@ -1119,7 +1120,7 @@
fileName);
}
try {
- ID = CMSManager.getModule().loadProfile(profileData);
+ cmmProfile = CMSManager.getModule().loadProfile(profileData);
} catch (CMMException c) {
ProfileDataException pde = new
ProfileDataException("Invalid ICC Profile Data" + fileName);
@@ -1229,14 +1230,14 @@
causing a deferred profile
to be loaded */
}
- return getColorSpaceType(ID);
+ return getColorSpaceType(cmmProfile);
}
- static int getColorSpaceType(long profileID) {
+ static int getColorSpaceType(Profile p) {
byte[] theHeader;
int theColorSpaceSig, theColorSpace;
- theHeader = getData(profileID, icSigHead);
+ theHeader = getData(p, icSigHead);
theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
theColorSpace = iccCStoJCS (theColorSpaceSig);
return theColorSpace;
@@ -1258,15 +1259,15 @@
if (ProfileDeferralMgr.deferring) {
ProfileDeferralMgr.activateProfiles();
}
- return getPCSType(ID);
+ return getPCSType(cmmProfile);
}
- static int getPCSType(long profileID) {
+ static int getPCSType(Profile p) {
byte[] theHeader;
int thePCSSig, thePCS;
- theHeader = getData(profileID, icSigHead);
+ theHeader = getData(p, icSigHead);
thePCSSig = intFromBigEndian(theHeader, icHdrPcs);
thePCS = iccCStoJCS(thePCSSig);
return thePCS;
@@ -1326,12 +1327,12 @@
PCMM mdl = CMSManager.getModule();
/* get the number of bytes needed for this profile */
- profileSize = mdl.getProfileSize(ID);
+ profileSize = mdl.getProfileSize(cmmProfile);
profileData = new byte [profileSize];
/* get the data for the profile */
- mdl.getProfileData(ID, profileData);
+ mdl.getProfileData(cmmProfile, profileData);
return profileData;
}
@@ -1358,11 +1359,11 @@
ProfileDeferralMgr.activateProfiles();
}
- return getData(ID, tagSignature);
+ return getData(cmmProfile, tagSignature);
}
- static byte[] getData(long profileID, int tagSignature) {
+ static byte[] getData(Profile p, int tagSignature) {
int tagSize;
byte[] tagData;
@@ -1370,12 +1371,12 @@
PCMM mdl = CMSManager.getModule();
/* get the number of bytes needed for this tag */
- tagSize = mdl.getTagSize(profileID, tagSignature);
+ tagSize = mdl.getTagSize(p, tagSignature);
tagData = new byte[tagSize]; /* get an array for the tag */
/* get the tag's data */
- mdl.getTagData(profileID, tagSignature, tagData);
+ mdl.getTagData(p, tagSignature, tagData);
} catch(CMMException c) {
tagData = null;
}
@@ -1406,7 +1407,7 @@
ProfileDeferralMgr.activateProfiles();
}
- CMSManager.getModule().setTagData(ID, tagSignature, tagData);
+ CMSManager.getModule().setTagData(cmmProfile, tagSignature, tagData);
}
/**
--- a/jdk/src/share/classes/java/awt/color/ICC_ProfileGray.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/awt/color/ICC_ProfileGray.java Sat Sep 14 20:43:34 2013 +0100
@@ -35,7 +35,7 @@
package java.awt.color;
-import java.awt.image.LookupTable;
+import sun.java2d.cmm.Profile;
import sun.java2d.cmm.ProfileDeferralInfo;
/**
@@ -76,8 +76,8 @@
/**
* Constructs a new ICC_ProfileGray from a CMM ID.
*/
- ICC_ProfileGray(long ID) {
- super(ID);
+ ICC_ProfileGray(Profile p) {
+ super(p);
}
/**
--- a/jdk/src/share/classes/java/awt/color/ICC_ProfileRGB.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/awt/color/ICC_ProfileRGB.java Sat Sep 14 20:43:34 2013 +0100
@@ -35,7 +35,7 @@
package java.awt.color;
-import java.awt.image.LookupTable;
+import sun.java2d.cmm.Profile;
import sun.java2d.cmm.ProfileDeferralInfo;
/**
@@ -114,8 +114,8 @@
* @param ID The CMM ID for the profile.
*
*/
- ICC_ProfileRGB(long ID) {
- super(ID);
+ ICC_ProfileRGB(Profile p) {
+ super(p);
}
/**
--- a/jdk/src/share/classes/java/awt/event/InputEvent.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/awt/event/InputEvent.java Sat Sep 14 20:43:34 2013 +0100
@@ -33,6 +33,7 @@
import sun.awt.AWTAccessor;
import sun.util.logging.PlatformLogger;
+import sun.security.util.SecurityConstants;
/**
* The root event class for all component-level input events.
@@ -350,7 +351,7 @@
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
try {
- sm.checkSystemClipboardAccess();
+ sm.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
b = true;
} catch (SecurityException se) {
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
--- a/jdk/src/share/classes/java/io/Console.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/io/Console.java Sat Sep 14 20:43:34 2013 +0100
@@ -124,9 +124,11 @@
* {@link java.io.Reader#read(java.nio.CharBuffer) read(java.nio.CharBuffer)}
* on the returned object will not read in characters beyond the line
* bound for each invocation, even if the destination buffer has space for
- * more characters. A line bound is considered to be any one of a line feed
- * (<tt>'\n'</tt>), a carriage return (<tt>'\r'</tt>), a carriage return
- * followed immediately by a linefeed, or an end of stream.
+ * more characters. The {@code Reader}'s {@code read} methods may block if a
+ * line bound has not been entered or reached on the console's input device.
+ * A line bound is considered to be any one of a line feed (<tt>'\n'</tt>),
+ * a carriage return (<tt>'\r'</tt>), a carriage return followed immediately
+ * by a linefeed, or an end of stream.
*
* @return The reader associated with this console
*/
--- a/jdk/src/share/classes/java/lang/AutoCloseable.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/AutoCloseable.java Sat Sep 14 20:43:34 2013 +0100
@@ -26,7 +26,24 @@
package java.lang;
/**
- * A resource that must be closed when it is no longer needed.
+ * An object that may hold resources (such as file or socket handles)
+ * until it is closed. The {@link #close()} method of an {@code AutoCloseable}
+ * object is called automatically when exiting a {@code
+ * try}-with-resources block for which the object has been declared in
+ * the resource specification header. This construction ensures prompt
+ * release, avoiding resource exhaustion exceptions and errors that
+ * may otherwise occur.
+ *
+ * @apiNote
+ * <p>It is possible, and in fact common, for a base class to
+ * implement AutoCloseable even though not all of its subclasses or
+ * instances will hold releasable resources. For code that must operate
+ * in complete generality, or when it is known that the {@code AutoCloseable}
+ * instance requires resource release, it is recommended to use {@code
+ * try}-with-resources constructions. However, when using facilities such as
+ * {@link java.util.stream.Stream} that support both I/O-based and
+ * non-I/O-based forms, {@code try}-with-resources blocks are in
+ * general unnecessary when using non-I/O-based forms.
*
* @author Josh Bloch
* @since 1.7
--- a/jdk/src/share/classes/java/lang/Class.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/Class.java Sat Sep 14 20:43:34 2013 +0100
@@ -821,6 +821,10 @@
* <p> If this object represents a primitive type or void, the method
* returns an array of length 0.
*
+ * <p> If this {@code Class} object represents an array type, the
+ * interfaces {@code Cloneable} and {@code java.io.Serializable} are
+ * returned in that order.
+ *
* @return an array of interfaces implemented by this class.
*/
public Class<?>[] getInterfaces() {
@@ -1484,22 +1488,24 @@
/**
* Returns an array containing {@code Field} objects reflecting all
* the accessible public fields of the class or interface represented by
- * this {@code Class} object. The elements in the array returned are
- * not sorted and are not in any particular order. This method returns an
- * array of length 0 if the class or interface has no accessible public
- * fields, or if it represents an array class, a primitive type, or void.
+ * this {@code Class} object.
+ *
+ * <p> If this {@code Class} object represents a class or interface with no
+ * no accessible public fields, then this method returns an array of length
+ * 0.
+ *
+ * <p> If this {@code Class} object represents a class, then this method
+ * returns the public fields of the class and of all its superclasses.
*
- * <p> Specifically, if this {@code Class} object represents a class,
- * this method returns the public fields of this class and of all its
- * superclasses. If this {@code Class} object represents an
- * interface, this method returns the fields of this interface and of all
- * its superinterfaces.
+ * <p> If this {@code Class} object represents an interface, then this
+ * method returns the fields of the interface and of all its
+ * superinterfaces.
*
- * <p> The implicit length field for array class is not reflected by this
- * method. User code should use the methods of class {@code Array} to
- * manipulate arrays.
+ * <p> If this {@code Class} object represents an array type, a primitive
+ * type, or void, then this method returns an array of length 0.
*
- * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.3.
+ * <p> The elements in the returned array are not sorted and are not in any
+ * particular order.
*
* @return the array of {@code Field} objects representing the
* public fields
@@ -1512,6 +1518,8 @@
* of this class.
*
* @since JDK1.1
+ * @jls 8.2 Class Members
+ * @jls 8.3 Field Declarations
*/
@CallerSensitive
public Field[] getFields() throws SecurityException {
@@ -1521,23 +1529,33 @@
/**
- * Returns an array containing {@code Method} objects reflecting all
- * the public <em>member</em> methods of the class or interface represented
- * by this {@code Class} object, including those declared by the class
- * or interface and those inherited from superclasses and
- * superinterfaces. Array classes return all the (public) member methods
- * inherited from the {@code Object} class. The elements in the array
- * returned are not sorted and are not in any particular order. This
- * method returns an array of length 0 if this {@code Class} object
- * represents a class or interface that has no public member methods, or if
- * this {@code Class} object represents a primitive type or void.
+ * Returns an array containing {@code Method} objects reflecting all the
+ * public methods of the class or interface represented by this {@code
+ * Class} object, including those declared by the class or interface and
+ * those inherited from superclasses and superinterfaces.
+ *
+ * <p> If this {@code Class} object represents a type that has multiple
+ * public methods with the same name and parameter types, but different
+ * return types, then the returned array has a {@code Method} object for
+ * each such method.
+ *
+ * <p> If this {@code Class} object represents a type with a class
+ * initialization method {@code <clinit>}, then the returned array does
+ * <em>not</em> have a corresponding {@code Method} object.
*
- * <p> The class initialization method {@code <clinit>} is not
- * included in the returned array. If the class declares multiple public
- * member methods with the same parameter types, they are all included in
- * the returned array.
+ * <p> If this {@code Class} object represents an array type, then the
+ * returned array has a {@code Method} object for each of the public
+ * methods inherited by the array type from {@code Object}. It does not
+ * contain a {@code Method} object for {@code clone()}.
*
- * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.4.
+ * <p> If this {@code Class} object represents a class or interface with no
+ * public methods, then the returned array has length 0.
+ *
+ * <p> If this {@code Class} object represents a primitive type or void,
+ * then the returned array has length 0.
+ *
+ * <p> The elements in the returned array are not sorted and are not in any
+ * particular order.
*
* @return the array of {@code Method} objects representing the
* public methods of this class
@@ -1549,6 +1567,8 @@
* s.checkPackageAccess()} denies access to the package
* of this class.
*
+ * @jls 8.2 Class Members
+ * @jls 8.4 Method Declarations
* @since JDK1.1
*/
@CallerSensitive
@@ -1595,13 +1615,14 @@
/**
- * Returns a {@code Field} object that reflects the specified public
- * member field of the class or interface represented by this
- * {@code Class} object. The {@code name} parameter is a
- * {@code String} specifying the simple name of the desired field.
+ * Returns a {@code Field} object that reflects the specified public member
+ * field of the class or interface represented by this {@code Class}
+ * object. The {@code name} parameter is a {@code String} specifying the
+ * simple name of the desired field.
*
* <p> The field to be reflected is determined by the algorithm that
- * follows. Let C be the class represented by this object:
+ * follows. Let C be the class or interface represented by this object:
+ *
* <OL>
* <LI> If C declares a public field with the name specified, that is the
* field to be reflected.</LI>
@@ -1614,7 +1635,8 @@
* is thrown.</LI>
* </OL>
*
- * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.3.
+ * <p> If this {@code Class} object represents an array type, then this
+ * method does not find the {@code length} field of the array type.
*
* @param name the field name
* @return the {@code Field} object of this class specified by
@@ -1631,6 +1653,8 @@
* of this class.
*
* @since JDK1.1
+ * @jls 8.2 Class Members
+ * @jls 8.3 Field Declarations
*/
@CallerSensitive
public Field getField(String name)
@@ -1685,7 +1709,8 @@
* method and the method being overridden would have the same
* signature but different return types.
*
- * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.4.
+ * <p> If this {@code Class} object represents an array type, then this
+ * method does not find the {@code clone()} method.
*
* @param name the name of the method
* @param parameterTypes the list of parameters
@@ -1702,6 +1727,8 @@
* s.checkPackageAccess()} denies access to the package
* of this class.
*
+ * @jls 8.2 Class Members
+ * @jls 8.4 Method Declarations
* @since JDK1.1
*/
@CallerSensitive
@@ -1800,12 +1827,15 @@
* declared by the class or interface represented by this
* {@code Class} object. This includes public, protected, default
* (package) access, and private fields, but excludes inherited fields.
- * The elements in the array returned are not sorted and are not in any
- * particular order. This method returns an array of length 0 if the class
- * or interface declares no fields, or if this {@code Class} object
- * represents a primitive type, an array class, or void.
+ *
+ * <p> If this {@code Class} object represents a class or interface with no
+ * declared fields, then this method returns an array of length 0.
*
- * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.3.
+ * <p> If this {@code Class} object represents an array type, a primitive
+ * type, or void, then this method returns an array of length 0.
+ *
+ * <p> The elements in the returned array are not sorted and are not in any
+ * particular order.
*
* @return the array of {@code Field} objects representing all the
* declared fields of this class
@@ -1831,6 +1861,8 @@
* </ul>
*
* @since JDK1.1
+ * @jls 8.2 Class Members
+ * @jls 8.3 Field Declarations
*/
@CallerSensitive
public Field[] getDeclaredFields() throws SecurityException {
@@ -1840,20 +1872,29 @@
/**
- * Returns an array of {@code Method} objects reflecting all the
- * methods declared by the class or interface represented by this
- * {@code Class} object. This includes public, protected, default
- * (package) access, and private methods, but excludes inherited methods.
- * The elements in the array returned are not sorted and are not in any
- * particular order. This method returns an array of length 0 if the class
- * or interface declares no methods, or if this {@code Class} object
- * represents a primitive type, an array class, or void. The class
- * initialization method {@code <clinit>} is not included in the
- * returned array. If the class declares multiple public member methods
- * with the same parameter types, they are all included in the returned
- * array.
+ *
+ * Returns an array containing {@code Method} objects reflecting all the
+ * declared methods of the class or interface represented by this {@code
+ * Class} object, including public, protected, default (package)
+ * access, and private methods, but excluding inherited methods.
+ *
+ * <p> If this {@code Class} object represents a type that has multiple
+ * declared methods with the same name and parameter types, but different
+ * return types, then the returned array has a {@code Method} object for
+ * each such method.
*
- * <p> See <em>The Java Language Specification</em>, section 8.2.
+ * <p> If this {@code Class} object represents a type that has a class
+ * initialization method {@code <clinit>}, then the returned array does
+ * <em>not</em> have a corresponding {@code Method} object.
+ *
+ * <p> If this {@code Class} object represents a class or interface with no
+ * declared methods, then the returned array has length 0.
+ *
+ * <p> If this {@code Class} object represents an array type, a primitive
+ * type, or void, then the returned array has length 0.
+ *
+ * <p> The elements in the returned array are not sorted and are not in any
+ * particular order.
*
* @return the array of {@code Method} objects representing all the
* declared methods of this class
@@ -1878,6 +1919,8 @@
*
* </ul>
*
+ * @jls 8.2 Class Members
+ * @jls 8.4 Method Declarations
* @since JDK1.1
*/
@CallerSensitive
@@ -1935,9 +1978,11 @@
/**
* Returns a {@code Field} object that reflects the specified declared
* field of the class or interface represented by this {@code Class}
- * object. The {@code name} parameter is a {@code String} that
- * specifies the simple name of the desired field. Note that this method
- * will not reflect the {@code length} field of an array class.
+ * object. The {@code name} parameter is a {@code String} that specifies
+ * the simple name of the desired field.
+ *
+ * <p> If this {@code Class} object represents an array type, then this
+ * method does not find the {@code length} field of the array type.
*
* @param name the name of the field
* @return the {@code Field} object for the specified field in this
@@ -1967,6 +2012,8 @@
* </ul>
*
* @since JDK1.1
+ * @jls 8.2 Class Members
+ * @jls 8.3 Field Declarations
*/
@CallerSensitive
public Field getDeclaredField(String name)
@@ -1994,6 +2041,9 @@
* name is "<init>"or "<clinit>" a {@code NoSuchMethodException}
* is raised.
*
+ * <p> If this {@code Class} object represents an array type, then this
+ * method does not find the {@code clone()} method.
+ *
* @param name the name of the method
* @param parameterTypes the parameter array
* @return the {@code Method} object for the method of this class
@@ -2021,6 +2071,8 @@
*
* </ul>
*
+ * @jls 8.2 Class Members
+ * @jls 8.4 Method Declarations
* @since JDK1.1
*/
@CallerSensitive
--- a/jdk/src/share/classes/java/lang/Math.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/Math.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 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
@@ -646,7 +646,7 @@
/**
* Returns the closest {@code int} to the argument, with ties
- * rounding up.
+ * rounding to positive infinity.
*
* <p>
* Special cases:
@@ -665,15 +665,37 @@
* @see java.lang.Integer#MIN_VALUE
*/
public static int round(float a) {
- if (a != 0x1.fffffep-2f) // greatest float value less than 0.5
- return (int)floor(a + 0.5f);
- else
- return 0;
+ int intBits = Float.floatToRawIntBits(a);
+ int biasedExp = (intBits & FloatConsts.EXP_BIT_MASK)
+ >> (FloatConsts.SIGNIFICAND_WIDTH - 1);
+ int shift = (FloatConsts.SIGNIFICAND_WIDTH - 2
+ + FloatConsts.EXP_BIAS) - biasedExp;
+ if ((shift & -32) == 0) { // shift >= 0 && shift < 32
+ // a is a finite number such that pow(2,-32) <= ulp(a) < 1
+ int r = ((intBits & FloatConsts.SIGNIF_BIT_MASK)
+ | (FloatConsts.SIGNIF_BIT_MASK + 1));
+ if (intBits < 0) {
+ r = -r;
+ }
+ // In the comments below each Java expression evaluates to the value
+ // the corresponding mathematical expression:
+ // (r) evaluates to a / ulp(a)
+ // (r >> shift) evaluates to floor(a * 2)
+ // ((r >> shift) + 1) evaluates to floor((a + 1/2) * 2)
+ // (((r >> shift) + 1) >> 1) evaluates to floor(a + 1/2)
+ return ((r >> shift) + 1) >> 1;
+ } else {
+ // a is either
+ // - a finite number with abs(a) < exp(2,FloatConsts.SIGNIFICAND_WIDTH-32) < 1/2
+ // - a finite number with ulp(a) >= 1 and hence a is a mathematical integer
+ // - an infinity or NaN
+ return (int) a;
+ }
}
/**
* Returns the closest {@code long} to the argument, with ties
- * rounding up.
+ * rounding to positive infinity.
*
* <p>Special cases:
* <ul><li>If the argument is NaN, the result is 0.
@@ -692,10 +714,32 @@
* @see java.lang.Long#MIN_VALUE
*/
public static long round(double a) {
- if (a != 0x1.fffffffffffffp-2) // greatest double value less than 0.5
- return (long)floor(a + 0.5d);
- else
- return 0;
+ long longBits = Double.doubleToRawLongBits(a);
+ long biasedExp = (longBits & DoubleConsts.EXP_BIT_MASK)
+ >> (DoubleConsts.SIGNIFICAND_WIDTH - 1);
+ long shift = (DoubleConsts.SIGNIFICAND_WIDTH - 2
+ + DoubleConsts.EXP_BIAS) - biasedExp;
+ if ((shift & -64) == 0) { // shift >= 0 && shift < 64
+ // a is a finite number such that pow(2,-64) <= ulp(a) < 1
+ long r = ((longBits & DoubleConsts.SIGNIF_BIT_MASK)
+ | (DoubleConsts.SIGNIF_BIT_MASK + 1));
+ if (longBits < 0) {
+ r = -r;
+ }
+ // In the comments below each Java expression evaluates to the value
+ // the corresponding mathematical expression:
+ // (r) evaluates to a / ulp(a)
+ // (r >> shift) evaluates to floor(a * 2)
+ // ((r >> shift) + 1) evaluates to floor((a + 1/2) * 2)
+ // (((r >> shift) + 1) >> 1) evaluates to floor(a + 1/2)
+ return ((r >> shift) + 1) >> 1;
+ } else {
+ // a is either
+ // - a finite number with abs(a) < exp(2,DoubleConsts.SIGNIFICAND_WIDTH-64) < 1/2
+ // - a finite number with ulp(a) >= 1 and hence a is a mathematical integer
+ // - an infinity or NaN
+ return (long) a;
+ }
}
private static final class RandomNumberGeneratorHolder {
--- a/jdk/src/share/classes/java/lang/SecurityManager.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/SecurityManager.java Sat Sep 14 20:43:34 2013 +0100
@@ -1336,9 +1336,16 @@
* top-level windows; <code>false</code> otherwise.
* @exception NullPointerException if the <code>window</code> argument is
* <code>null</code>.
+ * @deprecated The dependency on {@code AWTPermission} creates an
+ * impediment to future modularization of the Java platform.
+ * Users of this method should instead invoke
+ * {@link #checkPermission} directly.
+ * This method will be changed in a future release to check
+ * the permission {@code java.security.AllPermission}.
* @see java.awt.Window
* @see #checkPermission(java.security.Permission) checkPermission
*/
+ @Deprecated
public boolean checkTopLevelWindow(Object window) {
if (window == null) {
throw new NullPointerException("window can't be null");
@@ -1398,8 +1405,15 @@
* @since JDK1.1
* @exception SecurityException if the calling thread does not have
* permission to access the system clipboard.
+ * @deprecated The dependency on {@code AWTPermission} creates an
+ * impediment to future modularization of the Java platform.
+ * Users of this method should instead invoke
+ * {@link #checkPermission} directly.
+ * This method will be changed in a future release to check
+ * the permission {@code java.security.AllPermission}.
* @see #checkPermission(java.security.Permission) checkPermission
*/
+ @Deprecated
public void checkSystemClipboardAccess() {
Permission perm = SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION;
if (perm == null) {
@@ -1427,8 +1441,15 @@
* @since JDK1.1
* @exception SecurityException if the calling thread does not have
* permission to access the AWT event queue.
+ * @deprecated The dependency on {@code AWTPermission} creates an
+ * impediment to future modularization of the Java platform.
+ * Users of this method should instead invoke
+ * {@link #checkPermission} directly.
+ * This method will be changed in a future release to check
+ * the permission {@code java.security.AllPermission}.
* @see #checkPermission(java.security.Permission) checkPermission
*/
+ @Deprecated
public void checkAwtEventQueueAccess() {
Permission perm = SecurityConstants.AWT.CHECK_AWT_EVENTQUEUE_PERMISSION;
if (perm == null) {
--- a/jdk/src/share/classes/java/lang/StrictMath.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/StrictMath.java Sat Sep 14 20:43:34 2013 +0100
@@ -633,7 +633,7 @@
/**
* Returns the closest {@code int} to the argument, with ties
- * rounding up.
+ * rounding to positive infinity.
*
* <p>Special cases:
* <ul><li>If the argument is NaN, the result is 0.
@@ -656,7 +656,7 @@
/**
* Returns the closest {@code long} to the argument, with ties
- * rounding up.
+ * rounding to positive infinity.
*
* <p>Special cases:
* <ul><li>If the argument is NaN, the result is 0.
--- a/jdk/src/share/classes/java/lang/String.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/String.java Sat Sep 14 20:43:34 2013 +0100
@@ -2457,8 +2457,8 @@
* String message = String.join(" ", strings);
* //message returned is: "Java is cool"
*
- * Set<String> strings = new HashSet<>();
- * Strings.add("Java"); strings.add("is");
+ * Set<String> strings = new LinkedHashSet<>();
+ * strings.add("Java"); strings.add("is");
* strings.add("very"); strings.add("cool");
* String message = String.join("-", strings);
* //message returned is: "Java-is-very-cool"
@@ -2652,7 +2652,7 @@
* returns {@code "t\u005Cu0131tle"}, where '\u005Cu0131' is the
* LATIN SMALL LETTER DOTLESS I character.
* To obtain correct results for locale insensitive strings, use
- * {@code toLowerCase(Locale.ENGLISH)}.
+ * {@code toLowerCase(Locale.ROOT)}.
* <p>
* @return the {@code String}, converted to lowercase.
* @see java.lang.String#toLowerCase(Locale)
@@ -2815,7 +2815,7 @@
* returns {@code "T\u005Cu0130TLE"}, where '\u005Cu0130' is the
* LATIN CAPITAL LETTER I WITH DOT ABOVE character.
* To obtain correct results for locale insensitive strings, use
- * {@code toUpperCase(Locale.ENGLISH)}.
+ * {@code toUpperCase(Locale.ROOT)}.
* <p>
* @return the {@code String}, converted to uppercase.
* @see java.lang.String#toUpperCase(Locale)
--- a/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Sat Sep 14 20:43:34 2013 +0100
@@ -124,7 +124,7 @@
this.samMethodType = samMethodType;
this.implMethod = implMethod;
- this.implInfo = new MethodHandleInfo(implMethod);
+ this.implInfo = caller.revealDirect(implMethod);
// @@@ Temporary work-around pending resolution of 8005119
this.implKind = (implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeSpecial)
? MethodHandleInfo.REF_invokeVirtual
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/lang/invoke/InfoFromMemberName.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,145 @@
+/*
+ * 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. 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.lang.invoke;
+
+import java.security.*;
+import java.lang.reflect.*;
+import java.lang.invoke.MethodHandleNatives.Constants;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/*
+ * Auxiliary to MethodHandleInfo, wants to nest in MethodHandleInfo but must be non-public.
+ */
+/*non-public*/
+final
+class InfoFromMemberName implements MethodHandleInfo {
+ private final MemberName member;
+ private final int referenceKind;
+
+ InfoFromMemberName(Lookup lookup, MemberName member, byte referenceKind) {
+ assert(member.isResolved() || member.isMethodHandleInvoke());
+ assert(member.referenceKindIsConsistentWith(referenceKind));
+ this.member = member;
+ this.referenceKind = referenceKind;
+ }
+
+ @Override
+ public Class<?> getDeclaringClass() {
+ return member.getDeclaringClass();
+ }
+
+ @Override
+ public String getName() {
+ return member.getName();
+ }
+
+ @Override
+ public MethodType getMethodType() {
+ return member.getMethodOrFieldType();
+ }
+
+ @Override
+ public int getModifiers() {
+ return member.getModifiers();
+ }
+
+ @Override
+ public int getReferenceKind() {
+ return referenceKind;
+ }
+
+ @Override
+ public String toString() {
+ return MethodHandleInfo.toString(getReferenceKind(), getDeclaringClass(), getName(), getMethodType());
+ }
+
+ @Override
+ public <T extends Member> T reflectAs(Class<T> expected, Lookup lookup) {
+ if (member.isMethodHandleInvoke() && !member.isVarargs()) {
+ // This member is an instance of a signature-polymorphic method, which cannot be reflected
+ // A method handle invoker can come in either of two forms:
+ // A generic placeholder (present in the source code, and varargs)
+ // and a signature-polymorphic instance (synthetic and not varargs).
+ // For more information see comments on {@link MethodHandleNatives#linkMethod}.
+ throw new IllegalArgumentException("cannot reflect signature polymorphic method");
+ }
+ Member mem = AccessController.doPrivileged(new PrivilegedAction<Member>() {
+ public Member run() {
+ try {
+ return reflectUnchecked();
+ } catch (ReflectiveOperationException ex) {
+ throw new IllegalArgumentException(ex);
+ }
+ }
+ });
+ try {
+ Class<?> defc = getDeclaringClass();
+ byte refKind = (byte) getReferenceKind();
+ lookup.checkAccess(refKind, defc, convertToMemberName(refKind, mem));
+ } catch (IllegalAccessException ex) {
+ throw new IllegalArgumentException(ex);
+ }
+ return expected.cast(mem);
+ }
+
+ private Member reflectUnchecked() throws ReflectiveOperationException {
+ byte refKind = (byte) getReferenceKind();
+ Class<?> defc = getDeclaringClass();
+ boolean isPublic = Modifier.isPublic(getModifiers());
+ if (MethodHandleNatives.refKindIsMethod(refKind)) {
+ if (isPublic)
+ return defc.getMethod(getName(), getMethodType().parameterArray());
+ else
+ return defc.getDeclaredMethod(getName(), getMethodType().parameterArray());
+ } else if (MethodHandleNatives.refKindIsConstructor(refKind)) {
+ if (isPublic)
+ return defc.getConstructor(getMethodType().parameterArray());
+ else
+ return defc.getDeclaredConstructor(getMethodType().parameterArray());
+ } else if (MethodHandleNatives.refKindIsField(refKind)) {
+ if (isPublic)
+ return defc.getField(getName());
+ else
+ return defc.getDeclaredField(getName());
+ } else {
+ throw new IllegalArgumentException("referenceKind="+refKind);
+ }
+ }
+
+ private static MemberName convertToMemberName(byte refKind, Member mem) throws IllegalAccessException {
+ if (mem instanceof Method) {
+ boolean wantSpecial = (refKind == REF_invokeSpecial);
+ return new MemberName((Method) mem, wantSpecial);
+ } else if (mem instanceof Constructor) {
+ return new MemberName((Constructor) mem);
+ } else if (mem instanceof Field) {
+ boolean isSetter = (refKind == REF_putField || refKind == REF_putStatic);
+ return new MemberName((Field) mem, isSetter);
+ }
+ throw new InternalError(mem.getClass().getName());
+ }
+}
--- a/jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Sat Sep 14 20:43:34 2013 +0100
@@ -612,6 +612,12 @@
return false; // inner class of some sort
if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
return false; // not on BCP
+ MethodType mtype = member.getMethodOrFieldType();
+ if (!isStaticallyNameable(mtype.returnType()))
+ return false;
+ for (Class<?> ptype : mtype.parameterArray())
+ if (!isStaticallyNameable(ptype))
+ return false;
if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls))
return true; // in java.lang.invoke package
if (member.isPublic() && isStaticallyNameable(cls))
--- a/jdk/src/share/classes/java/lang/invoke/Invokers.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/Invokers.java Sat Sep 14 20:43:34 2013 +0100
@@ -87,6 +87,7 @@
lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_INVOKER);
invoker = SimpleMethodHandle.make(invokerType, lform);
}
+ invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invokeExact", mtype));
assert(checkInvoker(invoker));
exactInvoker = invoker;
return invoker;
@@ -110,6 +111,7 @@
lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_INVOKER);
invoker = SimpleMethodHandle.make(invokerType, lform);
}
+ invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invoke", mtype));
assert(checkInvoker(invoker));
generalInvoker = invoker;
return invoker;
--- a/jdk/src/share/classes/java/lang/invoke/MemberName.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/MemberName.java Sat Sep 14 20:43:34 2013 +0100
@@ -320,14 +320,18 @@
/** Utility method to query if this member is a method handle invocation (invoke or invokeExact). */
public boolean isMethodHandleInvoke() {
- final int bits = Modifier.NATIVE | Modifier.FINAL;
+ final int bits = MH_INVOKE_MODS;
final int negs = Modifier.STATIC;
if (testFlags(bits | negs, bits) &&
clazz == MethodHandle.class) {
- return name.equals("invoke") || name.equals("invokeExact");
+ return isMethodHandleInvokeName(name);
}
return false;
}
+ public static boolean isMethodHandleInvokeName(String name) {
+ return name.equals("invoke") || name.equals("invokeExact");
+ }
+ private static final int MH_INVOKE_MODS = Modifier.NATIVE | Modifier.FINAL | Modifier.PUBLIC;
/** Utility method to query the modifier flags of this member. */
public boolean isStatic() {
@@ -482,12 +486,27 @@
m.getClass(); // NPE check
// fill in vmtarget, vmindex while we have m in hand:
MethodHandleNatives.init(this, m);
+ if (clazz == null) { // MHN.init failed
+ if (m.getDeclaringClass() == MethodHandle.class &&
+ isMethodHandleInvokeName(m.getName())) {
+ // The JVM did not reify this signature-polymorphic instance.
+ // Need a special case here.
+ // See comments on MethodHandleNatives.linkMethod.
+ MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes());
+ int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual);
+ init(MethodHandle.class, m.getName(), type, flags);
+ if (isMethodHandleInvoke())
+ return;
+ }
+ throw new LinkageError(m.toString());
+ }
assert(isResolved() && this.clazz != null);
this.name = m.getName();
if (this.type == null)
this.type = new Object[] { m.getReturnType(), m.getParameterTypes() };
if (wantSpecial) {
- assert(!isAbstract()) : this;
+ if (isAbstract())
+ throw new AbstractMethodError(this.toString());
if (getReferenceKind() == REF_invokeVirtual)
changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
else if (getReferenceKind() == REF_invokeInterface)
@@ -562,6 +581,22 @@
initResolved(true);
}
+ /**
+ * Create a name for a signature-polymorphic invoker.
+ * This is a placeholder for a signature-polymorphic instance
+ * (of MH.invokeExact, etc.) that the JVM does not reify.
+ * See comments on {@link MethodHandleNatives#linkMethod}.
+ */
+ static MemberName makeMethodHandleInvoke(String name, MethodType type) {
+ return makeMethodHandleInvoke(name, type, MH_INVOKE_MODS | SYNTHETIC);
+ }
+ static MemberName makeMethodHandleInvoke(String name, MethodType type, int mods) {
+ MemberName mem = new MemberName(MethodHandle.class, name, type, REF_invokeVirtual);
+ mem.flags |= mods; // it's not resolved, but add these modifiers anyway
+ assert(mem.isMethodHandleInvoke()) : mem;
+ return mem;
+ }
+
// bare-bones constructor; the JVM will fill it in
MemberName() { }
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandle.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandle.java Sat Sep 14 20:43:34 2013 +0100
@@ -1285,6 +1285,21 @@
}
/*non-public*/
+ MethodHandle withInternalMemberName(MemberName member) {
+ if (member != null) {
+ return MethodHandleImpl.makeWrappedMember(this, member);
+ } else if (internalMemberName() == null) {
+ // The required internaMemberName is null, and this MH (like most) doesn't have one.
+ return this;
+ } else {
+ // The following case is rare. Mask the internalMemberName by wrapping the MH in a BMH.
+ MethodHandle result = rebind();
+ assert (result.internalMemberName() == null);
+ return result;
+ }
+ }
+
+ /*non-public*/
boolean isInvokeSpecial() {
return false; // DMH.Special returns true
}
@@ -1356,7 +1371,7 @@
MethodHandle rebind() {
// Bind 'this' into a new invoker, of the known class BMH.
MethodType type2 = type();
- LambdaForm form2 = reinvokerForm(type2.basicType());
+ LambdaForm form2 = reinvokerForm(this);
// form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }
return BoundMethodHandle.bindSingle(type2, form2, this);
}
@@ -1369,23 +1384,38 @@
/** Create a LF which simply reinvokes a target of the given basic type.
* The target MH must override {@link #reinvokerTarget} to provide the target.
*/
- static LambdaForm reinvokerForm(MethodType mtype) {
- mtype = mtype.basicType();
+ static LambdaForm reinvokerForm(MethodHandle target) {
+ MethodType mtype = target.type().basicType();
LambdaForm reinvoker = mtype.form().cachedLambdaForm(MethodTypeForm.LF_REINVOKE);
if (reinvoker != null) return reinvoker;
- MethodHandle MH_invokeBasic = MethodHandles.basicInvoker(mtype);
+ if (mtype.parameterSlotCount() >= MethodType.MAX_MH_ARITY)
+ return makeReinvokerForm(target.type(), target); // cannot cache this
+ reinvoker = makeReinvokerForm(mtype, null);
+ return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, reinvoker);
+ }
+ private static LambdaForm makeReinvokerForm(MethodType mtype, MethodHandle customTargetOrNull) {
+ boolean customized = (customTargetOrNull != null);
+ MethodHandle MH_invokeBasic = customized ? null : MethodHandles.basicInvoker(mtype);
final int THIS_BMH = 0;
final int ARG_BASE = 1;
final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
int nameCursor = ARG_LIMIT;
- final int NEXT_MH = nameCursor++;
+ final int NEXT_MH = customized ? -1 : nameCursor++;
final int REINVOKE = nameCursor++;
LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
- names[NEXT_MH] = new LambdaForm.Name(NF_reinvokerTarget, names[THIS_BMH]);
- Object[] targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class);
- targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH
- names[REINVOKE] = new LambdaForm.Name(MH_invokeBasic, targetArgs);
- return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, new LambdaForm("BMH.reinvoke", ARG_LIMIT, names));
+ Object[] targetArgs;
+ MethodHandle targetMH;
+ if (customized) {
+ targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class);
+ targetMH = customTargetOrNull;
+ } else {
+ names[NEXT_MH] = new LambdaForm.Name(NF_reinvokerTarget, names[THIS_BMH]);
+ targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class);
+ targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH
+ targetMH = MethodHandles.basicInvoker(mtype);
+ }
+ names[REINVOKE] = new LambdaForm.Name(targetMH, targetArgs);
+ return new LambdaForm("BMH.reinvoke", ARG_LIMIT, names);
}
private static final LambdaForm.NamedFunction NF_reinvokerTarget;
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java Sat Sep 14 20:43:34 2013 +0100
@@ -317,7 +317,7 @@
private MethodHandle cache;
AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
- super(type, reinvokerForm(type));
+ super(type, reinvokerForm(target));
this.target = target;
this.arrayType = arrayType;
this.cache = target.asCollector(arrayType, 0);
@@ -778,16 +778,27 @@
}
static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
- static MethodHandle FAKE_METHOD_HANDLE_INVOKE;
- static
- MethodHandle fakeMethodHandleInvoke(MemberName method) {
- MethodType type = method.getInvocationType();
- assert(type.equals(MethodType.methodType(Object.class, Object[].class)));
- MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE;
+ static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
+ static MethodHandle fakeMethodHandleInvoke(MemberName method) {
+ int idx;
+ assert(method.isMethodHandleInvoke());
+ switch (method.getName()) {
+ case "invoke": idx = 0; break;
+ case "invokeExact": idx = 1; break;
+ default: throw new InternalError(method.getName());
+ }
+ MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx];
if (mh != null) return mh;
- mh = throwException(type.insertParameterTypes(0, UnsupportedOperationException.class));
+ MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class,
+ MethodHandle.class, Object[].class);
+ mh = throwException(type);
mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle"));
- FAKE_METHOD_HANDLE_INVOKE = mh;
+ if (!method.getInvocationType().equals(mh.type()))
+ throw new InternalError(method.toString());
+ mh = mh.withInternalMemberName(method);
+ mh = mh.asVarargsCollector(Object[].class);
+ assert(method.isVarargs());
+ FAKE_METHOD_HANDLE_INVOKE[idx] = mh;
return mh;
}
@@ -821,7 +832,7 @@
MethodHandle vamh = prepareForInvoker(mh);
// Cache the result of makeInjectedInvoker once per argument class.
MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
- return restoreToType(bccInvoker.bindTo(vamh), mh.type());
+ return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName());
}
private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
@@ -876,8 +887,11 @@
}
// Undo the adapter effect of prepareForInvoker:
- private static MethodHandle restoreToType(MethodHandle vamh, MethodType type) {
- return vamh.asCollector(Object[].class, type.parameterCount()).asType(type);
+ private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, MemberName member) {
+ MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount());
+ mh = mh.asType(type);
+ mh = mh.withInternalMemberName(member);
+ return mh;
}
private static final MethodHandle MH_checkCallerClass;
@@ -939,4 +953,41 @@
}
}
}
+
+
+ /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */
+ static class WrappedMember extends MethodHandle {
+ private final MethodHandle target;
+ private final MemberName member;
+
+ private WrappedMember(MethodHandle target, MethodType type, MemberName member) {
+ super(type, reinvokerForm(target));
+ this.target = target;
+ this.member = member;
+ }
+
+ @Override
+ MethodHandle reinvokerTarget() {
+ return target;
+ }
+ @Override
+ MemberName internalMemberName() {
+ return member;
+ }
+ @Override
+ boolean isInvokeSpecial() {
+ return target.isInvokeSpecial();
+ }
+ @Override
+ MethodHandle viewAsType(MethodType newType) {
+ return new WrappedMember(target, newType, member);
+ }
+ }
+
+ static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) {
+ if (member.equals(target.internalMemberName()))
+ return target;
+ return new WrappedMember(target, target.type(), member);
+ }
+
}
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java Sat Sep 14 20:43:34 2013 +0100
@@ -24,80 +24,246 @@
*/
package java.lang.invoke;
+
+import java.lang.reflect.*;
+import java.util.*;
import java.lang.invoke.MethodHandleNatives.Constants;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandleStatics.*;
/**
- * Cracking (reflecting) method handles back into their constituent symbolic parts.
+ * A symbolic reference obtained by cracking a method handle into its consitutent symbolic parts.
+ * To crack a direct method handle, call {@link Lookup#revealDirect Lookup.revealDirect}.
+ * <p>
+ * A <em>direct method handle</em> represents a method, constructor, or field without
+ * any intervening argument bindings or other transformations.
+ * The method, constructor, or field referred to by a direct method handle is called
+ * its <em>underlying member</em>.
+ * Direct method handles may be obtained in any of these ways:
+ * <ul>
+ * <li>By executing an {@code ldc} instruction on a {@code CONSTANT_MethodHandle} constant.
+ * (See the Java Virtual Machine Specification, sections 4.4.8 and 5.4.3.)
+ * <li>By calling one of the <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>,
+ * such as {@link Lookup#findVirtual Lookup.findVirtual},
+ * to resolve a symbolic reference into a method handle.
+ * A symbolic reference consists of a class, name string, and type.
+ * <li>By calling the factory method {@link Lookup#unreflect Lookup.unreflect}
+ * or {@link Lookup#unreflectSpecial Lookup.unreflectSpecial}
+ * to convert a {@link Method} into a method handle.
+ * <li>By calling the factory method {@link Lookup#unreflectConstructor Lookup.unreflectConstructor}
+ * to convert a {@link Constructor} into a method handle.
+ * <li>By calling the factory method {@link Lookup#unreflectGetter Lookup.unreflectGetter}
+ * or {@link Lookup#unreflectSetter Lookup.unreflectSetter}
+ * to convert a {@link Field} into a method handle.
+ * </ul>
+ * In all of these cases, it is possible to crack the resulting direct method handle
+ * to recover a symbolic reference for the underlying method, constructor, or field.
+ * Cracking must be done via a {@code Lookup} object equivalent to that which created
+ * the target method handle, or which has enough access permissions to recreate
+ * an equivalent method handle.
*
+ * <h1><a name="refkinds"></a>Reference kinds</h1>
+ * The <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>
+ * correspond to all major use cases for methods, constructors, and fields.
+ * These use cases may be distinguished using small integers as follows:
+ * <table border=1 cellpadding=5 summary="reference kinds">
+ * <tr><th>reference kind</th><th>descriptive name</th><th>scope</th><th>member</th><th>behavior</th></tr>
+ * <tr>
+ * <td>{@code 1}</td><td>{@code REF_getField}</td><td>{@code class}</td>
+ * <td>{@code FT f;}</td><td>{@code (T) this.f;}</td>
+ * </tr>
+ * <tr>
+ * <td>{@code 2}</td><td>{@code REF_getStatic}</td><td>{@code class} or {@code interface}</td>
+ * <td>{@code static}<br>{@code FT f;}</td><td>{@code (T) C.f;}</td>
+ * </tr>
+ * <tr>
+ * <td>{@code 3}</td><td>{@code REF_putField}</td><td>{@code class}</td>
+ * <td>{@code FT f;}</td><td>{@code this.f = x;}</td>
+ * </tr>
+ * <tr>
+ * <td>{@code 4}</td><td>{@code REF_putStatic}</td><td>{@code class}</td>
+ * <td>{@code static}<br>{@code FT f;}</td><td>{@code C.f = arg;}</td>
+ * </tr>
+ * <tr>
+ * <td>{@code 5}</td><td>{@code REF_invokeVirtual}</td><td>{@code class}</td>
+ * <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@code 6}</td><td>{@code REF_invokeStatic}</td><td>{@code class} or {@code interface}</td>
+ * <td>{@code static}<br>{@code T m(A*);}</td><td>{@code (T) C.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@code 7}</td><td>{@code REF_invokeSpecial}</td><td>{@code class} or {@code interface}</td>
+ * <td>{@code T m(A*);}</td><td>{@code (T) super.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@code 8}</td><td>{@code REF_newInvokeSpecial}</td><td>{@code class}</td>
+ * <td>{@code C(A*);}</td><td>{@code new C(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@code 9}</td><td>{@code REF_invokeInterface}</td><td>{@code interface}</td>
+ * <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
+ * </tr>
+ * </table>
+ * @since 1.8
*/
-final class MethodHandleInfo {
- public static final int
- REF_getField = Constants.REF_getField,
- REF_getStatic = Constants.REF_getStatic,
- REF_putField = Constants.REF_putField,
- REF_putStatic = Constants.REF_putStatic,
- REF_invokeVirtual = Constants.REF_invokeVirtual,
- REF_invokeStatic = Constants.REF_invokeStatic,
- REF_invokeSpecial = Constants.REF_invokeSpecial,
- REF_newInvokeSpecial = Constants.REF_newInvokeSpecial,
- REF_invokeInterface = Constants.REF_invokeInterface;
-
- private final Class<?> declaringClass;
- private final String name;
- private final MethodType methodType;
- private final int referenceKind;
-
- public MethodHandleInfo(MethodHandle mh) {
- MemberName mn = mh.internalMemberName();
- if (mn == null) throw new IllegalArgumentException("not a direct method handle");
- this.declaringClass = mn.getDeclaringClass();
- this.name = mn.getName();
- this.methodType = mn.getMethodOrFieldType();
- byte refKind = mn.getReferenceKind();
- if (refKind == REF_invokeSpecial && !mh.isInvokeSpecial())
- // Devirtualized method invocation is usually formally virtual.
- refKind = REF_invokeVirtual;
- this.referenceKind = refKind;
- }
+public
+interface MethodHandleInfo {
+ /**
+ * A direct method handle reference kind,
+ * as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
+ */
+ public static final int
+ REF_getField = Constants.REF_getField,
+ REF_getStatic = Constants.REF_getStatic,
+ REF_putField = Constants.REF_putField,
+ REF_putStatic = Constants.REF_putStatic,
+ REF_invokeVirtual = Constants.REF_invokeVirtual,
+ REF_invokeStatic = Constants.REF_invokeStatic,
+ REF_invokeSpecial = Constants.REF_invokeSpecial,
+ REF_newInvokeSpecial = Constants.REF_newInvokeSpecial,
+ REF_invokeInterface = Constants.REF_invokeInterface;
- public Class<?> getDeclaringClass() {
- return declaringClass;
- }
+ /**
+ * Returns the reference kind of the cracked method handle, which in turn
+ * determines whether the method handle's underlying member was a constructor, method, or field.
+ * See the <a href="MethodHandleInfo.html#refkinds">table above</a> for definitions.
+ * @return the integer code for the kind of reference used to access the underlying member
+ */
+ public int getReferenceKind();
- public String getName() {
- return name;
- }
+ /**
+ * Returns the class in which the cracked method handle's underlying member was defined.
+ * @return the declaring class of the underlying member
+ */
+ public Class<?> getDeclaringClass();
+
+ /**
+ * Returns the name of the cracked method handle's underlying member.
+ * This is {@code "<init>"} if the underlying member was a constructor,
+ * else it is a simple method name or field name.
+ * @return the simple name of the underlying member
+ */
+ public String getName();
- public MethodType getMethodType() {
- return methodType;
- }
+ /**
+ * Returns the nominal type of the cracked symbolic reference, expressed as a method type.
+ * If the reference is to a constructor, the return type will be {@code void}.
+ * If it is to a non-static method, the method type will not mention the {@code this} parameter.
+ * If it is to a field and the requested access is to read the field,
+ * the method type will have no parameters and return the field type.
+ * If it is to a field and the requested access is to write the field,
+ * the method type will have one parameter of the field type and return {@code void}.
+ * <p>
+ * Note that original direct method handle may include a leading {@code this} parameter,
+ * or (in the case of a constructor) will replace the {@code void} return type
+ * with the constructed class.
+ * The nominal type does not include any {@code this} parameter,
+ * and (in the case of a constructor) will return {@code void}.
+ * @return the type of the underlying member, expressed as a method type
+ */
+ public MethodType getMethodType();
- public int getModifiers() {
- return -1; //TODO
- }
+ // Utility methods.
+ // NOTE: class/name/type and reference kind constitute a symbolic reference
+ // member and modifiers are an add-on, derived from Core Reflection (or the equivalent)
- public int getReferenceKind() {
- return referenceKind;
- }
+ /**
+ * Reflects the underlying member as a method, constructor, or field object.
+ * If the underlying member is public, it is reflected as if by
+ * {@code getMethod}, {@code getConstructor}, or {@code getField}.
+ * Otherwise, it is reflected as if by
+ * {@code getDeclaredMethod}, {@code getDeclaredConstructor}, or {@code getDeclaredField}.
+ * The underlying member must be accessible to the given lookup object.
+ * @param <T> the desired type of the result, either {@link Member} or a subtype
+ * @param expected a class object representing the desired result type {@code T}
+ * @param lookup the lookup object that created this MethodHandleInfo, or one with equivalent access privileges
+ * @return a reference to the method, constructor, or field object
+ * @exception ClassCastException if the member is not of the expected type
+ * @exception NullPointerException if either argument is {@code null}
+ * @exception IllegalArgumentException if the underlying member is not accessible to the given lookup object
+ */
+ public <T extends Member> T reflectAs(Class<T> expected, Lookup lookup);
- static String getReferenceKindString(int referenceKind) {
- switch (referenceKind) {
- case REF_getField: return "getfield";
- case REF_getStatic: return "getstatic";
- case REF_putField: return "putfield";
- case REF_putStatic: return "putstatic";
- case REF_invokeVirtual: return "invokevirtual";
- case REF_invokeStatic: return "invokestatic";
- case REF_invokeSpecial: return "invokespecial";
- case REF_newInvokeSpecial: return "newinvokespecial";
- case REF_invokeInterface: return "invokeinterface";
- default: return "UNKNOWN_REFENCE_KIND" + "[" + referenceKind + "]";
- }
+ /**
+ * Returns the access modifiers of the underlying member.
+ * @return the Java language modifiers for underlying member,
+ * or -1 if the member cannot be accessed
+ * @see Modifier
+ * @see reflectAs
+ */
+ public int getModifiers();
+
+ /**
+ * Determines if the underlying member was a variable arity method or constructor.
+ * Such members are represented by method handles that are varargs collectors.
+ * @implSpec
+ * This produces a result equivalent to:
+ * <pre>{@code
+ * getReferenceKind() >= REF_invokeVirtual && Modifier.isTransient(getModifiers())
+ * }</pre>
+ *
+ *
+ * @return {@code true} if and only if the underlying member was declared with variable arity.
+ */
+ // spelling derived from java.lang.reflect.Executable, not MethodHandle.isVarargsCollector
+ public default boolean isVarArgs() {
+ // fields are never varargs:
+ if (MethodHandleNatives.refKindIsField((byte) getReferenceKind()))
+ return false;
+ // not in the public API: Modifier.VARARGS
+ final int ACC_VARARGS = 0x00000080; // from JVMS 4.6 (Table 4.20)
+ assert(ACC_VARARGS == Modifier.TRANSIENT);
+ return Modifier.isTransient(getModifiers());
}
- @Override
- public String toString() {
- return String.format("%s %s.%s:%s", getReferenceKindString(referenceKind),
- declaringClass.getName(), name, methodType);
+ /**
+ * Returns the descriptive name of the given reference kind,
+ * as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
+ * The conventional prefix "REF_" is omitted.
+ * @param referenceKind an integer code for a kind of reference used to access a class member
+ * @return a mixed-case string such as {@code "getField"}
+ * @exception IllegalArgumentException if the argument is not a valid
+ * <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
+ */
+ public static String referenceKindToString(int referenceKind) {
+ if (!MethodHandleNatives.refKindIsValid(referenceKind))
+ throw newIllegalArgumentException("invalid reference kind", referenceKind);
+ return MethodHandleNatives.refKindName((byte)referenceKind);
+ }
+
+ /**
+ * Returns a string representation for a {@code MethodHandleInfo},
+ * given the four parts of its symbolic reference.
+ * This is defined to be of the form {@code "RK C.N:MT"}, where {@code RK} is the
+ * {@linkplain #referenceKindToString reference kind string} for {@code kind},
+ * {@code C} is the {@linkplain java.lang.Class#getName name} of {@code defc}
+ * {@code N} is the {@code name}, and
+ * {@code MT} is the {@code type}.
+ * These four values may be obtained from the
+ * {@linkplain #getReferenceKind reference kind},
+ * {@linkplain #getDeclaringClass declaring class},
+ * {@linkplain #getName member name},
+ * and {@linkplain #getMethodType method type}
+ * of a {@code MethodHandleInfo} object.
+ *
+ * @implSpec
+ * This produces a result equivalent to:
+ * <pre>{@code
+ * String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type)
+ * }</pre>
+ *
+ * @param kind the {@linkplain #getReferenceKind reference kind} part of the symbolic reference
+ * @param defc the {@linkplain #getDeclaringClass declaring class} part of the symbolic reference
+ * @param name the {@linkplain #getName member name} part of the symbolic reference
+ * @param type the {@linkplain #getMethodType method type} part of the symbolic reference
+ * @return a string of the form {@code "RK C.N:MT"}
+ * @exception IllegalArgumentException if the first argument is not a valid
+ * <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
+ * @exception NullPointerException if any reference argument is {@code null}
+ */
+ public static String toString(int kind, Class<?> defc, String name, MethodType type) {
+ Objects.requireNonNull(name); Objects.requireNonNull(type);
+ return String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type);
}
}
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java Sat Sep 14 20:43:34 2013 +0100
@@ -205,6 +205,9 @@
static boolean refKindIsMethod(byte refKind) {
return !refKindIsField(refKind) && (refKind != REF_newInvokeSpecial);
}
+ static boolean refKindIsConstructor(byte refKind) {
+ return (refKind == REF_newInvokeSpecial);
+ }
static boolean refKindHasReceiver(byte refKind) {
assert(refKindIsValid(refKind));
return (refKind & 1) != 0;
@@ -313,7 +316,65 @@
* The method assumes the following arguments on the stack:
* 0: the method handle being invoked
* 1-N: the arguments to the method handle invocation
- * N+1: an implicitly added type argument (the given MethodType)
+ * N+1: an optional, implicitly added argument (typically the given MethodType)
+ * <p>
+ * The nominal method at such a call site is an instance of
+ * a signature-polymorphic method (see @PolymorphicSignature).
+ * Such method instances are user-visible entities which are
+ * "split" from the generic placeholder method in {@code MethodHandle}.
+ * (Note that the placeholder method is not identical with any of
+ * its instances. If invoked reflectively, is guaranteed to throw an
+ * {@code UnsupportedOperationException}.)
+ * If the signature-polymorphic method instance is ever reified,
+ * it appears as a "copy" of the original placeholder
+ * (a native final member of {@code MethodHandle}) except
+ * that its type descriptor has shape required by the instance,
+ * and the method instance is <em>not</em> varargs.
+ * The method instance is also marked synthetic, since the
+ * method (by definition) does not appear in Java source code.
+ * <p>
+ * The JVM is allowed to reify this method as instance metadata.
+ * For example, {@code invokeBasic} is always reified.
+ * But the JVM may instead call {@code linkMethod}.
+ * If the result is an * ordered pair of a {@code (method, appendix)},
+ * the method gets all the arguments (0..N inclusive)
+ * plus the appendix (N+1), and uses the appendix to complete the call.
+ * In this way, one reusable method (called a "linker method")
+ * can perform the function of any number of polymorphic instance
+ * methods.
+ * <p>
+ * Linker methods are allowed to be weakly typed, with any or
+ * all references rewritten to {@code Object} and any primitives
+ * (except {@code long}/{@code float}/{@code double})
+ * rewritten to {@code int}.
+ * A linker method is trusted to return a strongly typed result,
+ * according to the specific method type descriptor of the
+ * signature-polymorphic instance it is emulating.
+ * This can involve (as necessary) a dynamic check using
+ * data extracted from the appendix argument.
+ * <p>
+ * The JVM does not inspect the appendix, other than to pass
+ * it verbatim to the linker method at every call.
+ * This means that the JDK runtime has wide latitude
+ * for choosing the shape of each linker method and its
+ * corresponding appendix.
+ * Linker methods should be generated from {@code LambdaForm}s
+ * so that they do not become visible on stack traces.
+ * <p>
+ * The {@code linkMethod} call is free to omit the appendix
+ * (returning null) and instead emulate the required function
+ * completely in the linker method.
+ * As a corner case, if N==255, no appendix is possible.
+ * In this case, the method returned must be custom-generated to
+ * to perform any needed type checking.
+ * <p>
+ * If the JVM does not reify a method at a call site, but instead
+ * calls {@code linkMethod}, the corresponding call represented
+ * in the bytecodes may mention a valid method which is not
+ * representable with a {@code MemberName}.
+ * Therefore, use cases for {@code linkMethod} tend to correspond to
+ * special cases in reflective code such as {@code findVirtual}
+ * or {@code revealDirect}.
*/
static MemberName linkMethod(Class<?> callerClass, int refKind,
Class<?> defc, String name, Object type,
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java Sat Sep 14 20:43:34 2013 +0100
@@ -26,8 +26,6 @@
package java.lang.invoke;
import java.lang.reflect.*;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
@@ -54,6 +52,7 @@
* </ul>
* <p>
* @author John Rose, JSR 292 EG
+ * @since 1.7
*/
public class MethodHandles {
@@ -97,6 +96,38 @@
}
/**
+ * Performs an unchecked "crack" of a direct method handle.
+ * The result is as if the user had obtained a lookup object capable enough
+ * to crack the target method handle, called
+ * {@link java.lang.invoke.MethodHandles.Lookup#revealDirect Lookup.revealDirect}
+ * on the target to obtain its symbolic reference, and then called
+ * {@link java.lang.invoke.MethodHandleInfo#reflectAs MethodHandleInfo.reflectAs}
+ * to resolve the symbolic reference to a member.
+ * <p>
+ * If there is a security manager, its {@code checkPermission} method
+ * is called with a {@code ReflectPermission("suppressAccessChecks")} permission.
+ * @param <T> the desired type of the result, either {@link Member} or a subtype
+ * @param target a direct method handle to crack into symbolic reference components
+ * @param expected a class object representing the desired result type {@code T}
+ * @return a reference to the method, constructor, or field object
+ * @exception SecurityException if the caller is not privileged to call {@code setAccessible}
+ * @exception NullPointerException if either argument is {@code null}
+ * @exception IllegalArgumentException if the target is not a direct method handle
+ * @exception ClassCastException if the member is not of the expected type
+ * @since 1.8
+ */
+ public static <T extends Member> T
+ reflectAs(Class<T> expected, MethodHandle target) {
+ SecurityManager smgr = System.getSecurityManager();
+ if (smgr != null) smgr.checkPermission(ACCESS_PERMISSION);
+ Lookup lookup = Lookup.IMPL_LOOKUP; // use maximally privileged lookup
+ return lookup.revealDirect(target).reflectAs(expected, lookup);
+ }
+ // Copied from AccessibleObject, as used by Method.setAccessible, etc.:
+ static final private java.security.Permission ACCESS_PERMISSION =
+ new ReflectPermission("suppressAccessChecks");
+
+ /**
* A <em>lookup object</em> is a factory for creating method handles,
* when the creation requires access checking.
* Method handles do not perform
@@ -647,6 +678,7 @@
return invoker(type);
if ("invokeExact".equals(name))
return exactInvoker(type);
+ assert(!MemberName.isMethodHandleInvokeName(name));
return null;
}
@@ -892,6 +924,10 @@
* @throws NullPointerException if the argument is null
*/
public MethodHandle unreflect(Method m) throws IllegalAccessException {
+ if (m.getDeclaringClass() == MethodHandle.class) {
+ MethodHandle mh = unreflectForMH(m);
+ if (mh != null) return mh;
+ }
MemberName method = new MemberName(m);
byte refKind = method.getReferenceKind();
if (refKind == REF_invokeSpecial)
@@ -900,6 +936,12 @@
Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
}
+ private MethodHandle unreflectForMH(Method m) {
+ // these names require special lookups because they throw UnsupportedOperationException
+ if (MemberName.isMethodHandleInvokeName(m.getName()))
+ return MethodHandleImpl.fakeMethodHandleInvoke(new MemberName(m));
+ return null;
+ }
/**
* Produces a method handle for a reflected method.
@@ -1004,6 +1046,46 @@
return unreflectField(f, true);
}
+ /**
+ * Cracks a direct method handle created by this lookup object or a similar one.
+ * Security and access checks are performed to ensure that this lookup object
+ * is capable of reproducing the target method handle.
+ * This means that the cracking may fail if target is a direct method handle
+ * but was created by an unrelated lookup object.
+ * @param target a direct method handle to crack into symbolic reference components
+ * @return a symbolic reference which can be used to reconstruct this method handle from this lookup object
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails
+ * @exception NullPointerException if the target is {@code null}
+ * @since 1.8
+ */
+ public MethodHandleInfo revealDirect(MethodHandle target) {
+ MemberName member = target.internalMemberName();
+ if (member == null || (!member.isResolved() && !member.isMethodHandleInvoke()))
+ throw newIllegalArgumentException("not a direct method handle");
+ Class<?> defc = member.getDeclaringClass();
+ byte refKind = member.getReferenceKind();
+ assert(MethodHandleNatives.refKindIsValid(refKind));
+ if (refKind == REF_invokeSpecial && !target.isInvokeSpecial())
+ // Devirtualized method invocation is usually formally virtual.
+ // To avoid creating extra MemberName objects for this common case,
+ // we encode this extra degree of freedom using MH.isInvokeSpecial.
+ refKind = REF_invokeVirtual;
+ if (refKind == REF_invokeVirtual && defc.isInterface())
+ // Symbolic reference is through interface but resolves to Object method (toString, etc.)
+ refKind = REF_invokeInterface;
+ // Check SM permissions and member access before cracking.
+ try {
+ checkSecurityManager(defc, member);
+ checkAccess(refKind, defc, member);
+ } catch (IllegalAccessException ex) {
+ throw new IllegalArgumentException(ex);
+ }
+ // Produce the handle to the results.
+ return new InfoFromMemberName(this, member, refKind);
+ }
+
/// Helper methods, all package-private.
MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
@@ -1201,12 +1283,12 @@
private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
boolean doRestrict, Class<?> callerClass) throws IllegalAccessException {
checkMethod(refKind, refc, method);
- if (method.isMethodHandleInvoke())
- return fakeMethodHandleInvoke(method);
+ assert(!method.isMethodHandleInvoke());
Class<?> refcAsSuper;
if (refKind == REF_invokeSpecial &&
refc != lookupClass() &&
+ !refc.isInterface() &&
refc != (refcAsSuper = lookupClass().getSuperclass()) &&
refc.isAssignableFrom(lookupClass())) {
assert(!method.getName().equals("<init>")); // not this code path
@@ -1234,9 +1316,6 @@
mh = restrictReceiver(method, mh, lookupClass());
return mh;
}
- private MethodHandle fakeMethodHandleInvoke(MemberName method) {
- return throwException(method.getReturnType(), UnsupportedOperationException.class);
- }
private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh,
Class<?> callerClass)
throws IllegalAccessException {
--- a/jdk/src/share/classes/java/lang/invoke/SerializedLambda.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/SerializedLambda.java Sat Sep 14 20:43:34 2013 +0100
@@ -225,7 +225,7 @@
@Override
public String toString() {
- String implKind=MethodHandleInfo.getReferenceKindString(implMethodKind);
+ String implKind=MethodHandleInfo.referenceKindToString(implMethodKind);
return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " +
"%s=%s %s.%s:%s, %s=%s, %s=%d]",
"capturingClass", capturingClass,
--- a/jdk/src/share/classes/java/lang/reflect/Executable.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/lang/reflect/Executable.java Sat Sep 14 20:43:34 2013 +0100
@@ -428,20 +428,32 @@
}
/**
- * Returns an array of arrays that represent the annotations on
- * the formal parameters, in declaration order, of the executable
- * represented by this object. (Returns an array of length zero if
- * the underlying executable is parameterless. If the executable has
- * one or more parameters, a nested array of length zero is
- * returned for each parameter with no annotations.) The
- * annotation objects contained in the returned arrays are
- * serializable. The caller of this method is free to modify the
- * returned arrays; it will have no effect on the arrays returned
- * to other callers.
+ * Returns an array of arrays of {@code Annotation}s that
+ * represent the annotations on the formal parameters, in
+ * declaration order, of the {@code Executable} represented by
+ * this object. Synthetic and mandated parameters (see
+ * explanation below), such as the outer "this" parameter to an
+ * inner class constructor will be represented in the returned
+ * array. If the executable has no parameters (meaning no formal,
+ * no synthetic, and no mandated parameters), a zero-length array
+ * will be returned. If the {@code Executable} has one or more
+ * parameters, a nested array of length zero is returned for each
+ * parameter with no annotations. The annotation objects contained
+ * in the returned arrays are serializable. The caller of this
+ * method is free to modify the returned arrays; it will have no
+ * effect on the arrays returned to other callers.
*
- * @return an array of arrays that represent the annotations on the formal
- * parameters, in declaration order, of the executable represented by this
- * object
+ * A compiler may add extra parameters that are implicitly
+ * declared in source ("mandated"), as well as parameters that
+ * are neither implicitly nor explicitly declared in source
+ * ("synthetic") to the parameter list for a method. See {@link
+ * java.lang.reflect.Parameter} for more information.
+ *
+ * @see java.lang.reflect.Parameter
+ * @see java.lang.reflect.Parameter#getAnnotations
+ * @return an array of arrays that represent the annotations on
+ * the formal and implicit parameters, in declaration order, of
+ * the executable represented by this object
*/
public abstract Annotation[][] getParameterAnnotations();
--- a/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java Sat Sep 14 20:43:34 2013 +0100
@@ -719,7 +719,3 @@
public final static int SHUT_RD = 0;
public final static int SHUT_WR = 1;
}
-
-class InetAddressContainer {
- InetAddress addr;
-}
--- a/jdk/src/share/classes/java/net/IDN.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/net/IDN.java Sat Sep 14 20:43:34 2013 +0100
@@ -292,13 +292,17 @@
if (useSTD3ASCIIRules) {
for (int i = 0; i < dest.length(); i++) {
int c = dest.charAt(i);
- if (!isLDHChar(c)) {
- throw new IllegalArgumentException("Contains non-LDH characters");
+ if (isNonLDHAsciiCodePoint(c)) {
+ throw new IllegalArgumentException(
+ "Contains non-LDH ASCII characters");
}
}
- if (dest.charAt(0) == '-' || dest.charAt(dest.length() - 1) == '-') {
- throw new IllegalArgumentException("Has leading or trailing hyphen");
+ if (dest.charAt(0) == '-' ||
+ dest.charAt(dest.length() - 1) == '-') {
+
+ throw new IllegalArgumentException(
+ "Has leading or trailing hyphen");
}
}
@@ -401,26 +405,20 @@
//
// LDH stands for "letter/digit/hyphen", with characters restricted to the
// 26-letter Latin alphabet <A-Z a-z>, the digits <0-9>, and the hyphen
- // <->
- // non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x56..0x60, 0x7B..0x7F
+ // <->.
+ // Non LDH refers to characters in the ASCII range, but which are not
+ // letters, digits or the hypen.
+ //
+ // non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x5B..0x60, 0x7B..0x7F
//
- private static boolean isLDHChar(int ch){
- // high runner case
- if(ch > 0x007A){
- return false;
- }
- //['-' '0'..'9' 'A'..'Z' 'a'..'z']
- if((ch == 0x002D) ||
- (0x0030 <= ch && ch <= 0x0039) ||
- (0x0041 <= ch && ch <= 0x005A) ||
- (0x0061 <= ch && ch <= 0x007A)
- ){
- return true;
- }
- return false;
+ private static boolean isNonLDHAsciiCodePoint(int ch){
+ return (0x0000 <= ch && ch <= 0x002C) ||
+ (0x002E <= ch && ch <= 0x002F) ||
+ (0x003A <= ch && ch <= 0x0040) ||
+ (0x005B <= ch && ch <= 0x0060) ||
+ (0x007B <= ch && ch <= 0x007F);
}
-
//
// search dots in a string and return the index of that character;
// or if there is no dots, return the length of input string
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/net/InetAddressContainer.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,30 @@
+/*
+ * 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. 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.net;
+
+class InetAddressContainer {
+ InetAddress addr;
+}
--- a/jdk/src/share/classes/java/nio/file/Files.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/nio/file/Files.java Sat Sep 14 20:43:34 2013 +0100
@@ -25,34 +25,56 @@
package java.nio.file;
-import java.nio.file.attribute.*;
-import java.nio.file.spi.FileSystemProvider;
-import java.nio.file.spi.FileTypeDetector;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.UncheckedIOException;
+import java.io.Writer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.SeekableByteChannel;
-import java.io.Closeable;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.io.Writer;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.util.*;
-import java.util.function.BiPredicate;
-import java.util.stream.CloseableStream;
-import java.util.stream.DelegatingStream;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
+import java.nio.file.attribute.BasicFileAttributeView;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.DosFileAttributes;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.attribute.FileOwnerAttributeView;
+import java.nio.file.attribute.FileStoreAttributeView;
+import java.nio.file.attribute.FileTime;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFileAttributes;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.UserPrincipal;
+import java.nio.file.spi.FileSystemProvider;
+import java.nio.file.spi.FileTypeDetector;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiPredicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
/**
* This class consists exclusively of static methods that operate on files,
@@ -74,6 +96,21 @@
return path.getFileSystem().provider();
}
+ /**
+ * Convert a Closeable to a Runnable by converting checked IOException
+ * to UncheckedIOException
+ */
+ private static Runnable asUncheckedRunnable(Closeable c) {
+ return () -> {
+ try {
+ c.close();
+ }
+ catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ };
+ }
+
// -- File contents --
/**
@@ -3228,29 +3265,7 @@
// -- Stream APIs --
/**
- * Implementation of CloseableStream
- */
- private static class DelegatingCloseableStream<T> extends DelegatingStream<T>
- implements CloseableStream<T>
- {
- private final Closeable closeable;
-
- DelegatingCloseableStream(Closeable c, Stream<T> delegate) {
- super(delegate);
- this.closeable = c;
- }
-
- public void close() {
- try {
- closeable.close();
- } catch (IOException ex) {
- throw new UncheckedIOException(ex);
- }
- }
- }
-
- /**
- * Return a lazily populated {@code CloseableStream}, the elements of
+ * Return a lazily populated {@code Stream}, the elements of
* which are the entries in the directory. The listing is not recursive.
*
* <p> The elements of the stream are {@link Path} objects that are
@@ -3264,10 +3279,13 @@
* reflect updates to the directory that occur after returning from this
* method.
*
- * <p> When not using the try-with-resources construct, then the stream's
- * {@link CloseableStream#close close} method should be invoked after the
- * operation is completed so as to free any resources held for the open
- * directory. Operating on a closed stream behaves as if the end of stream
+ * <p> The returned stream encapsulates a {@link DirectoryStream}.
+ * If timely disposal of file system resources is required, the
+ * {@code try}-with-resources construct should be used to ensure that the
+ * stream's {@link Stream#close close} method is invoked after the stream
+ * operations are completed.
+ *
+ * <p> Operating on a closed stream behaves as if the end of stream
* has been reached. Due to read-ahead, one or more elements may be
* returned after the stream has been closed.
*
@@ -3278,7 +3296,7 @@
*
* @param dir The path to the directory
*
- * @return The {@code CloseableStream} describing the content of the
+ * @return The {@code Stream} describing the content of the
* directory
*
* @throws NotDirectoryException
@@ -3294,43 +3312,54 @@
* @see #newDirectoryStream(Path)
* @since 1.8
*/
- public static CloseableStream<Path> list(Path dir) throws IOException {
+ public static Stream<Path> list(Path dir) throws IOException {
DirectoryStream<Path> ds = Files.newDirectoryStream(dir);
- final Iterator<Path> delegate = ds.iterator();
+ try {
+ final Iterator<Path> delegate = ds.iterator();
- // Re-wrap DirectoryIteratorException to UncheckedIOException
- Iterator<Path> it = new Iterator<Path>() {
- public boolean hasNext() {
+ // Re-wrap DirectoryIteratorException to UncheckedIOException
+ Iterator<Path> it = new Iterator<Path>() {
+ @Override
+ public boolean hasNext() {
+ try {
+ return delegate.hasNext();
+ } catch (DirectoryIteratorException e) {
+ throw new UncheckedIOException(e.getCause());
+ }
+ }
+ @Override
+ public Path next() {
+ try {
+ return delegate.next();
+ } catch (DirectoryIteratorException e) {
+ throw new UncheckedIOException(e.getCause());
+ }
+ }
+ };
+
+ return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false)
+ .onClose(asUncheckedRunnable(ds));
+ } catch (Error|RuntimeException e) {
+ try {
+ ds.close();
+ } catch (IOException ex) {
try {
- return delegate.hasNext();
- } catch (DirectoryIteratorException e) {
- throw new UncheckedIOException(e.getCause());
- }
+ e.addSuppressed(ex);
+ } catch (Throwable ignore) {}
}
- public Path next() {
- try {
- return delegate.next();
- } catch (DirectoryIteratorException e) {
- throw new UncheckedIOException(e.getCause());
- }
- }
- };
-
- Stream<Path> s = StreamSupport.stream(
- Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT),
- false);
- return new DelegatingCloseableStream<>(ds, s);
+ throw e;
+ }
}
/**
- * Return a {@code CloseableStream} that is lazily populated with {@code
+ * Return a {@code Stream} that is lazily populated with {@code
* Path} by walking the file tree rooted at a given starting file. The
* file tree is traversed <em>depth-first</em>, the elements in the stream
* are {@link Path} objects that are obtained as if by {@link
* Path#resolve(Path) resolving} the relative path against {@code start}.
*
* <p> The {@code stream} walks the file tree as elements are consumed.
- * The {@code CloseableStream} returned is guaranteed to have at least one
+ * The {@code Stream} returned is guaranteed to have at least one
* element, the starting file itself. For each file visited, the stream
* attempts to read its {@link BasicFileAttributes}. If the file is a
* directory and can be opened successfully, entries in the directory, and
@@ -3370,10 +3399,11 @@
* <p> When a security manager is installed and it denies access to a file
* (or directory), then it is ignored and not included in the stream.
*
- * <p> When not using the try-with-resources construct, then the stream's
- * {@link CloseableStream#close close} method should be invoked after the
- * operation is completed so as to free any resources held for the open
- * directory. Operate the stream after it is closed will throw an
+ * <p> The returned stream encapsulates one or more {@link DirectoryStream}s.
+ * If timely disposal of file system resources is required, the
+ * {@code try}-with-resources construct should be used to ensure that the
+ * stream's {@link Stream#close close} method is invoked after the stream
+ * operations are completed. Operating on a closed stream will result in an
* {@link java.lang.IllegalStateException}.
*
* <p> If an {@link IOException} is thrown when accessing the directory
@@ -3388,7 +3418,7 @@
* @param options
* options to configure the traversal
*
- * @return the {@link CloseableStream} of {@link Path}
+ * @return the {@link Stream} of {@link Path}
*
* @throws IllegalArgumentException
* if the {@code maxDepth} parameter is negative
@@ -3401,21 +3431,22 @@
* if an I/O error is thrown when accessing the starting file.
* @since 1.8
*/
- public static CloseableStream<Path> walk(Path start, int maxDepth,
- FileVisitOption... options)
- throws IOException
- {
+ public static Stream<Path> walk(Path start, int maxDepth,
+ FileVisitOption... options)
+ throws IOException {
FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
-
- Stream<Path> s = StreamSupport.stream(
- Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT),
- false).
- map(entry -> entry.file());
- return new DelegatingCloseableStream<>(iterator, s);
+ try {
+ return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), false)
+ .onClose(iterator::close)
+ .map(entry -> entry.file());
+ } catch (Error|RuntimeException e) {
+ iterator.close();
+ throw e;
+ }
}
/**
- * Return a {@code CloseableStream} that is lazily populated with {@code
+ * Return a {@code Stream} that is lazily populated with {@code
* Path} by walking the file tree rooted at a given starting file. The
* file tree is traversed <em>depth-first</em>, the elements in the stream
* are {@link Path} objects that are obtained as if by {@link
@@ -3428,12 +3459,19 @@
* </pre></blockquote>
* In other words, it visits all levels of the file tree.
*
+ * <p> The returned stream encapsulates one or more {@link DirectoryStream}s.
+ * If timely disposal of file system resources is required, the
+ * {@code try}-with-resources construct should be used to ensure that the
+ * stream's {@link Stream#close close} method is invoked after the stream
+ * operations are completed. Operating on a closed stream will result in an
+ * {@link java.lang.IllegalStateException}.
+ *
* @param start
* the starting file
* @param options
* options to configure the traversal
*
- * @return the {@link CloseableStream} of {@link Path}
+ * @return the {@link Stream} of {@link Path}
*
* @throws SecurityException
* If the security manager denies access to the starting file.
@@ -3446,15 +3484,14 @@
* @see #walk(Path, int, FileVisitOption...)
* @since 1.8
*/
- public static CloseableStream<Path> walk(Path start,
- FileVisitOption... options)
- throws IOException
- {
+ public static Stream<Path> walk(Path start,
+ FileVisitOption... options)
+ throws IOException {
return walk(start, Integer.MAX_VALUE, options);
}
/**
- * Return a {@code CloseableStream} that is lazily populated with {@code
+ * Return a {@code Stream} that is lazily populated with {@code
* Path} by searching for files in a file tree rooted at a given starting
* file.
*
@@ -3463,12 +3500,19 @@
* {@link BiPredicate} is invoked with its {@link Path} and {@link
* BasicFileAttributes}. The {@code Path} object is obtained as if by
* {@link Path#resolve(Path) resolving} the relative path against {@code
- * start} and is only included in the returned {@link CloseableStream} if
+ * start} and is only included in the returned {@link Stream} if
* the {@code BiPredicate} returns true. Compare to calling {@link
* java.util.stream.Stream#filter filter} on the {@code Stream}
* returned by {@code walk} method, this method may be more efficient by
* avoiding redundant retrieval of the {@code BasicFileAttributes}.
*
+ * <p> The returned stream encapsulates one or more {@link DirectoryStream}s.
+ * If timely disposal of file system resources is required, the
+ * {@code try}-with-resources construct should be used to ensure that the
+ * stream's {@link Stream#close close} method is invoked after the stream
+ * operations are completed. Operating on a closed stream will result in an
+ * {@link java.lang.IllegalStateException}.
+ *
* <p> If an {@link IOException} is thrown when accessing the directory
* after returned from this method, it is wrapped in an {@link
* UncheckedIOException} which will be thrown from the method that caused
@@ -3484,7 +3528,7 @@
* @param options
* options to configure the traversal
*
- * @return the {@link CloseableStream} of {@link Path}
+ * @return the {@link Stream} of {@link Path}
*
* @throws IllegalArgumentException
* if the {@code maxDepth} parameter is negative
@@ -3499,24 +3543,25 @@
* @see #walk(Path, int, FileVisitOption...)
* @since 1.8
*/
- public static CloseableStream<Path> find(Path start,
- int maxDepth,
- BiPredicate<Path, BasicFileAttributes> matcher,
- FileVisitOption... options)
- throws IOException
- {
+ public static Stream<Path> find(Path start,
+ int maxDepth,
+ BiPredicate<Path, BasicFileAttributes> matcher,
+ FileVisitOption... options)
+ throws IOException {
FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
-
- Stream<Path> s = StreamSupport.stream(
- Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT),
- false).
- filter(entry -> matcher.test(entry.file(), entry.attributes())).
- map(entry -> entry.file());
- return new DelegatingCloseableStream<>(iterator, s);
+ try {
+ return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), false)
+ .onClose(iterator::close)
+ .filter(entry -> matcher.test(entry.file(), entry.attributes()))
+ .map(entry -> entry.file());
+ } catch (Error|RuntimeException e) {
+ iterator.close();
+ throw e;
+ }
}
/**
- * Read all lines from a file as a {@code CloseableStream}. Unlike {@link
+ * Read all lines from a file as a {@code Stream}. Unlike {@link
* #readAllLines(Path, Charset) readAllLines}, this method does not read
* all lines into a {@code List}, but instead populates lazily as the stream
* is consumed.
@@ -3528,22 +3573,24 @@
* <p> After this method returns, then any subsequent I/O exception that
* occurs while reading from the file or when a malformed or unmappable byte
* sequence is read, is wrapped in an {@link UncheckedIOException} that will
- * be thrown form the
+ * be thrown from the
* {@link java.util.stream.Stream} method that caused the read to take
* place. In case an {@code IOException} is thrown when closing the file,
* it is also wrapped as an {@code UncheckedIOException}.
*
- * <p> When not using the try-with-resources construct, then stream's
- * {@link CloseableStream#close close} method should be invoked after
- * operation is completed so as to free any resources held for the open
- * file.
+ * <p> The returned stream encapsulates a {@link Reader}. If timely
+ * disposal of file system resources is required, the try-with-resources
+ * construct should be used to ensure that the stream's
+ * {@link Stream#close close} method is invoked after the stream operations
+ * are completed.
+ *
*
* @param path
* the path to the file
* @param cs
* the charset to use for decoding
*
- * @return the lines from the file as a {@code CloseableStream}
+ * @return the lines from the file as a {@code Stream}
*
* @throws IOException
* if an I/O error occurs opening the file
@@ -3557,10 +3604,19 @@
* @see java.io.BufferedReader#lines()
* @since 1.8
*/
- public static CloseableStream<String> lines(Path path, Charset cs)
- throws IOException
- {
+ public static Stream<String> lines(Path path, Charset cs) throws IOException {
BufferedReader br = Files.newBufferedReader(path, cs);
- return new DelegatingCloseableStream<>(br, br.lines());
+ try {
+ return br.lines().onClose(asUncheckedRunnable(br));
+ } catch (Error|RuntimeException e) {
+ try {
+ br.close();
+ } catch (IOException ex) {
+ try {
+ e.addSuppressed(ex);
+ } catch (Throwable ignore) {}
+ }
+ throw e;
+ }
}
}
--- a/jdk/src/share/classes/java/rmi/activation/Activatable.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/rmi/activation/Activatable.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -93,6 +93,8 @@
* @exception RemoteException if either of the following fails:
* a) registering the object with the activation system or b) exporting
* the object to the RMI runtime.
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation.
* @since 1.2
**/
protected Activatable(String location,
@@ -143,6 +145,8 @@
* @exception RemoteException if either of the following fails:
* a) registering the object with the activation system or b) exporting
* the object to the RMI runtime.
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation.
* @since 1.2
**/
protected Activatable(String location,
@@ -175,6 +179,8 @@
* @param port the port number on which the object is exported
* @exception RemoteException if exporting the object to the RMI
* runtime fails
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
*/
protected Activatable(ActivationID id, int port)
@@ -206,6 +212,8 @@
* @param ssf the server-side socket factory for receiving remote calls
* @exception RemoteException if exporting the object to the RMI
* runtime fails
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
*/
protected Activatable(ActivationID id, int port,
@@ -239,6 +247,8 @@
* is not registered with the activation system
* @exception ActivationException if activation system is not running
* @exception RemoteException if remote call fails
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
*/
public static Remote register(ActivationDesc desc)
@@ -273,6 +283,8 @@
* already be inactive)
* @exception ActivationException if group is not active
* @exception RemoteException if call informing monitor fails
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
*/
public static boolean inactive(ActivationID id)
@@ -290,6 +302,8 @@
* @exception UnknownObjectException if object (<code>id</code>) is unknown
* @exception ActivationException if activation system is not running
* @exception RemoteException if remote call to activation system fails
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
*/
public static void unregister(ActivationID id)
@@ -334,6 +348,8 @@
* the wrong group
* @exception ActivationException if activation group is not active
* @exception RemoteException if object registration or export fails
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
**/
public static ActivationID exportObject(Remote obj,
@@ -407,6 +423,8 @@
* descriptor with the activation system
* @exception ActivationException if activation group is not active
* @exception RemoteException if object registration or export fails
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
**/
public static ActivationID exportObject(Remote obj,
@@ -473,6 +491,8 @@
* @param port the port on which the object is exported (an anonymous
* port is used if port=0)
* @exception RemoteException if object export fails
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
*/
public static Remote exportObject(Remote obj,
@@ -503,6 +523,8 @@
* remote object
* @param ssf the server-side socket factory for receiving remote calls
* @exception RemoteException if object export fails
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
*/
public static Remote exportObject(Remote obj,
@@ -531,6 +553,8 @@
* @return true if operation is successful, false otherwise
* @exception NoSuchObjectException if the remote object is not
* currently exported
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
*/
public static boolean unexportObject(Remote obj, boolean force)
--- a/jdk/src/share/classes/java/rmi/activation/ActivationDesc.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/rmi/activation/ActivationDesc.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -105,6 +105,8 @@
* @param data the object's initialization (activation) data contained
* in marshalled form.
* @exception ActivationException if the current group is nonexistent
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
*/
public ActivationDesc(String className,
@@ -142,6 +144,8 @@
* <code>true</code> does not force an initial immediate activation of
* a newly registered object; initial activation is lazy.
* @exception ActivationException if the current group is nonexistent
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
*/
public ActivationDesc(String className,
@@ -176,6 +180,8 @@
* @param data the object's initialization (activation) data contained
* in marshalled form.
* @exception IllegalArgumentException if <code>groupID</code> is null
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
*/
public ActivationDesc(ActivationGroupID groupID,
@@ -208,6 +214,8 @@
* <code>true</code> does not force an initial immediate activation of
* a newly registered object; initial activation is lazy.
* @exception IllegalArgumentException if <code>groupID</code> is null
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
*/
public ActivationDesc(ActivationGroupID groupID,
--- a/jdk/src/share/classes/java/rmi/activation/ActivationGroup.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/rmi/activation/ActivationGroup.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -133,6 +133,8 @@
*
* @param groupID the group's identifier
* @throws RemoteException if this group could not be exported
+ * @throws UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
*/
protected ActivationGroup(ActivationGroupID groupID)
@@ -267,6 +269,8 @@
* (Note: The default implementation of the security manager
* <code>checkSetFactory</code>
* method requires the RuntimePermission "setFactory")
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @see SecurityManager#checkSetFactory
* @since 1.2
*/
@@ -345,6 +349,8 @@
/**
* Returns the current activation group's identifier. Returns null
* if no group is currently active for this VM.
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @return the activation group's identifier
* @since 1.2
*/
@@ -394,6 +400,8 @@
* (Note: The default implementation of the security manager
* <code>checkSetFactory</code>
* method requires the RuntimePermission "setFactory")
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @see #getSystem
* @see SecurityManager#checkSetFactory
* @since 1.2
@@ -428,6 +436,8 @@
* @exception ActivationException if activation system cannot be
* obtained or is not bound
* (means that it is not running)
+ * @exception UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @see #setSystem
* @since 1.2
*/
--- a/jdk/src/share/classes/java/rmi/activation/ActivationGroupID.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/rmi/activation/ActivationGroupID.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -63,6 +63,8 @@
* Constructs a unique group id.
*
* @param system the group's activation system
+ * @throws UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
*/
public ActivationGroupID(ActivationSystem system) {
--- a/jdk/src/share/classes/java/rmi/activation/ActivationID.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/rmi/activation/ActivationID.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -90,6 +90,8 @@
*
* @param activator reference to the activator responsible for
* activating the object
+ * @throws UnsupportedOperationException if and only if activation is
+ * not supported by this implementation
* @since 1.2
*/
public ActivationID(Activator activator) {
--- a/jdk/src/share/classes/java/rmi/activation/package.html Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/rmi/activation/package.html Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
<!--
- Copyright (c) 1998, 1999, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 1998, 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
@@ -31,6 +31,15 @@
object's reference can be made ``persistent'' and later activated into a
``live'' object using the RMI activation mechanism.
+<p>Implementations are not required to support the activation
+mechanism. If activation is not supported by this implementation,
+several specific activation API methods are all required to throw
+{@code UnsupportedOperationException}. If activation is supported by this
+implementation, these methods must never throw {@code
+UnsupportedOperationException}. These methods are denoted by the
+presence of an entry for {@code UnsupportedOperationException} in the
+<strong>Throws</strong> section of each method's specification.
+
<!--
<h2>Package Specification</h2>
--- a/jdk/src/share/classes/java/security/AccessController.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/security/AccessController.java Sat Sep 14 20:43:34 2013 +0100
@@ -279,6 +279,9 @@
* <p> Note that any DomainCombiner associated with the current
* AccessControlContext will be ignored while the action is performed.
*
+ * @param <T> the type of the value returned by the PrivilegedAction's
+ * {@code run} method.
+ *
* @param action the action to be performed.
*
* @return the value returned by the action's {@code run} method.
@@ -305,6 +308,9 @@
* <p> This method preserves the current AccessControlContext's
* DomainCombiner (which may be null) while the action is performed.
*
+ * @param <T> the type of the value returned by the PrivilegedAction's
+ * {@code run} method.
+ *
* @param action the action to be performed.
*
* @return the value returned by the action's {@code run} method.
@@ -344,6 +350,8 @@
* {@link java.security.SecurityPermission}, then the action is performed
* with no permissions.
*
+ * @param <T> the type of the value returned by the PrivilegedAction's
+ * {@code run} method.
* @param action the action to be performed.
* @param context an <i>access control context</i>
* representing the restriction to be applied to the
@@ -377,6 +385,8 @@
* If the action's {@code run} method throws an (unchecked) exception,
* it will propagate through this method.
*
+ * @param <T> the type of the value returned by the PrivilegedAction's
+ * {@code run} method.
* @param action the action to be performed.
* @param context an <i>access control context</i>
* representing the restriction to be applied to the
@@ -429,6 +439,8 @@
* <p> This method preserves the current AccessControlContext's
* DomainCombiner (which may be null) while the action is performed.
*
+ * @param <T> the type of the value returned by the PrivilegedAction's
+ * {@code run} method.
* @param action the action to be performed.
* @param context an <i>access control context</i>
* representing the restriction to be applied to the
@@ -479,6 +491,9 @@
* <p> Note that any DomainCombiner associated with the current
* AccessControlContext will be ignored while the action is performed.
*
+ * @param <T> the type of the value returned by the
+ * PrivilegedExceptionAction's {@code run} method.
+ *
* @param action the action to be performed
*
* @return the value returned by the action's {@code run} method
@@ -509,6 +524,9 @@
* <p> This method preserves the current AccessControlContext's
* DomainCombiner (which may be null) while the action is performed.
*
+ * @param <T> the type of the value returned by the
+ * PrivilegedExceptionAction's {@code run} method.
+ *
* @param action the action to be performed.
*
* @return the value returned by the action's {@code run} method
@@ -585,6 +603,8 @@
* {@link java.security.SecurityPermission}, then the action is performed
* with no permissions.
*
+ * @param <T> the type of the value returned by the
+ * PrivilegedExceptionAction's {@code run} method.
* @param action the action to be performed
* @param context an <i>access control context</i>
* representing the restriction to be applied to the
@@ -622,6 +642,8 @@
* If the action's {@code run} method throws an (unchecked) exception,
* it will propagate through this method.
*
+ * @param <T> the type of the value returned by the
+ * PrivilegedExceptionAction's {@code run} method.
* @param action the action to be performed.
* @param context an <i>access control context</i>
* representing the restriction to be applied to the
@@ -676,6 +698,8 @@
* <p> This method preserves the current AccessControlContext's
* DomainCombiner (which may be null) while the action is performed.
*
+ * @param <T> the type of the value returned by the
+ * PrivilegedExceptionAction's {@code run} method.
* @param action the action to be performed.
* @param context an <i>access control context</i>
* representing the restriction to be applied to the
--- a/jdk/src/share/classes/java/security/AlgorithmParameters.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/security/AlgorithmParameters.java Sat Sep 14 20:43:34 2013 +0100
@@ -324,6 +324,7 @@
* parameters should be returned in an instance of the
* {@code DSAParameterSpec} class.
*
+ * @param <T> the type of the parameter specification to be returrned
* @param paramSpec the specification class in which
* the parameters should be returned.
*
--- a/jdk/src/share/classes/java/security/AlgorithmParametersSpi.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/security/AlgorithmParametersSpi.java Sat Sep 14 20:43:34 2013 +0100
@@ -102,6 +102,8 @@
* parameters should be returned in an instance of the
* {@code DSAParameterSpec} class.
*
+ * @param <T> the type of the parameter specification to be returned
+ *
* @param paramSpec the specification class in which
* the parameters should be returned.
*
--- a/jdk/src/share/classes/java/security/KeyFactory.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/security/KeyFactory.java Sat Sep 14 20:43:34 2013 +0100
@@ -395,6 +395,8 @@
* key material should be returned in an instance of the
* {@code DSAPublicKeySpec} class.
*
+ * @param <T> the type of the key specification to be returned
+ *
* @param key the key.
*
* @param keySpec the specification class in which
--- a/jdk/src/share/classes/java/security/KeyFactorySpi.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/security/KeyFactorySpi.java Sat Sep 14 20:43:34 2013 +0100
@@ -106,6 +106,8 @@
* key material should be returned in an instance of the
* {@code DSAPublicKeySpec} class.
*
+ * @param <T> the type of the key specification to be returned
+ *
* @param key the key.
*
* @param keySpec the specification class in which
--- a/jdk/src/share/classes/java/security/KeyStore.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/security/KeyStore.java Sat Sep 14 20:43:34 2013 +0100
@@ -1753,6 +1753,7 @@
/**
* Returns the KeyStore described by this object.
*
+ * @return the {@code KeyStore} described by this object
* @exception KeyStoreException if an error occured during the
* operation, for example if the KeyStore could not be
* instantiated or loaded
--- a/jdk/src/share/classes/java/security/Principal.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/security/Principal.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -81,6 +81,7 @@
* <p>Subclasses may override this with a different implementation, if
* necessary.
*
+ * @param subject the {@code Subject}
* @return true if {@code subject} is non-null and is
* implied by this principal, or false otherwise.
* @since 1.8
--- a/jdk/src/share/classes/java/security/cert/CertPathBuilderSpi.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/security/cert/CertPathBuilderSpi.java Sat Sep 14 20:43:34 2013 +0100
@@ -87,6 +87,8 @@
* service providers, this method cannot be abstract and by default throws
* an {@code UnsupportedOperationException}.
*
+ * @return a {@code CertPathChecker} that this implementation uses to
+ * check the revocation status of certificates
* @throws UnsupportedOperationException if this method is not supported
* @since 1.8
*/
--- a/jdk/src/share/classes/java/security/cert/CertPathValidatorSpi.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/security/cert/CertPathValidatorSpi.java Sat Sep 14 20:43:34 2013 +0100
@@ -97,6 +97,8 @@
* service providers, this method cannot be abstract and by default throws
* an {@code UnsupportedOperationException}.
*
+ * @return a {@code CertPathChecker} that this implementation uses to
+ * check the revocation status of certificates
* @throws UnsupportedOperationException if this method is not supported
* @since 1.8
*/
--- a/jdk/src/share/classes/java/security/cert/PKIXRevocationChecker.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/security/cert/PKIXRevocationChecker.java Sat Sep 14 20:43:34 2013 +0100
@@ -103,6 +103,9 @@
private Map<X509Certificate, byte[]> ocspResponses = Collections.emptyMap();
private Set<Option> options = Collections.emptySet();
+ /**
+ * Default constructor.
+ */
protected PKIXRevocationChecker() {}
/**
@@ -300,8 +303,7 @@
* <li>The CRL or OCSP response cannot be obtained because of a
* network error.
* <li>The OCSP responder returns one of the following errors
- * specified in section 2.3 of RFC 2560: internalError, tryLater,
- * or unauthorized.
+ * specified in section 2.3 of RFC 2560: internalError or tryLater.
* </ul><br>
* Note that these conditions apply to both OCSP and CRLs, and unless
* the {@code NO_FALLBACK} option is set, the revocation check is
--- a/jdk/src/share/classes/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -46,6 +46,11 @@
public interface RSAMultiPrimePrivateCrtKey extends RSAPrivateKey {
+ /**
+ * The type fingerprint that is set to indicate
+ * serialization compatibility with a previous
+ * version of the type.
+ */
static final long serialVersionUID = 618058533534628008L;
/**
--- a/jdk/src/share/classes/java/security/interfaces/RSAPrivateCrtKey.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/security/interfaces/RSAPrivateCrtKey.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -39,6 +39,11 @@
public interface RSAPrivateCrtKey extends RSAPrivateKey {
+ /**
+ * The type fingerprint that is set to indicate
+ * serialization compatibility with a previous
+ * version of the type.
+ */
static final long serialVersionUID = -5682214253527700368L;
/**
--- a/jdk/src/share/classes/java/security/interfaces/RSAPrivateKey.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/security/interfaces/RSAPrivateKey.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -39,6 +39,11 @@
public interface RSAPrivateKey extends java.security.PrivateKey, RSAKey
{
+ /**
+ * The type fingerprint that is set to indicate
+ * serialization compatibility with a previous
+ * version of the type.
+ */
static final long serialVersionUID = 5187144804936595022L;
/**
--- a/jdk/src/share/classes/java/security/interfaces/RSAPublicKey.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/security/interfaces/RSAPublicKey.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -36,6 +36,11 @@
public interface RSAPublicKey extends java.security.PublicKey, RSAKey
{
+ /**
+ * The type fingerprint that is set to indicate
+ * serialization compatibility with a previous
+ * version of the type.
+ */
static final long serialVersionUID = -8727434096241101194L;
/**
--- a/jdk/src/share/classes/java/sql/DriverManager.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/sql/DriverManager.java Sat Sep 14 20:43:34 2013 +0100
@@ -326,6 +326,7 @@
* @param driver the new JDBC Driver that is to be registered with the
* {@code DriverManager}
* @exception SQLException if a database access error occurs
+ * @exception NullPointerException if {@code driver} is null
*/
public static synchronized void registerDriver(java.sql.Driver driver)
throws SQLException {
@@ -345,6 +346,7 @@
* @param da the {@code DriverAction} implementation to be used when
* {@code DriverManager#deregisterDriver} is called
* @exception SQLException if a database access error occurs
+ * @exception NullPointerException if {@code driver} is null
*/
public static synchronized void registerDriver(java.sql.Driver driver,
DriverAction da)
--- a/jdk/src/share/classes/java/sql/PreparedStatement.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/sql/PreparedStatement.java Sat Sep 14 20:43:34 2013 +0100
@@ -954,7 +954,6 @@
* the JDBC driver does not support this data type
* @see Types
*
- * @since 1.6
*/
void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength)
throws SQLException;
--- a/jdk/src/share/classes/java/time/Duration.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/Duration.java Sat Sep 14 20:43:34 2013 +0100
@@ -74,7 +74,7 @@
import java.io.DataOutput;
import java.io.IOException;
import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
@@ -1299,8 +1299,9 @@
/**
* Writes the object using a
* <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+ * @serialData
* <pre>
- * out.writeByte(1); // identifies this as a Duration
+ * out.writeByte(1); // identifies a Duration
* out.writeLong(seconds);
* out.writeInt(nanos);
* </pre>
@@ -1316,7 +1317,7 @@
* @return never
* @throws InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
--- a/jdk/src/share/classes/java/time/Instant.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/Instant.java Sat Sep 14 20:43:34 2013 +0100
@@ -76,7 +76,7 @@
import java.io.DataOutput;
import java.io.IOException;
import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
@@ -1317,8 +1317,9 @@
/**
* Writes the object using a
* <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+ * @serialData
* <pre>
- * out.writeByte(2); // identifies this as an Instant
+ * out.writeByte(2); // identifies an Instant
* out.writeLong(seconds);
* out.writeInt(nanos);
* </pre>
@@ -1334,7 +1335,7 @@
* @return never
* @throws InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
--- a/jdk/src/share/classes/java/time/LocalDate.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/LocalDate.java Sat Sep 14 20:43:34 2013 +0100
@@ -78,7 +78,7 @@
import java.io.DataOutput;
import java.io.IOException;
import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.chrono.ChronoLocalDate;
import java.time.chrono.Era;
@@ -2019,8 +2019,9 @@
/**
* Writes the object using a
* <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+ * @serialData
* <pre>
- * out.writeByte(3); // identifies this as a LocalDate
+ * out.writeByte(3); // identifies a LocalDate
* out.writeInt(year);
* out.writeByte(month);
* out.writeByte(day);
@@ -2037,7 +2038,7 @@
* @return never
* @throws InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
--- a/jdk/src/share/classes/java/time/LocalDateTime.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/LocalDateTime.java Sat Sep 14 20:43:34 2013 +0100
@@ -76,7 +76,7 @@
import java.io.DataOutput;
import java.io.IOException;
import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.chrono.ChronoLocalDateTime;
import java.time.format.DateTimeFormatter;
@@ -1953,8 +1953,9 @@
/**
* Writes the object using a
* <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+ * @serialData
* <pre>
- * out.writeByte(5); // identifies this as a LocalDateTime
+ * out.writeByte(5); // identifies a LocalDateTime
* // the <a href="../../serialized-form.html#java.time.LocalDate">date</a> excluding the one byte header
* // the <a href="../../serialized-form.html#java.time.LocalTime">time</a> excluding the one byte header
* </pre>
@@ -1970,7 +1971,7 @@
* @return never
* @throws InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
--- a/jdk/src/share/classes/java/time/LocalTime.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/LocalTime.java Sat Sep 14 20:43:34 2013 +0100
@@ -74,7 +74,7 @@
import java.io.DataOutput;
import java.io.IOException;
import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
@@ -1595,8 +1595,11 @@
/**
* Writes the object using a
* <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+ * @serialData
+ * A twos-complement value indicates the remaining values are not in the stream
+ * and should be set to zero.
* <pre>
- * out.writeByte(4); // identifies this as a LocalTime
+ * out.writeByte(4); // identifies a LocalTime
* if (nano == 0) {
* if (second == 0) {
* if (minute == 0) {
@@ -1629,7 +1632,7 @@
* @return never
* @throws InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
--- a/jdk/src/share/classes/java/time/MonthDay.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/MonthDay.java Sat Sep 14 20:43:34 2013 +0100
@@ -68,7 +68,7 @@
import java.io.DataOutput;
import java.io.IOException;
import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.chrono.Chronology;
import java.time.chrono.IsoChronology;
@@ -744,9 +744,10 @@
//-----------------------------------------------------------------------
/**
* Writes the object using a
- * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+ * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+ * @serialData
* <pre>
- * out.writeByte(13); // identifies this as a MonthDay
+ * out.writeByte(13); // identifies a MonthDay
* out.writeByte(month);
* out.writeByte(day);
* </pre>
@@ -762,7 +763,7 @@
* @return never
* @throws InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
--- a/jdk/src/share/classes/java/time/OffsetDateTime.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/OffsetDateTime.java Sat Sep 14 20:43:34 2013 +0100
@@ -72,7 +72,7 @@
import java.io.InvalidObjectException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
@@ -1901,9 +1901,10 @@
//-----------------------------------------------------------------------
/**
* Writes the object using a
- * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+ * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+ * @serialData
* <pre>
- * out.writeByte(10); // identifies this as a OffsetDateTime
+ * out.writeByte(10); // identifies a OffsetDateTime
* out.writeObject(dateTime);
* out.writeObject(offset);
* </pre>
@@ -1919,7 +1920,7 @@
* @return never
* @throws InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
--- a/jdk/src/share/classes/java/time/OffsetTime.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/OffsetTime.java Sat Sep 14 20:43:34 2013 +0100
@@ -73,7 +73,7 @@
import java.io.InvalidObjectException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
@@ -1372,9 +1372,10 @@
//-----------------------------------------------------------------------
/**
* Writes the object using a
- * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+ * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+ * @serialData
* <pre>
- * out.writeByte(9); // identifies this as a OffsetTime
+ * out.writeByte(9); // identifies a OffsetTime
* out.writeObject(time);
* out.writeObject(offset);
* </pre>
@@ -1390,7 +1391,7 @@
* @return never
* @throws InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
--- a/jdk/src/share/classes/java/time/Period.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/Period.java Sat Sep 14 20:43:34 2013 +0100
@@ -70,7 +70,7 @@
import java.io.DataOutput;
import java.io.IOException;
import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.chrono.ChronoLocalDate;
import java.time.chrono.Chronology;
@@ -993,11 +993,12 @@
/**
* Writes the object using a
* <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+ * @serialData
* <pre>
- * out.writeByte(14); // identifies this as a Period
+ * out.writeByte(14); // identifies a Period
* out.writeInt(years);
* out.writeInt(months);
- * out.writeInt(seconds);
+ * out.writeInt(days);
* </pre>
*
* @return the instance of {@code Ser}, not null
@@ -1011,7 +1012,7 @@
* @return never
* @throws java.io.InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
--- a/jdk/src/share/classes/java/time/Ser.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/Ser.java Sat Sep 14 20:43:34 2013 +0100
@@ -72,14 +72,14 @@
* byte flag would be used in order to specify an alternative version of the type format.
* For example {@code LOCAL_DATE_TYPE_VERSION_2 = 21}.
* <p>
- * In order to serialise the object it writes its byte and then calls back to the appropriate class where
- * the serialisation is performed. In order to deserialise the object it read in the type byte, switching
+ * In order to serialize the object it writes its byte and then calls back to the appropriate class where
+ * the serialization is performed. In order to deserialize the object it read in the type byte, switching
* in order to select which class to call back into.
* <p>
- * The serialisation format is determined on a per class basis. In the case of field based classes each
+ * The serialization format is determined on a per class basis. In the case of field based classes each
* of the fields is written out with an appropriate size format in descending order of the field's size. For
* example in the case of {@link LocalDate} year is written before month. Composite classes, such as
- * {@link LocalDateTime} are serialised as one object.
+ * {@link LocalDateTime} are serialized as one object.
* <p>
* This class is mutable and should be created once per serialization.
*
@@ -133,6 +133,27 @@
//-----------------------------------------------------------------------
/**
* Implements the {@code Externalizable} interface to write the object.
+ * @serialData
+ *
+ * Each serializable class is mapped to a type that is the first byte
+ * in the stream. Refer to each class {@code writeReplace}
+ * serialized form for the value of the type and sequence of values for the type.
+ * <ul>
+ * <li><a href="../../serialized-form.html#java.time.Duration">Duration.writeReplace</a>
+ * <li><a href="../../serialized-form.html#java.time.Instant">Instant.writeReplace</a>
+ * <li><a href="../../serialized-form.html#java.time.LocalDate">LocalDate.writeReplace</a>
+ * <li><a href="../../serialized-form.html#java.time.LocalDateTime">LocalDateTime.writeReplace</a>
+ * <li><a href="../../serialized-form.html#java.time.LocalTime">LocalTime.writeReplace</a>
+ * <li><a href="../../serialized-form.html#java.time.MonthDay">MonthDay.writeReplace</a>
+ * <li><a href="../../serialized-form.html#java.time.OffsetTime">OffsetTime.writeReplace</a>
+ * <li><a href="../../serialized-form.html#java.time.OffsetDateTime">OffsetDateTime.writeReplace</a>
+ * <li><a href="../../serialized-form.html#java.time.Period">Period.writeReplace</a>
+ * <li><a href="../../serialized-form.html#java.time.Year">Year.writeReplace</a>
+ * <li><a href="../../serialized-form.html#java.time.YearMonth">YearMonth.writeReplace</a>
+ * <li><a href="../../serialized-form.html#java.time.ZoneId">ZoneId.writeReplace</a>
+ * <li><a href="../../serialized-form.html#java.time.ZoneOffset">ZoneOffset.writeReplace</a>
+ * <li><a href="../../serialized-form.html#java.time.ZonedDateTime">ZonedDateTime.writeReplace</a>
+ * </ul>
*
* @param out the data stream to write to, not null
*/
@@ -194,6 +215,29 @@
//-----------------------------------------------------------------------
/**
* Implements the {@code Externalizable} interface to read the object.
+ * @serialData
+ *
+ * The streamed type and parameters defined by the type's {@code writeReplace}
+ * method are read and passed to the corresponding static factory for the type
+ * to create a new instance. That instance is returned as the de-serialized
+ * {@code Ser} object.
+ *
+ * <ul>
+ * <li><a href="../../serialized-form.html#java.time.Duration">Duration</a> - {@code Duration.ofSeconds(seconds, nanos);}
+ * <li><a href="../../serialized-form.html#java.time.Instant">Instant</a> - {@code Instant.ofEpochSecond(seconds, nanos);}
+ * <li><a href="../../serialized-form.html#java.time.LocalDate">LocalDate</a> - {@code LocalDate.of(year, month, day);}
+ * <li><a href="../../serialized-form.html#java.time.LocalDateTime">LocalDateTime</a> - {@code LocalDateTime.of(date, time);}
+ * <li><a href="../../serialized-form.html#java.time.LocalTime">LocalTime</a> - {@code LocalTime.of(hour, minute, second, nano);}
+ * <li><a href="../../serialized-form.html#java.time.MonthDay">MonthDay</a> - {@code MonthDay.of(month, day);}
+ * <li><a href="../../serialized-form.html#java.time.OffsetTime">OffsetTime</a> - {@code OffsetTime.of(time, offset);}
+ * <li><a href="../../serialized-form.html#java.time.OffsetDateTime">OffsetDateTime</a> - {@code OffsetDateTime.of(dateTime, offset);}
+ * <li><a href="../../serialized-form.html#java.time.Period">Period</a> - {@code Period.of(years, months, days);}
+ * <li><a href="../../serialized-form.html#java.time.Year">Year</a> - {@code Year.of(year);}
+ * <li><a href="../../serialized-form.html#java.time.YearMonth">YearMonth</a> - {@code YearMonth.of(year, month);}
+ * <li><a href="../../serialized-form.html#java.time.ZonedDateTime">ZonedDateTime</a> - {@code ZonedDateTime.ofLenient(dateTime, offset, zone);}
+ * <li><a href="../../serialized-form.html#java.time.ZoneId">ZoneId</a> - {@code ZoneId.of(id);}
+ * <li><a href="../../serialized-form.html#java.time.ZoneOffset">ZoneOffset</a> - {@code (offsetByte == 127 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(offsetByte * 900));}
+ * </ul>
*
* @param in the data to read, not null
*/
--- a/jdk/src/share/classes/java/time/Year.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/Year.java Sat Sep 14 20:43:34 2013 +0100
@@ -74,7 +74,7 @@
import java.io.DataOutput;
import java.io.IOException;
import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.chrono.Chronology;
import java.time.chrono.IsoChronology;
@@ -1080,9 +1080,10 @@
//-----------------------------------------------------------------------
/**
* Writes the object using a
- * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+ * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+ * @serialData
* <pre>
- * out.writeByte(11); // identifies this as a Year
+ * out.writeByte(11); // identifies a Year
* out.writeInt(year);
* </pre>
*
@@ -1097,7 +1098,7 @@
* @return never
* @throws InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
--- a/jdk/src/share/classes/java/time/YearMonth.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/YearMonth.java Sat Sep 14 20:43:34 2013 +0100
@@ -77,7 +77,7 @@
import java.io.DataOutput;
import java.io.IOException;
import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.chrono.Chronology;
import java.time.chrono.IsoChronology;
@@ -1205,9 +1205,10 @@
//-----------------------------------------------------------------------
/**
* Writes the object using a
- * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+ * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+ * @serialData
* <pre>
- * out.writeByte(12); // identifies this as a YearMonth
+ * out.writeByte(12); // identifies a YearMonth
* out.writeInt(year);
* out.writeByte(month);
* </pre>
@@ -1223,7 +1224,7 @@
* @return never
* @throws InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
--- a/jdk/src/share/classes/java/time/ZoneId.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/ZoneId.java Sat Sep 14 20:43:34 2013 +0100
@@ -63,6 +63,7 @@
import java.io.DataOutput;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
@@ -662,6 +663,15 @@
//-----------------------------------------------------------------------
/**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws InvalidObjectException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ /**
* Outputs this zone as a {@code String}, using the ID.
*
* @return a string representation of this time-zone ID, not null
@@ -675,9 +685,10 @@
/**
* Writes the object using a
* <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+ * @serialData
* <pre>
- * out.writeByte(7); // identifies this as a ZoneId (not ZoneOffset)
- * out.writeUTF(zoneId);
+ * out.writeByte(7); // identifies a ZoneId (not ZoneOffset)
+ * out.writeUTF(getId());
* </pre>
* <p>
* When read back in, the {@code ZoneId} will be created as though using
--- a/jdk/src/share/classes/java/time/ZoneOffset.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/ZoneOffset.java Sat Sep 14 20:43:34 2013 +0100
@@ -70,7 +70,7 @@
import java.io.DataOutput;
import java.io.IOException;
import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.temporal.ChronoField;
import java.time.temporal.Temporal;
@@ -740,12 +740,13 @@
/**
* Writes the object using a
* <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+ * @serialData
* <pre>
- * out.writeByte(8); // identifies this as a ZoneOffset
+ * out.writeByte(8); // identifies a ZoneOffset
* int offsetByte = totalSeconds % 900 == 0 ? totalSeconds / 900 : 127;
* out.writeByte(offsetByte);
* if (offsetByte == 127) {
- * out.writeInt(totalSeconds);
+ * out.writeInt(totalSeconds);
* }
* </pre>
*
@@ -760,7 +761,7 @@
* @return never
* @throws InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
--- a/jdk/src/share/classes/java/time/ZoneRegion.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/ZoneRegion.java Sat Sep 14 20:43:34 2013 +0100
@@ -60,7 +60,7 @@
import java.io.DataOutput;
import java.io.IOException;
import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.zone.ZoneRules;
import java.time.zone.ZoneRulesException;
@@ -181,8 +181,9 @@
/**
* Writes the object using a
* <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+ * @serialData
* <pre>
- * out.writeByte(7); // identifies this as a ZoneId (not ZoneOffset)
+ * out.writeByte(7); // identifies a ZoneId (not ZoneOffset)
* out.writeUTF(zoneId);
* </pre>
*
@@ -197,7 +198,7 @@
* @return never
* @throws InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
--- a/jdk/src/share/classes/java/time/ZonedDateTime.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/ZonedDateTime.java Sat Sep 14 20:43:34 2013 +0100
@@ -69,7 +69,7 @@
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInput;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.chrono.ChronoZonedDateTime;
import java.time.format.DateTimeFormatter;
@@ -2192,9 +2192,10 @@
/**
* Writes the object using a
* <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+ * @serialData
* <pre>
- * out.writeByte(6); // identifies this as a ZonedDateTime
- * // the <a href="../../serialized-form.html#java.time.LocalDateTime">date-time</a> excluding the one byte header
+ * out.writeByte(6); // identifies a ZonedDateTime
+ * // the <a href="../../serialized-form.html#java.time.LocalDateTime">dateTime</a> excluding the one byte header
* // the <a href="../../serialized-form.html#java.time.ZoneOffset">offset</a> excluding the one byte header
* // the <a href="../../serialized-form.html#java.time.ZoneId">zone ID</a> excluding the one byte header
* </pre>
@@ -2210,7 +2211,7 @@
* @return never
* @throws InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
--- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java Sat Sep 14 20:43:34 2013 +0100
@@ -94,7 +94,7 @@
*
* @implSpec
* This class is immutable and thread-safe.
- *
+ * @serial
* @param <D> the concrete type for the date of this date-time
* @since 1.8
*/
@@ -157,11 +157,11 @@
/**
* The date part.
*/
- private final D date;
+ private final transient D date;
/**
* The time part.
*/
- private final LocalTime time;
+ private final transient LocalTime time;
//-----------------------------------------------------------------------
/**
@@ -402,6 +402,18 @@
}
//-----------------------------------------------------------------------
+ /**
+ * Writes the ChronoLocalDateTime using a
+ * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+ * @serialData
+ * <pre>
+ * out.writeByte(2); // identifies a ChronoLocalDateTime
+ * out.writeObject(toLocalDate());
+ * out.witeObject(toLocalTime());
+ * </pre>
+ *
+ * @return the instance of {@code Ser}, not null
+ */
private Object writeReplace() {
return new Ser(Ser.CHRONO_LOCAL_DATE_TIME_TYPE, this);
}
@@ -411,7 +423,7 @@
* @return never
* @throws InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
--- a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java Sat Sep 14 20:43:34 2013 +0100
@@ -98,6 +98,7 @@
* @implSpec
* This class is immutable and thread-safe.
*
+ * @serial Document the delegation of this class in the serialized-form specification.
* @param <D> the concrete type for the date of this date-time
* @since 1.8
*/
@@ -112,15 +113,15 @@
/**
* The local date-time.
*/
- private final ChronoLocalDateTimeImpl<D> dateTime;
+ private final transient ChronoLocalDateTimeImpl<D> dateTime;
/**
* The zone offset.
*/
- private final ZoneOffset offset;
+ private final transient ZoneOffset offset;
/**
* The zone ID.
*/
- private final ZoneId zone;
+ private final transient ZoneId zone;
//-----------------------------------------------------------------------
/**
@@ -222,6 +223,7 @@
}
//-----------------------------------------------------------------------
+ @Override
public ZoneOffset getOffset() {
return offset;
}
@@ -256,10 +258,12 @@
return dateTime;
}
+ @Override
public ZoneId getZone() {
return zone;
}
+ @Override
public ChronoZonedDateTime<D> withZoneSameLocal(ZoneId zone) {
return ofBest(dateTime, zone, offset);
}
@@ -321,6 +325,19 @@
}
//-----------------------------------------------------------------------
+ /**
+ * Writes the ChronoZonedDateTime using a
+ * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+ * @serialData
+ * <pre>
+ * out.writeByte(3); // identifies a ChronoZonedDateTime
+ * out.writeObject(toLocalDateTime());
+ * out.writeObject(getOffset());
+ * out.writeObject(getZone());
+ * </pre>
+ *
+ * @return the instance of {@code Ser}, not null
+ */
private Object writeReplace() {
return new Ser(Ser.CHRONO_ZONE_DATE_TIME_TYPE, this);
}
@@ -330,7 +347,7 @@
* @return never
* @throws InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
--- a/jdk/src/share/classes/java/time/chrono/Chronology.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/Chronology.java Sat Sep 14 20:43:34 2013 +0100
@@ -1258,14 +1258,15 @@
/**
* Writes the Chronology using a
* <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+ * @serialData
* <pre>
- * out.writeByte(1); // identifies this as a Chronology
+ * out.writeByte(1); // identifies a Chronology
* out.writeUTF(getId());
* </pre>
*
* @return the instance of {@code Ser}, not null
*/
- protected Object writeReplace() {
+ Object writeReplace() {
return new Ser(Ser.CHRONO_TYPE, this);
}
@@ -1274,14 +1275,26 @@
* @return never
* @throws InvalidObjectException always
*/
- private Object readResolve() throws ObjectStreamException {
+ private Object readResolve() throws InvalidObjectException {
throw new InvalidObjectException("Deserialization via serialization delegate");
}
+ /**
+ * Write the Chronology id to the stream.
+ * @param out the output stream
+ * @throws IOException on any error during the write
+ */
void writeExternal(DataOutput out) throws IOException {
out.writeUTF(getId());
}
+ /**
+ * Reads the Chronology id and creates the Chronology.
+ * @param in the input stream
+ * @return the Chronology
+ * @throws IOException on errors during the read
+ * @throws DateTimeException if the Chronology cannot be returned
+ */
static Chronology readExternal(DataInput in) throws IOException {
String id = in.readUTF();
return Chronology.of(id);
--- a/jdk/src/share/classes/java/time/chrono/HijrahChronology.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/HijrahChronology.java Sat Sep 14 20:43:34 2013 +0100
@@ -63,6 +63,8 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
import java.io.Serializable;
import java.security.AccessController;
import java.security.PrivilegedActionException;
@@ -217,11 +219,11 @@
/**
* The Hijrah Calendar id.
*/
- private final String typeId;
+ private final transient String typeId;
/**
* The Hijrah calendarType.
*/
- private transient final String calendarType;
+ private final transient String calendarType;
/**
* Serialization version.
*/
@@ -236,7 +238,7 @@
* Flag to indicate the initialization of configuration data is complete.
* @see #checkCalendarInit()
*/
- private volatile boolean initComplete;
+ private transient volatile boolean initComplete;
/**
* Array of epoch days indexed by Hijrah Epoch month.
* Computed by {@link #loadCalendarData}.
@@ -281,7 +283,7 @@
* A reference to the properties stored in
* ${java.home}/lib/calendars.properties
*/
- private transient final static Properties calendarProperties;
+ private final transient static Properties calendarProperties;
/**
* Prefix of property names for Hijrah calendar variants.
@@ -1073,4 +1075,30 @@
throw new IllegalArgumentException("date must be yyyy-MM-dd", ex);
}
}
+
+ //-----------------------------------------------------------------------
+ /**
+ * Writes the Chronology using a
+ * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+ * @serialData
+ * <pre>
+ * out.writeByte(1); // identifies a Chronology
+ * out.writeUTF(getId());
+ * </pre>
+ *
+ * @return the instance of {@code Ser}, not null
+ */
+ @Override
+ Object writeReplace() {
+ return super.writeReplace();
+ }
+
+ /**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws InvalidObjectException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
}
--- a/jdk/src/share/classes/java/time/chrono/HijrahDate.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/HijrahDate.java Sat Sep 14 20:43:34 2013 +0100
@@ -65,6 +65,7 @@
import static java.time.temporal.ChronoField.YEAR;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
@@ -118,7 +119,7 @@
/**
* The Chronology of this HijrahDate.
*/
- private final HijrahChronology chrono;
+ private final transient HijrahChronology chrono;
/**
* The proleptic year.
*/
@@ -600,29 +601,41 @@
}
//-----------------------------------------------------------------------
+ /**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws InvalidObjectException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ /**
+ * Writes the object using a
+ * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+ * @serialData
+ * <pre>
+ * out.writeByte(6); // identifies a HijrahDate
+ * out.writeObject(chrono); // the HijrahChronology variant
+ * out.writeInt(get(YEAR));
+ * out.writeByte(get(MONTH_OF_YEAR));
+ * out.writeByte(get(DAY_OF_MONTH));
+ * </pre>
+ *
+ * @return the instance of {@code Ser}, not null
+ */
private Object writeReplace() {
return new Ser(Ser.HIJRAH_DATE_TYPE, this);
}
void writeExternal(ObjectOutput out) throws IOException {
// HijrahChronology is implicit in the Hijrah_DATE_TYPE
- out.writeObject(chrono);
+ out.writeObject(getChronology());
out.writeInt(get(YEAR));
out.writeByte(get(MONTH_OF_YEAR));
out.writeByte(get(DAY_OF_MONTH));
}
- /**
- * Replaces the date instance from the stream with a valid one.
- * ReadExternal has already read the fields and created a new instance
- * from the data.
- *
- * @return the resolved date, never null
- */
- private Object readResolve() {
- return this;
- }
-
static HijrahDate readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
HijrahChronology chrono = (HijrahChronology) in.readObject();
int year = in.readInt();
--- a/jdk/src/share/classes/java/time/chrono/HijrahEra.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/HijrahEra.java Sat Sep 14 20:43:34 2013 +0100
@@ -63,9 +63,6 @@
import static java.time.temporal.ChronoField.ERA;
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
import java.time.DateTimeException;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalField;
@@ -158,18 +155,4 @@
return Era.super.range(field);
}
- //-----------------------------------------------------------------------
- private Object writeReplace() {
- return new Ser(Ser.HIJRAH_ERA_TYPE, this);
- }
-
- void writeExternal(DataOutput out) throws IOException {
- out.writeByte(this.getValue());
- }
-
- static HijrahEra readExternal(DataInput in) throws IOException {
- byte eraValue = in.readByte();
- return HijrahEra.of(eraValue);
- }
-
}
--- a/jdk/src/share/classes/java/time/chrono/IsoChronology.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/IsoChronology.java Sat Sep 14 20:43:34 2013 +0100
@@ -61,6 +61,8 @@
*/
package java.time.chrono;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.ERA;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
@@ -563,4 +565,29 @@
return field.range();
}
+ //-----------------------------------------------------------------------
+ /**
+ * Writes the Chronology using a
+ * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+ * @serialData
+ * <pre>
+ * out.writeByte(1); // identifies a Chronology
+ * out.writeUTF(getId());
+ * </pre>
+ *
+ * @return the instance of {@code Ser}, not null
+ */
+ @Override
+ Object writeReplace() {
+ return super.writeReplace();
+ }
+
+ /**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws InvalidObjectException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
}
--- a/jdk/src/share/classes/java/time/chrono/JapaneseChronology.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/JapaneseChronology.java Sat Sep 14 20:43:34 2013 +0100
@@ -56,6 +56,8 @@
*/
package java.time.chrono;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.DAY_OF_YEAR;
import static java.time.temporal.ChronoField.ERA;
@@ -503,4 +505,29 @@
return dateYearDay(era, yoe, doy); // smart is same as strict
}
+ //-----------------------------------------------------------------------
+ /**
+ * Writes the Chronology using a
+ * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+ * @serialData
+ * <pre>
+ * out.writeByte(1); // identifies a Chronology
+ * out.writeUTF(getId());
+ * </pre>
+ *
+ * @return the instance of {@code Ser}, not null
+ */
+ @Override
+ Object writeReplace() {
+ return super.writeReplace();
+ }
+
+ /**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws InvalidObjectException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
}
--- a/jdk/src/share/classes/java/time/chrono/JapaneseDate.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/JapaneseDate.java Sat Sep 14 20:43:34 2013 +0100
@@ -69,6 +69,7 @@
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
@@ -129,7 +130,7 @@
/**
* The underlying ISO local date.
*/
- private transient final LocalDate isoDate;
+ private final transient LocalDate isoDate;
/**
* The JapaneseEra of this date.
*/
@@ -689,6 +690,28 @@
}
//-----------------------------------------------------------------------
+ /**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws InvalidObjectException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ /**
+ * Writes the object using a
+ * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+ * @serialData
+ * <pre>
+ * out.writeByte(4); // identifies a JapaneseDate
+ * out.writeInt(get(YEAR));
+ * out.writeByte(get(MONTH_OF_YEAR));
+ * out.writeByte(get(DAY_OF_MONTH));
+ * </pre>
+ *
+ * @return the instance of {@code Ser}, not null
+ */
private Object writeReplace() {
return new Ser(Ser.JAPANESE_DATE_TYPE, this);
}
--- a/jdk/src/share/classes/java/time/chrono/JapaneseEra.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/JapaneseEra.java Sat Sep 14 20:43:34 2013 +0100
@@ -104,7 +104,7 @@
static final sun.util.calendar.Era[] ERA_CONFIG;
/**
- * The singleton instance for the 'Meiji' era (1868-09-08 - 1912-07-29)
+ * The singleton instance for the 'Meiji' era (1868-01-01 - 1912-07-29)
* which has the value -1.
*/
public static final JapaneseEra MEIJI = new JapaneseEra(-1, LocalDate.of(1868, 1, 1));
@@ -155,7 +155,7 @@
* The era value.
* @serial
*/
- private final int eraValue;
+ private final transient int eraValue;
// the first day of the era
private final transient LocalDate since;
@@ -371,6 +371,17 @@
}
//-----------------------------------------------------------------------
+ /**
+ * Writes the object using a
+ * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+ * @serialData
+ * <pre>
+ * out.writeByte(5); // identifies a JapaneseEra
+ * out.writeInt(getValue());
+ * </pre>
+ *
+ * @return the instance of {@code Ser}, not null
+ */
private Object writeReplace() {
return new Ser(Ser.JAPANESE_ERA_TYPE, this);
}
--- a/jdk/src/share/classes/java/time/chrono/MinguoChronology.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/MinguoChronology.java Sat Sep 14 20:43:34 2013 +0100
@@ -56,6 +56,8 @@
*/
package java.time.chrono;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
import static java.time.temporal.ChronoField.YEAR;
@@ -333,4 +335,29 @@
return (MinguoDate) super.resolveDate(fieldValues, resolverStyle);
}
+ //-----------------------------------------------------------------------
+ /**
+ * Writes the Chronology using a
+ * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+ * @serialData
+ * <pre>
+ * out.writeByte(1); // identifies a Chronology
+ * out.writeUTF(getId());
+ * </pre>
+ *
+ * @return the instance of {@code Ser}, not null
+ */
+ @Override
+ Object writeReplace() {
+ return super.writeReplace();
+ }
+
+ /**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws InvalidObjectException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
}
--- a/jdk/src/share/classes/java/time/chrono/MinguoDate.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/MinguoDate.java Sat Sep 14 20:43:34 2013 +0100
@@ -64,6 +64,7 @@
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
@@ -106,7 +107,7 @@
/**
* The underlying date.
*/
- private final LocalDate isoDate;
+ private final transient LocalDate isoDate;
//-----------------------------------------------------------------------
/**
@@ -448,6 +449,28 @@
}
//-----------------------------------------------------------------------
+ /**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws InvalidObjectException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ /**
+ * Writes the object using a
+ * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+ * @serialData
+ * <pre>
+ * out.writeByte(8); // identifies a MinguoDate
+ * out.writeInt(get(YEAR));
+ * out.writeByte(get(MONTH_OF_YEAR));
+ * out.writeByte(get(DAY_OF_MONTH));
+ * </pre>
+ *
+ * @return the instance of {@code Ser}, not null
+ */
private Object writeReplace() {
return new Ser(Ser.MINGUO_DATE_TYPE, this);
}
--- a/jdk/src/share/classes/java/time/chrono/MinguoEra.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/MinguoEra.java Sat Sep 14 20:43:34 2013 +0100
@@ -61,9 +61,6 @@
*/
package java.time.chrono;
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
import java.time.DateTimeException;
/**
@@ -155,18 +152,4 @@
return ordinal();
}
- //-----------------------------------------------------------------------
- private Object writeReplace() {
- return new Ser(Ser.MINGUO_ERA_TYPE, this);
- }
-
- void writeExternal(DataOutput out) throws IOException {
- out.writeByte(this.getValue());
- }
-
- static MinguoEra readExternal(DataInput in) throws IOException {
- byte eraValue = in.readByte();
- return MinguoEra.of(eraValue);
- }
-
}
--- a/jdk/src/share/classes/java/time/chrono/Ser.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/Ser.java Sat Sep 14 20:43:34 2013 +0100
@@ -74,14 +74,14 @@
* byte flag would be used in order to specify an alternative version of the type format.
* For example {@code CHRONO_TYPE_VERSION_2 = 21}
* <p>
- * In order to serialise the object it writes its byte and then calls back to the appropriate class where
- * the serialisation is performed. In order to deserialise the object it read in the type byte, switching
+ * In order to serialize the object it writes its byte and then calls back to the appropriate class where
+ * the serialization is performed. In order to deserialize the object it read in the type byte, switching
* in order to select which class to call back into.
* <p>
- * The serialisation format is determined on a per class basis. In the case of field based classes each
+ * The serialization format is determined on a per class basis. In the case of field based classes each
* of the fields is written out with an appropriate size format in descending order of the field's size. For
* example in the case of {@link LocalDate} year is written before month. Composite classes, such as
- * {@link LocalDateTime} are serialised as one object. Enum classes are serialised using the index of their
+ * {@link LocalDateTime} are serialized as one object. Enum classes are serialized using the index of their
* element.
* <p>
* This class is mutable and should be created once per serialization.
@@ -102,11 +102,8 @@
static final byte JAPANESE_DATE_TYPE = 4;
static final byte JAPANESE_ERA_TYPE = 5;
static final byte HIJRAH_DATE_TYPE = 6;
- static final byte HIJRAH_ERA_TYPE = 7;
- static final byte MINGUO_DATE_TYPE = 8;
- static final byte MINGUO_ERA_TYPE = 9;
- static final byte THAIBUDDHIST_DATE_TYPE = 10;
- static final byte THAIBUDDHIST_ERA_TYPE = 11;
+ static final byte MINGUO_DATE_TYPE = 7;
+ static final byte THAIBUDDHIST_DATE_TYPE = 8;
/** The type being serialized. */
private byte type;
@@ -133,6 +130,24 @@
//-----------------------------------------------------------------------
/**
* Implements the {@code Externalizable} interface to write the object.
+ * @serialData
+ * Each serializable class is mapped to a type that is the first byte
+ * in the stream. Refer to each class {@code writeReplace}
+ * serialized form for the value of the type and sequence of values for the type.
+ * <ul>
+ * <li><a href="../../../serialized-form.html#java.time.chrono.HijrahChronology">HijrahChronology.writeReplace</a>
+ * <li><a href="../../../serialized-form.html#java.time.chrono.IsoChronology">IsoChronology.writeReplace</a>
+ * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseChronology">JapaneseChronology.writeReplace</a>
+ * <li><a href="../../../serialized-form.html#java.time.chrono.MinguoChronology">MinguoChronology.writeReplace</a>
+ * <li><a href="../../../serialized-form.html#java.time.chrono.ThaiBuddhistChronology">ThaiBuddhistChronology.writeReplace</a>
+ * <li><a href="../../../serialized-form.html#java.time.chrono.ChronoLocalDateTimeImpl">ChronoLocalDateTime.writeReplace</a>
+ * <li><a href="../../../serialized-form.html#java.time.chrono.ChronoZonedDateTimeImpl">ChronoZonedDateTime.writeReplace</a>
+ * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseDate">JapaneseDate.writeReplace</a>
+ * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseEra">JapaneseEra.writeReplace</a>
+ * <li><a href="../../../serialized-form.html#java.time.chrono.HijrahDate">HijrahDate.writeReplace</a>
+ * <li><a href="../../../serialized-form.html#java.time.chrono.MinguoDate">MinguoDate.writeReplace</a>
+ * <li><a href="../../../serialized-form.html#java.time.chrono.ThaiBuddhistDate">ThaiBuddhistDate.writeReplace</a>
+ * </ul>
*
* @param out the data stream to write to, not null
*/
@@ -162,21 +177,12 @@
case HIJRAH_DATE_TYPE:
((HijrahDate) object).writeExternal(out);
break;
- case HIJRAH_ERA_TYPE:
- ((HijrahEra) object).writeExternal(out);
- break;
case MINGUO_DATE_TYPE:
((MinguoDate) object).writeExternal(out);
break;
- case MINGUO_ERA_TYPE:
- ((MinguoEra) object).writeExternal(out);
- break;
case THAIBUDDHIST_DATE_TYPE:
((ThaiBuddhistDate) object).writeExternal(out);
break;
- case THAIBUDDHIST_ERA_TYPE:
- ((ThaiBuddhistEra) object).writeExternal(out);
- break;
default:
throw new InvalidClassException("Unknown serialized type");
}
@@ -185,8 +191,28 @@
//-----------------------------------------------------------------------
/**
* Implements the {@code Externalizable} interface to read the object.
+ * @serialData
+ * The streamed type and parameters defined by the type's {@code writeReplace}
+ * method are read and passed to the corresponding static factory for the type
+ * to create a new instance. That instance is returned as the de-serialized
+ * {@code Ser} object.
*
- * @param in the data to read, not null
+ * <ul>
+ * <li><a href="../../../serialized-form.html#java.time.chrono.HijrahChronology">HijrahChronology</a> - Chronology.of(id)
+ * <li><a href="../../../serialized-form.html#java.time.chrono.IsoChronology">IsoChronology</a> - Chronology.of(id)
+ * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseChronology">JapaneseChronology</a> - Chronology.of(id)
+ * <li><a href="../../../serialized-form.html#java.time.chrono.MinguoChronology">MinguoChronology</a> - Chronology.of(id)
+ * <li><a href="../../../serialized-form.html#java.time.chrono.ThaiBuddhistChronology">ThaiBuddhistChronology</a> - Chronology.of(id)
+ * <li><a href="../../../serialized-form.html#java.time.chrono.ChronoLocalDateTimeImpl">ChronoLocalDateTime</a> - date.atTime(time)
+ * <li><a href="../../../serialized-form.html#java.time.chrono.ChronoZonedDateTimeImpl">ChronoZonedDateTime</a> - dateTime.atZone(offset).withZoneSameLocal(zone)
+ * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseDate">JapaneseDate</a> - JapaneseChronology.INSTANCE.date(year, month, dayOfMonth)
+ * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseEra">JapaneseEra</a> - JapaneseEra.of(eraValue)
+ * <li><a href="../../../serialized-form.html#java.time.chrono.HijrahDate">HijrahDate</a> - HijrahChronology chrono.date(year, month, dayOfMonth)
+ * <li><a href="../../../serialized-form.html#java.time.chrono.MinguoDate">MinguoDate</a> - MinguoChronology.INSTANCE.date(year, month, dayOfMonth)
+ * <li><a href="../../../serialized-form.html#java.time.chrono.ThaiBuddhistDate">ThaiBuddhistDate</a> - ThaiBuddhistChronology.INSTANCE.date(year, month, dayOfMonth)
+ * </ul>
+ *
+ * @param in the data stream to read from, not null
*/
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
@@ -207,11 +233,8 @@
case JAPANESE_DATE_TYPE: return JapaneseDate.readExternal(in);
case JAPANESE_ERA_TYPE: return JapaneseEra.readExternal(in);
case HIJRAH_DATE_TYPE: return HijrahDate.readExternal(in);
- case HIJRAH_ERA_TYPE: return HijrahEra.readExternal(in);
case MINGUO_DATE_TYPE: return MinguoDate.readExternal(in);
- case MINGUO_ERA_TYPE: return MinguoEra.readExternal(in);
case THAIBUDDHIST_DATE_TYPE: return ThaiBuddhistDate.readExternal(in);
- case THAIBUDDHIST_ERA_TYPE: return ThaiBuddhistEra.readExternal(in);
default: throw new StreamCorruptedException("Unknown serialized type");
}
}
--- a/jdk/src/share/classes/java/time/chrono/ThaiBuddhistChronology.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistChronology.java Sat Sep 14 20:43:34 2013 +0100
@@ -56,6 +56,8 @@
*/
package java.time.chrono;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
import static java.time.temporal.ChronoField.YEAR;
@@ -369,4 +371,29 @@
return (ThaiBuddhistDate) super.resolveDate(fieldValues, resolverStyle);
}
+ //-----------------------------------------------------------------------
+ /**
+ * Writes the Chronology using a
+ * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+ * @serialData
+ * <pre>
+ * out.writeByte(1); // identifies a Chronology
+ * out.writeUTF(getId());
+ * </pre>
+ *
+ * @return the instance of {@code Ser}, not null
+ */
+ @Override
+ Object writeReplace() {
+ return super.writeReplace();
+ }
+
+ /**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws InvalidObjectException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
}
--- a/jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java Sat Sep 14 20:43:34 2013 +0100
@@ -64,6 +64,7 @@
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
@@ -106,7 +107,7 @@
/**
* The underlying date.
*/
- private final LocalDate isoDate;
+ private final transient LocalDate isoDate;
//-----------------------------------------------------------------------
/**
@@ -448,6 +449,28 @@
}
//-----------------------------------------------------------------------
+ /**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws InvalidObjectException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ /**
+ * Writes the object using a
+ * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+ * @serialData
+ * <pre>
+ * out.writeByte(10); // identifies a ThaiBuddhistDate
+ * out.writeInt(get(YEAR));
+ * out.writeByte(get(MONTH_OF_YEAR));
+ * out.writeByte(get(DAY_OF_MONTH));
+ * </pre>
+ *
+ * @return the instance of {@code Ser}, not null
+ */
private Object writeReplace() {
return new Ser(Ser.THAIBUDDHIST_DATE_TYPE, this);
}
--- a/jdk/src/share/classes/java/time/chrono/ThaiBuddhistEra.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistEra.java Sat Sep 14 20:43:34 2013 +0100
@@ -61,9 +61,6 @@
*/
package java.time.chrono;
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
import java.time.DateTimeException;
/**
@@ -155,18 +152,4 @@
return ordinal();
}
- //-----------------------------------------------------------------------
- private Object writeReplace() {
- return new Ser(Ser.THAIBUDDHIST_ERA_TYPE, this);
- }
-
- void writeExternal(DataOutput out) throws IOException {
- out.writeByte(this.getValue());
- }
-
- static ThaiBuddhistEra readExternal(DataInput in) throws IOException {
- byte eraValue = in.readByte();
- return ThaiBuddhistEra.of(eraValue);
- }
-
}
--- a/jdk/src/share/classes/java/time/zone/Ser.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/zone/Ser.java Sat Sep 14 20:43:34 2013 +0100
@@ -119,9 +119,20 @@
//-----------------------------------------------------------------------
/**
* Implements the {@code Externalizable} interface to write the object.
+ * @serialData
+ * Each serializable class is mapped to a type that is the first byte
+ * in the stream. Refer to each class {@code writeReplace}
+ * serialized form for the value of the type and sequence of values for the type.
+ *
+ * <ul>
+ * <li><a href="../../../serialized-form.html#java.time.zone.ZoneRules">ZoneRules.writeReplace</a>
+ * <li><a href="../../../serialized-form.html#java.time.zone.ZoneOffsetTransition">ZoneOffsetTransition.writeReplace</a>
+ * <li><a href="../../../serialized-form.html#java.time.zone.ZoneOffsetTransitionRule">ZoneOffsetTransitionRule.writeReplace</a>
+ * </ul>
*
* @param out the data stream to write to, not null
*/
+ @Override
public void writeExternal(ObjectOutput out) throws IOException {
writeInternal(type, object, out);
}
@@ -150,9 +161,23 @@
//-----------------------------------------------------------------------
/**
* Implements the {@code Externalizable} interface to read the object.
+ * @serialData
+ * The streamed type and parameters defined by the type's {@code writeReplace}
+ * method are read and passed to the corresponding static factory for the type
+ * to create a new instance. That instance is returned as the de-serialized
+ * {@code Ser} object.
*
+ * <ul>
+ * <li><a href="../../../serialized-form.html#java.time.zone.ZoneRules">ZoneRules</a>
+ * - {@code ZoneRules.of(standardTransitions, standardOffsets, savingsInstantTransitions, wallOffsets, lastRules);}
+ * <li><a href="../../../serialized-form.html#java.time.zone.ZoneOffsetTransition">ZoneOffsetTransition</a>
+ * - {@code ;}
+ * <li><a href="../../../serialized-form.html#java.time.zone.ZoneOffsetTransitionRule">ZoneOffsetTransitionRule</a>
+ * - {@code ;}
+ * </ul>
* @param in the data to read, not null
*/
+ @Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
type = in.readByte();
object = readInternal(type, in);
--- a/jdk/src/share/classes/java/time/zone/ZoneOffsetTransition.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/zone/ZoneOffsetTransition.java Sat Sep 14 20:43:34 2013 +0100
@@ -64,6 +64,7 @@
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.Duration;
import java.time.Instant;
@@ -170,8 +171,29 @@
//-----------------------------------------------------------------------
/**
- * Uses a serialization delegate.
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws InvalidObjectException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ /**
+ * Writes the object using a
+ * <a href="../../../serialized-form.html#java.time.zone.Ser">dedicated serialized form</a>.
+ * @serialData
+ * Refer to the serialized form of
+ * <a href="../../../serialized-form.html#java.time.zone.ZoneRules">ZoneRules.writeReplace</a>
+ * for the encoding of epoch seconds and offsets.
+ * <pre style="font-size:1.0em">{@code
*
+ * out.writeByte(2); // identifies a ZoneOffsetTransition
+ * out.writeEpochSec(toEpochSecond);
+ * out.writeOffset(offsetBefore);
+ * out.writeOfset(offsetAfter);
+ * }
+ * </pre>
* @return the replacing object, not null
*/
private Object writeReplace() {
--- a/jdk/src/share/classes/java/time/zone/ZoneOffsetTransitionRule.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/zone/ZoneOffsetTransitionRule.java Sat Sep 14 20:43:34 2013 +0100
@@ -67,6 +67,7 @@
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.DayOfWeek;
import java.time.LocalDate;
@@ -231,7 +232,56 @@
//-----------------------------------------------------------------------
/**
- * Uses a serialization delegate.
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws InvalidObjectException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ /**
+ * Writes the object using a
+ * <a href="../../../serialized-form.html#java.time.zone.Ser">dedicated serialized form</a>.
+ * @serialData
+ * Refer to the serialized form of
+ * <a href="../../../serialized-form.html#java.time.zone.ZoneRules">ZoneRules.writeReplace</a>
+ * for the encoding of epoch seconds and offsets.
+ * <pre style="font-size:1.0em">{@code
+ *
+ * out.writeByte(3); // identifies a ZoneOffsetTransition
+ * final int timeSecs = (timeEndOfDay ? 86400 : time.toSecondOfDay());
+ * final int stdOffset = standardOffset.getTotalSeconds();
+ * final int beforeDiff = offsetBefore.getTotalSeconds() - stdOffset;
+ * final int afterDiff = offsetAfter.getTotalSeconds() - stdOffset;
+ * final int timeByte = (timeSecs % 3600 == 0 ? (timeEndOfDay ? 24 : time.getHour()) : 31);
+ * final int stdOffsetByte = (stdOffset % 900 == 0 ? stdOffset / 900 + 128 : 255);
+ * final int beforeByte = (beforeDiff == 0 || beforeDiff == 1800 || beforeDiff == 3600 ? beforeDiff / 1800 : 3);
+ * final int afterByte = (afterDiff == 0 || afterDiff == 1800 || afterDiff == 3600 ? afterDiff / 1800 : 3);
+ * final int dowByte = (dow == null ? 0 : dow.getValue());
+ * int b = (month.getValue() << 28) + // 4 bits
+ * ((dom + 32) << 22) + // 6 bits
+ * (dowByte << 19) + // 3 bits
+ * (timeByte << 14) + // 5 bits
+ * (timeDefinition.ordinal() << 12) + // 2 bits
+ * (stdOffsetByte << 4) + // 8 bits
+ * (beforeByte << 2) + // 2 bits
+ * afterByte; // 2 bits
+ * out.writeInt(b);
+ * if (timeByte == 31) {
+ * out.writeInt(timeSecs);
+ * }
+ * if (stdOffsetByte == 255) {
+ * out.writeInt(stdOffset);
+ * }
+ * if (beforeByte == 3) {
+ * out.writeInt(offsetBefore.getTotalSeconds());
+ * }
+ * if (afterByte == 3) {
+ * out.writeInt(offsetAfter.getTotalSeconds());
+ * }
+ * }
+ * </pre>
*
* @return the replacing object, not null
*/
--- a/jdk/src/share/classes/java/time/zone/ZoneRules.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/time/zone/ZoneRules.java Sat Sep 14 20:43:34 2013 +0100
@@ -64,6 +64,7 @@
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.time.Duration;
import java.time.Instant;
@@ -145,7 +146,7 @@
/**
* The map of recent transitions.
*/
- private final ConcurrentMap<Integer, ZoneOffsetTransition[]> lastRulesCache =
+ private final transient ConcurrentMap<Integer, ZoneOffsetTransition[]> lastRulesCache =
new ConcurrentHashMap<Integer, ZoneOffsetTransition[]>();
/**
* The zero-length long array.
@@ -315,8 +316,74 @@
}
/**
- * Uses a serialization delegate.
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws InvalidObjectException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ /**
+ * Writes the object using a
+ * <a href="../../../serialized-form.html#java.time.zone.Ser">dedicated serialized form</a>.
+ * @serialData
+ * <pre style="font-size:1.0em">{@code
*
+ * out.writeByte(1); // identifies a ZoneRules
+ * out.writeInt(standardTransitions.length);
+ * for (long trans : standardTransitions) {
+ * Ser.writeEpochSec(trans, out);
+ * }
+ * for (ZoneOffset offset : standardOffsets) {
+ * Ser.writeOffset(offset, out);
+ * }
+ * out.writeInt(savingsInstantTransitions.length);
+ * for (long trans : savingsInstantTransitions) {
+ * Ser.writeEpochSec(trans, out);
+ * }
+ * for (ZoneOffset offset : wallOffsets) {
+ * Ser.writeOffset(offset, out);
+ * }
+ * out.writeByte(lastRules.length);
+ * for (ZoneOffsetTransitionRule rule : lastRules) {
+ * rule.writeExternal(out);
+ * }
+ * }
+ * </pre>
+ * <p>
+ * Epoch second values used for offsets are encoded in a variable
+ * length form to make the common cases put fewer bytes in the stream.
+ * <pre style="font-size:1.0em">{@code
+ *
+ * static void writeEpochSec(long epochSec, DataOutput out) throws IOException {
+ * if (epochSec >= -4575744000L && epochSec < 10413792000L && epochSec % 900 == 0) { // quarter hours between 1825 and 2300
+ * int store = (int) ((epochSec + 4575744000L) / 900);
+ * out.writeByte((store >>> 16) & 255);
+ * out.writeByte((store >>> 8) & 255);
+ * out.writeByte(store & 255);
+ * } else {
+ * out.writeByte(255);
+ * out.writeLong(epochSec);
+ * }
+ * }
+ * }
+ * </pre>
+ * <p>
+ * ZoneOffset values are encoded in a variable length form so the
+ * common cases put fewer bytes in the stream.
+ * <pre style="font-size:1.0em">{@code
+ *
+ * static void writeOffset(ZoneOffset offset, DataOutput out) throws IOException {
+ * final int offsetSecs = offset.getTotalSeconds();
+ * int offsetByte = offsetSecs % 900 == 0 ? offsetSecs / 900 : 127; // compress to -72 to +72
+ * out.writeByte(offsetByte);
+ * if (offsetByte == 127) {
+ * out.writeInt(offsetSecs);
+ * }
+ * }
+ *}
+ * </pre>
* @return the replacing object, not null
*/
private Object writeReplace() {
--- a/jdk/src/share/classes/java/util/Collection.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/Collection.java Sat Sep 14 20:43:34 2013 +0100
@@ -549,6 +549,7 @@
* @return a {@code Spliterator} over the elements in this collection
* @since 1.8
*/
+ @Override
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, 0);
}
--- a/jdk/src/share/classes/java/util/Collections.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/Collections.java Sat Sep 14 20:43:34 2013 +0100
@@ -3900,6 +3900,7 @@
return batchRemove(c, true);
}
private boolean batchRemove(Collection<?> c, boolean complement) {
+ Objects.requireNonNull(c);
boolean modified = false;
Iterator<Map.Entry<K,V>> it = iterator();
while (it.hasNext()) {
--- a/jdk/src/share/classes/java/util/Comparator.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/Comparator.java Sat Sep 14 20:43:34 2013 +0100
@@ -230,7 +230,7 @@
* @param keyComparator the {@code Comparator} used to compare the sort key
* @return a lexicographic-order comparator composed of this comparator
* and then comparing on the key extracted by the keyExtractor function
- * @throws NullPointerException if the argument is null.
+ * @throws NullPointerException if either argument is null.
* @see #comparing(Function, Comparator)
* @see #thenComparing(Comparator)
* @since 1.8
--- a/jdk/src/share/classes/java/util/HashMap.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/HashMap.java Sat Sep 14 20:43:34 2013 +0100
@@ -25,13 +25,14 @@
package java.util;
-import java.io.*;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
-import java.util.concurrent.ThreadLocalRandom;
import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
import java.util.function.Consumer;
-import java.util.function.BiFunction;
import java.util.function.Function;
/**
@@ -63,20 +64,25 @@
* structures are rebuilt) so that the hash table has approximately twice the
* number of buckets.
*
- * <p>As a general rule, the default load factor (.75) offers a good tradeoff
- * between time and space costs. Higher values decrease the space overhead
- * but increase the lookup cost (reflected in most of the operations of the
- * <tt>HashMap</tt> class, including <tt>get</tt> and <tt>put</tt>). The
- * expected number of entries in the map and its load factor should be taken
- * into account when setting its initial capacity, so as to minimize the
- * number of rehash operations. If the initial capacity is greater
- * than the maximum number of entries divided by the load factor, no
- * rehash operations will ever occur.
+ * <p>As a general rule, the default load factor (.75) offers a good
+ * tradeoff between time and space costs. Higher values decrease the
+ * space overhead but increase the lookup cost (reflected in most of
+ * the operations of the <tt>HashMap</tt> class, including
+ * <tt>get</tt> and <tt>put</tt>). The expected number of entries in
+ * the map and its load factor should be taken into account when
+ * setting its initial capacity, so as to minimize the number of
+ * rehash operations. If the initial capacity is greater than the
+ * maximum number of entries divided by the load factor, no rehash
+ * operations will ever occur.
*
- * <p>If many mappings are to be stored in a <tt>HashMap</tt> instance,
- * creating it with a sufficiently large capacity will allow the mappings to
- * be stored more efficiently than letting it perform automatic rehashing as
- * needed to grow the table.
+ * <p>If many mappings are to be stored in a <tt>HashMap</tt>
+ * instance, creating it with a sufficiently large capacity will allow
+ * the mappings to be stored more efficiently than letting it perform
+ * automatic rehashing as needed to grow the table. Note that using
+ * many keys with the same {@code hashCode()} is a sure way to slow
+ * down performance of any hash table. To ameliorate impact, when keys
+ * are {@link Comparable}, this class may use comparison order among
+ * keys to help break ties.
*
* <p><strong>Note that this implementation is not synchronized.</strong>
* If multiple threads access a hash map concurrently, and at least one of
@@ -128,11 +134,100 @@
* @see Hashtable
* @since 1.2
*/
+public class HashMap<K,V> extends AbstractMap<K,V>
+ implements Map<K,V>, Cloneable, Serializable {
-public class HashMap<K,V>
- extends AbstractMap<K,V>
- implements Map<K,V>, Cloneable, Serializable
-{
+ private static final long serialVersionUID = 362498820763181265L;
+
+ /*
+ * Implementation notes.
+ *
+ * This map usually acts as a binned (bucketed) hash table, but
+ * when bins get too large, they are transformed into bins of
+ * TreeNodes, each structured similarly to those in
+ * java.util.TreeMap. Most methods try to use normal bins, but
+ * relay to TreeNode methods when applicable (simply by checking
+ * instanceof a node). Bins of TreeNodes may be traversed and
+ * used like any others, but additionally support faster lookup
+ * when overpopulated. However, since the vast majority of bins in
+ * normal use are not overpopulated, checking for existence of
+ * tree bins may be delayed in the course of table methods.
+ *
+ * Tree bins (i.e., bins whose elements are all TreeNodes) are
+ * ordered primarily by hashCode, but in the case of ties, if two
+ * elements are of the same "class C implements Comparable<C>",
+ * type then their compareTo method is used for ordering. (We
+ * conservatively check generic types via reflection to validate
+ * this -- see method comparableClassFor). The added complexity
+ * of tree bins is worthwhile in providing worst-case O(log n)
+ * operations when keys either have distinct hashes or are
+ * orderable, Thus, performance degrades gracefully under
+ * accidental or malicious usages in which hashCode() methods
+ * return values that are poorly distributed, as well as those in
+ * which many keys share a hashCode, so long as they are also
+ * Comparable. (If neither of these apply, we may waste about a
+ * factor of two in time and space compared to taking no
+ * precautions. But the only known cases stem from poor user
+ * programming practices that are already so slow that this makes
+ * little difference.)
+ *
+ * Because TreeNodes are about twice the size of regular nodes, we
+ * use them only when bins contain enough nodes to warrant use
+ * (see TREEIFY_THRESHOLD). And when they become too small (due to
+ * removal or resizing) they are converted back to plain bins. In
+ * usages with well-distributed user hashCodes, tree bins are
+ * rarely used. Ideally, under random hashCodes, the frequency of
+ * nodes in bins follows a Poisson distribution
+ * (http://en.wikipedia.org/wiki/Poisson_distribution) with a
+ * parameter of about 0.5 on average for the default resizing
+ * threshold of 0.75, although with a large variance because of
+ * resizing granularity. Ignoring variance, the expected
+ * occurrences of list size k are (exp(-0.5) * pow(0.5, k) /
+ * factorial(k)). The first values are:
+ *
+ * 0: 0.60653066
+ * 1: 0.30326533
+ * 2: 0.07581633
+ * 3: 0.01263606
+ * 4: 0.00157952
+ * 5: 0.00015795
+ * 6: 0.00001316
+ * 7: 0.00000094
+ * 8: 0.00000006
+ * more: less than 1 in ten million
+ *
+ * The root of a tree bin is normally its first node. However,
+ * sometimes (currently only upon Iterator.remove), the root might
+ * be elsewhere, but can be recovered following parent links
+ * (method TreeNode.root()).
+ *
+ * All applicable internal methods accept a hash code as an
+ * argument (as normally supplied from a public method), allowing
+ * them to call each other without recomputing user hashCodes.
+ * Most internal methods also accept a "tab" argument, that is
+ * normally the current table, but may be a new or old one when
+ * resizing or converting.
+ *
+ * When bin lists are treeified, split, or untreeified, we keep
+ * them in the same relative access/traversal order (i.e., field
+ * Node.next) to better preserve locality, and to slightly
+ * simplify handling of splits and traversals that invoke
+ * iterator.remove. When using comparators on insertion, to keep a
+ * total ordering (or as close as is required here) across
+ * rebalancings, we compare classes and identityHashCodes as
+ * tie-breakers.
+ *
+ * The use and transitions among plain vs tree modes is
+ * complicated by the existence of subclass LinkedHashMap. See
+ * below for hook methods defined to be invoked upon insertion,
+ * removal and access that allow LinkedHashMap internals to
+ * otherwise remain independent of these mechanics. (This also
+ * requires that a map instance be passed to some utility methods
+ * that may create new nodes.)
+ *
+ * The concurrent-programming-like SSA-based coding style helps
+ * avoid aliasing errors amid all of the twisty pointer operations.
+ */
/**
* The default initial capacity - MUST be a power of two.
@@ -152,14 +247,158 @@
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
- * An empty table instance to share when the table is not inflated.
+ * The bin count threshold for using a tree rather than list for a
+ * bin. Bins are converted to trees when adding an element to a
+ * bin with at least this many nodes. The value must be greater
+ * than 2 and should be at least 8 to mesh with assumptions in
+ * tree removal about conversion back to plain bins upon
+ * shrinkage.
+ */
+ static final int TREEIFY_THRESHOLD = 8;
+
+ /**
+ * The bin count threshold for untreeifying a (split) bin during a
+ * resize operation. Should be less than TREEIFY_THRESHOLD, and at
+ * most 6 to mesh with shrinkage detection under removal.
+ */
+ static final int UNTREEIFY_THRESHOLD = 6;
+
+ /**
+ * The smallest table capacity for which bins may be treeified.
+ * (Otherwise the table is resized if too many nodes in a bin.)
+ * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
+ * between resizing and treeification thresholds.
+ */
+ static final int MIN_TREEIFY_CAPACITY = 64;
+
+ /**
+ * Basic hash bin node, used for most entries. (See below for
+ * TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
*/
- static final Object[] EMPTY_TABLE = {};
+ static class Node<K,V> implements Map.Entry<K,V> {
+ final int hash;
+ final K key;
+ V value;
+ Node<K,V> next;
+
+ Node(int hash, K key, V value, Node<K,V> next) {
+ this.hash = hash;
+ this.key = key;
+ this.value = value;
+ this.next = next;
+ }
+
+ public final K getKey() { return key; }
+ public final V getValue() { return value; }
+ public final String toString() { return key + "=" + value; }
+
+ public final int hashCode() {
+ return Objects.hashCode(key) ^ Objects.hashCode(value);
+ }
+
+ public final V setValue(V newValue) {
+ V oldValue = value;
+ value = newValue;
+ return oldValue;
+ }
+
+ public final boolean equals(Object o) {
+ if (o == this)
+ return true;
+ if (o instanceof Map.Entry) {
+ Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+ if (Objects.equals(key, e.getKey()) &&
+ Objects.equals(value, e.getValue()))
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /* ---------------- Static utilities -------------- */
/**
- * The table, resized as necessary. Length MUST Always be a power of two.
+ * Computes key.hashCode() and spreads (XORs) higher bits of hash
+ * to lower. Because the table uses power-of-two masking, sets of
+ * hashes that vary only in bits above the current mask will
+ * always collide. (Among known examples are sets of Float keys
+ * holding consecutive whole numbers in small tables.) So we
+ * apply a transform that spreads the impact of higher bits
+ * downward. There is a tradeoff between speed, utility, and
+ * quality of bit-spreading. Because many common sets of hashes
+ * are already reasonably distributed (so don't benefit from
+ * spreading), and because we use trees to handle large sets of
+ * collisions in bins, we just XOR some shifted bits in the
+ * cheapest possible way to reduce systematic lossage, as well as
+ * to incorporate impact of the highest bits that would otherwise
+ * never be used in index calculations because of table bounds.
+ */
+ static final int hash(Object key) {
+ int h;
+ return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
+ }
+
+ /**
+ * Returns x's Class if it is of the form "class C implements
+ * Comparable<C>", else null.
*/
- transient Object[] table = EMPTY_TABLE;
+ static Class<?> comparableClassFor(Object x) {
+ if (x instanceof Comparable) {
+ Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
+ if ((c = x.getClass()) == String.class) // bypass checks
+ return c;
+ if ((ts = c.getGenericInterfaces()) != null) {
+ for (int i = 0; i < ts.length; ++i) {
+ if (((t = ts[i]) instanceof ParameterizedType) &&
+ ((p = (ParameterizedType)t).getRawType() ==
+ Comparable.class) &&
+ (as = p.getActualTypeArguments()) != null &&
+ as.length == 1 && as[0] == c) // type arg is c
+ return c;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns k.compareTo(x) if x matches kc (k's screened comparable
+ * class), else 0.
+ */
+ @SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
+ static int compareComparables(Class<?> kc, Object k, Object x) {
+ return (x == null || x.getClass() != kc ? 0 :
+ ((Comparable)k).compareTo(x));
+ }
+
+ /**
+ * Returns a power of two size for the given target capacity.
+ */
+ static final int tableSizeFor(int cap) {
+ int n = cap - 1;
+ n |= n >>> 1;
+ n |= n >>> 2;
+ n |= n >>> 4;
+ n |= n >>> 8;
+ n |= n >>> 16;
+ return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
+ }
+
+ /* ---------------- Fields -------------- */
+
+ /**
+ * The table, initialized on first use, and resized as
+ * necessary. When allocated, length is always a power of two.
+ * (We also tolerate length zero in some operations to allow
+ * bootstrapping mechanics that are currently not needed.)
+ */
+ transient Node<K,V>[] table;
+
+ /**
+ * Holds cached entrySet(). Note that AbstractMap fields are used
+ * for keySet() and values().
+ */
+ transient Set<Map.Entry<K,V>> entrySet;
/**
* The number of key-value mappings contained in this map.
@@ -167,21 +406,6 @@
transient int size;
/**
- * The next size value at which to resize (capacity * load factor).
- * @serial
- */
- // If table == EMPTY_TABLE then this is the initial capacity at which the
- // table will be created when inflated.
- int threshold;
-
- /**
- * The load factor for the hash table.
- *
- * @serial
- */
- final float loadFactor;
-
- /**
* The number of times this HashMap has been structurally modified
* Structural modifications are those that change the number of mappings in
* the HashMap or otherwise modify its internal structure (e.g.,
@@ -191,627 +415,24 @@
transient int modCount;
/**
- * Holds values which can't be initialized until after VM is booted.
+ * The next size value at which to resize (capacity * load factor).
+ *
+ * @serial
*/
- private static class Holder {
- static final sun.misc.Unsafe UNSAFE;
-
- /**
- * Offset of "final" hashSeed field we must set in
- * readObject() method.
- */
- static final long HASHSEED_OFFSET;
-
- static final boolean USE_HASHSEED;
-
- static {
- String hashSeedProp = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction(
- "jdk.map.useRandomSeed"));
- boolean localBool = (null != hashSeedProp)
- ? Boolean.parseBoolean(hashSeedProp) : false;
- USE_HASHSEED = localBool;
-
- if (USE_HASHSEED) {
- try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- HASHSEED_OFFSET = UNSAFE.objectFieldOffset(
- HashMap.class.getDeclaredField("hashSeed"));
- } catch (NoSuchFieldException | SecurityException e) {
- throw new InternalError("Failed to record hashSeed offset", e);
- }
- } else {
- UNSAFE = null;
- HASHSEED_OFFSET = 0;
- }
- }
- }
-
- /*
- * A randomizing value associated with this instance that is applied to
- * hash code of keys to make hash collisions harder to find.
- *
- * Non-final so it can be set lazily, but be sure not to set more than once.
- */
- transient final int hashSeed;
-
- /*
- * TreeBin/TreeNode code from CHM doesn't handle the null key. Store the
- * null key entry here.
- */
- transient Entry<K,V> nullKeyEntry = null;
-
- /*
- * In order to improve performance under high hash-collision conditions,
- * HashMap will switch to storing a bin's entries in a balanced tree
- * (TreeBin) instead of a linked-list once the number of entries in the bin
- * passes a certain threshold (TreeBin.TREE_THRESHOLD), if at least one of
- * the keys in the bin implements Comparable. This technique is borrowed
- * from ConcurrentHashMap.
- */
-
- /*
- * Code based on CHMv8
- *
- * Node type for TreeBin
- */
- final static class TreeNode<K,V> {
- TreeNode parent; // red-black tree links
- TreeNode left;
- TreeNode right;
- TreeNode prev; // needed to unlink next upon deletion
- boolean red;
- final HashMap.Entry<K,V> entry;
-
- TreeNode(HashMap.Entry<K,V> entry, Object next, TreeNode parent) {
- this.entry = entry;
- this.entry.next = next;
- this.parent = parent;
- }
- }
+ // (The javadoc description is true upon serialization.
+ // Additionally, if the table array has not been allocated, this
+ // field holds the initial array capacity, or zero signifying
+ // DEFAULT_INITIAL_CAPACITY.)
+ int threshold;
/**
- * Returns a Class for the given object of the form "class C
- * implements Comparable<C>", if one exists, else null. See the TreeBin
- * docs, below, for explanation.
- */
- static Class<?> comparableClassFor(Object x) {
- Class<?> c, s, cmpc; Type[] ts, as; Type t; ParameterizedType p;
- if ((c = x.getClass()) == String.class) // bypass checks
- return c;
- if ((cmpc = Comparable.class).isAssignableFrom(c)) {
- while (cmpc.isAssignableFrom(s = c.getSuperclass()))
- c = s; // find topmost comparable class
- if ((ts = c.getGenericInterfaces()) != null) {
- for (int i = 0; i < ts.length; ++i) {
- if (((t = ts[i]) instanceof ParameterizedType) &&
- ((p = (ParameterizedType)t).getRawType() == cmpc) &&
- (as = p.getActualTypeArguments()) != null &&
- as.length == 1 && as[0] == c) // type arg is c
- return c;
- }
- }
- }
- return null;
- }
-
- /*
- * Code based on CHMv8
+ * The load factor for the hash table.
*
- * A specialized form of red-black tree for use in bins
- * whose size exceeds a threshold.
- *
- * TreeBins use a special form of comparison for search and
- * related operations (which is the main reason we cannot use
- * existing collections such as TreeMaps). TreeBins contain
- * Comparable elements, but may contain others, as well as
- * elements that are Comparable but not necessarily Comparable<T>
- * for the same T, so we cannot invoke compareTo among them. To
- * handle this, the tree is ordered primarily by hash value, then
- * by Comparable.compareTo order if applicable. On lookup at a
- * node, if elements are not comparable or compare as 0 then both
- * left and right children may need to be searched in the case of
- * tied hash values. (This corresponds to the full list search
- * that would be necessary if all elements were non-Comparable and
- * had tied hashes.) The red-black balancing code is updated from
- * pre-jdk-collections
- * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java)
- * based in turn on Cormen, Leiserson, and Rivest "Introduction to
- * Algorithms" (CLR).
+ * @serial
*/
- final class TreeBin {
- /*
- * The bin count threshold for using a tree rather than list for a bin. The
- * value reflects the approximate break-even point for using tree-based
- * operations.
- */
- static final int TREE_THRESHOLD = 16;
-
- TreeNode<K,V> root; // root of tree
- TreeNode<K,V> first; // head of next-pointer list
-
- /*
- * Split a TreeBin into lo and hi parts and install in given table.
- *
- * Existing Entrys are re-used, which maintains the before/after links for
- * LinkedHashMap.Entry.
- *
- * No check for Comparable, though this is the same as CHM.
- */
- final void splitTreeBin(Object[] newTable, int i, TreeBin loTree, TreeBin hiTree) {
- TreeBin oldTree = this;
- int bit = newTable.length >>> 1;
- int loCount = 0, hiCount = 0;
- TreeNode<K,V> e = oldTree.first;
- TreeNode<K,V> next;
-
- // This method is called when the table has just increased capacity,
- // so indexFor() is now taking one additional bit of hash into
- // account ("bit"). Entries in this TreeBin now belong in one of
- // two bins, "i" or "i+bit", depending on if the new top bit of the
- // hash is set. The trees for the two bins are loTree and hiTree.
- // If either tree ends up containing fewer than TREE_THRESHOLD
- // entries, it is converted back to a linked list.
- while (e != null) {
- // Save entry.next - it will get overwritten in putTreeNode()
- next = (TreeNode<K,V>)e.entry.next;
-
- int h = e.entry.hash;
- K k = (K) e.entry.key;
- V v = e.entry.value;
- if ((h & bit) == 0) {
- ++loCount;
- // Re-using e.entry
- loTree.putTreeNode(h, k, v, e.entry);
- } else {
- ++hiCount;
- hiTree.putTreeNode(h, k, v, e.entry);
- }
- // Iterate using the saved 'next'
- e = next;
- }
- if (loCount < TREE_THRESHOLD) { // too small, convert back to list
- HashMap.Entry loEntry = null;
- TreeNode<K,V> p = loTree.first;
- while (p != null) {
- @SuppressWarnings("unchecked")
- TreeNode<K,V> savedNext = (TreeNode<K,V>) p.entry.next;
- p.entry.next = loEntry;
- loEntry = p.entry;
- p = savedNext;
- }
- // assert newTable[i] == null;
- newTable[i] = loEntry;
- } else {
- // assert newTable[i] == null;
- newTable[i] = loTree;
- }
- if (hiCount < TREE_THRESHOLD) { // too small, convert back to list
- HashMap.Entry hiEntry = null;
- TreeNode<K,V> p = hiTree.first;
- while (p != null) {
- @SuppressWarnings("unchecked")
- TreeNode<K,V> savedNext = (TreeNode<K,V>) p.entry.next;
- p.entry.next = hiEntry;
- hiEntry = p.entry;
- p = savedNext;
- }
- // assert newTable[i + bit] == null;
- newTable[i + bit] = hiEntry;
- } else {
- // assert newTable[i + bit] == null;
- newTable[i + bit] = hiTree;
- }
- }
-
- /*
- * Popuplate the TreeBin with entries from the linked list e
- *
- * Assumes 'this' is a new/empty TreeBin
- *
- * Note: no check for Comparable
- * Note: I believe this changes iteration order
- */
- @SuppressWarnings("unchecked")
- void populate(HashMap.Entry e) {
- // assert root == null;
- // assert first == null;
- HashMap.Entry next;
- while (e != null) {
- // Save entry.next - it will get overwritten in putTreeNode()
- next = (HashMap.Entry)e.next;
- // Re-using Entry e will maintain before/after in LinkedHM
- putTreeNode(e.hash, (K)e.key, (V)e.value, e);
- // Iterate using the saved 'next'
- e = next;
- }
- }
-
- /**
- * Copied from CHMv8
- * From CLR
- */
- private void rotateLeft(TreeNode p) {
- if (p != null) {
- TreeNode r = p.right, pp, rl;
- if ((rl = p.right = r.left) != null) {
- rl.parent = p;
- }
- if ((pp = r.parent = p.parent) == null) {
- root = r;
- } else if (pp.left == p) {
- pp.left = r;
- } else {
- pp.right = r;
- }
- r.left = p;
- p.parent = r;
- }
- }
-
- /**
- * Copied from CHMv8
- * From CLR
- */
- private void rotateRight(TreeNode p) {
- if (p != null) {
- TreeNode l = p.left, pp, lr;
- if ((lr = p.left = l.right) != null) {
- lr.parent = p;
- }
- if ((pp = l.parent = p.parent) == null) {
- root = l;
- } else if (pp.right == p) {
- pp.right = l;
- } else {
- pp.left = l;
- }
- l.right = p;
- p.parent = l;
- }
- }
-
- /**
- * Returns the TreeNode (or null if not found) for the given
- * key. A front-end for recursive version.
- */
- final TreeNode getTreeNode(int h, K k) {
- return getTreeNode(h, k, root, comparableClassFor(k));
- }
-
- /**
- * Returns the TreeNode (or null if not found) for the given key
- * starting at given root.
- */
- @SuppressWarnings("unchecked")
- final TreeNode getTreeNode (int h, K k, TreeNode p, Class<?> cc) {
- // assert k != null;
- while (p != null) {
- int dir, ph; Object pk;
- if ((ph = p.entry.hash) != h)
- dir = (h < ph) ? -1 : 1;
- else if ((pk = p.entry.key) == k || k.equals(pk))
- return p;
- else if (cc == null || comparableClassFor(pk) != cc ||
- (dir = ((Comparable<Object>)k).compareTo(pk)) == 0) {
- // assert pk != null;
- TreeNode r, pl, pr; // check both sides
- if ((pr = p.right) != null &&
- (r = getTreeNode(h, k, pr, cc)) != null)
- return r;
- else if ((pl = p.left) != null)
- dir = -1;
- else // nothing there
- break;
- }
- p = (dir > 0) ? p.right : p.left;
- }
- return null;
- }
+ final float loadFactor;
- /*
- * Finds or adds a node.
- *
- * 'entry' should be used to recycle an existing Entry (e.g. in the case
- * of converting a linked-list bin to a TreeBin).
- * If entry is null, a new Entry will be created for the new TreeNode
- *
- * @return the TreeNode containing the mapping, or null if a new
- * TreeNode was added
- */
- @SuppressWarnings("unchecked")
- TreeNode putTreeNode(int h, K k, V v, HashMap.Entry<K,V> entry) {
- // assert k != null;
- //if (entry != null) {
- // assert h == entry.hash;
- // assert k == entry.key;
- // assert v == entry.value;
- // }
- Class<?> cc = comparableClassFor(k);
- TreeNode pp = root, p = null;
- int dir = 0;
- while (pp != null) { // find existing node or leaf to insert at
- int ph; Object pk;
- p = pp;
- if ((ph = p.entry.hash) != h)
- dir = (h < ph) ? -1 : 1;
- else if ((pk = p.entry.key) == k || k.equals(pk))
- return p;
- else if (cc == null || comparableClassFor(pk) != cc ||
- (dir = ((Comparable<Object>)k).compareTo(pk)) == 0) {
- TreeNode r, pr;
- if ((pr = p.right) != null &&
- (r = getTreeNode(h, k, pr, cc)) != null)
- return r;
- else // continue left
- dir = -1;
- }
- pp = (dir > 0) ? p.right : p.left;
- }
-
- // Didn't find the mapping in the tree, so add it
- TreeNode f = first;
- TreeNode x;
- if (entry != null) {
- x = new TreeNode(entry, f, p);
- } else {
- x = new TreeNode(newEntry(h, k, v, null), f, p);
- }
- first = x;
-
- if (p == null) {
- root = x;
- } else { // attach and rebalance; adapted from CLR
- TreeNode xp, xpp;
- if (f != null) {
- f.prev = x;
- }
- if (dir <= 0) {
- p.left = x;
- } else {
- p.right = x;
- }
- x.red = true;
- while (x != null && (xp = x.parent) != null && xp.red
- && (xpp = xp.parent) != null) {
- TreeNode xppl = xpp.left;
- if (xp == xppl) {
- TreeNode y = xpp.right;
- if (y != null && y.red) {
- y.red = false;
- xp.red = false;
- xpp.red = true;
- x = xpp;
- } else {
- if (x == xp.right) {
- rotateLeft(x = xp);
- xpp = (xp = x.parent) == null ? null : xp.parent;
- }
- if (xp != null) {
- xp.red = false;
- if (xpp != null) {
- xpp.red = true;
- rotateRight(xpp);
- }
- }
- }
- } else {
- TreeNode y = xppl;
- if (y != null && y.red) {
- y.red = false;
- xp.red = false;
- xpp.red = true;
- x = xpp;
- } else {
- if (x == xp.left) {
- rotateRight(x = xp);
- xpp = (xp = x.parent) == null ? null : xp.parent;
- }
- if (xp != null) {
- xp.red = false;
- if (xpp != null) {
- xpp.red = true;
- rotateLeft(xpp);
- }
- }
- }
- }
- }
- TreeNode r = root;
- if (r != null && r.red) {
- r.red = false;
- }
- }
- return null;
- }
-
- /*
- * From CHMv8
- *
- * Removes the given node, that must be present before this
- * call. This is messier than typical red-black deletion code
- * because we cannot swap the contents of an interior node
- * with a leaf successor that is pinned by "next" pointers
- * that are accessible independently of lock. So instead we
- * swap the tree linkages.
- */
- final void deleteTreeNode(TreeNode p) {
- TreeNode next = (TreeNode) p.entry.next; // unlink traversal pointers
- TreeNode pred = p.prev;
- if (pred == null) {
- first = next;
- } else {
- pred.entry.next = next;
- }
- if (next != null) {
- next.prev = pred;
- }
- TreeNode replacement;
- TreeNode pl = p.left;
- TreeNode pr = p.right;
- if (pl != null && pr != null) {
- TreeNode s = pr, sl;
- while ((sl = s.left) != null) // find successor
- {
- s = sl;
- }
- boolean c = s.red;
- s.red = p.red;
- p.red = c; // swap colors
- TreeNode sr = s.right;
- TreeNode pp = p.parent;
- if (s == pr) { // p was s's direct parent
- p.parent = s;
- s.right = p;
- } else {
- TreeNode sp = s.parent;
- if ((p.parent = sp) != null) {
- if (s == sp.left) {
- sp.left = p;
- } else {
- sp.right = p;
- }
- }
- if ((s.right = pr) != null) {
- pr.parent = s;
- }
- }
- p.left = null;
- if ((p.right = sr) != null) {
- sr.parent = p;
- }
- if ((s.left = pl) != null) {
- pl.parent = s;
- }
- if ((s.parent = pp) == null) {
- root = s;
- } else if (p == pp.left) {
- pp.left = s;
- } else {
- pp.right = s;
- }
- replacement = sr;
- } else {
- replacement = (pl != null) ? pl : pr;
- }
- TreeNode pp = p.parent;
- if (replacement == null) {
- if (pp == null) {
- root = null;
- return;
- }
- replacement = p;
- } else {
- replacement.parent = pp;
- if (pp == null) {
- root = replacement;
- } else if (p == pp.left) {
- pp.left = replacement;
- } else {
- pp.right = replacement;
- }
- p.left = p.right = p.parent = null;
- }
- if (!p.red) { // rebalance, from CLR
- TreeNode x = replacement;
- while (x != null) {
- TreeNode xp, xpl;
- if (x.red || (xp = x.parent) == null) {
- x.red = false;
- break;
- }
- if (x == (xpl = xp.left)) {
- TreeNode sib = xp.right;
- if (sib != null && sib.red) {
- sib.red = false;
- xp.red = true;
- rotateLeft(xp);
- sib = (xp = x.parent) == null ? null : xp.right;
- }
- if (sib == null) {
- x = xp;
- } else {
- TreeNode sl = sib.left, sr = sib.right;
- if ((sr == null || !sr.red)
- && (sl == null || !sl.red)) {
- sib.red = true;
- x = xp;
- } else {
- if (sr == null || !sr.red) {
- if (sl != null) {
- sl.red = false;
- }
- sib.red = true;
- rotateRight(sib);
- sib = (xp = x.parent) == null ?
- null : xp.right;
- }
- if (sib != null) {
- sib.red = (xp == null) ? false : xp.red;
- if ((sr = sib.right) != null) {
- sr.red = false;
- }
- }
- if (xp != null) {
- xp.red = false;
- rotateLeft(xp);
- }
- x = root;
- }
- }
- } else { // symmetric
- TreeNode sib = xpl;
- if (sib != null && sib.red) {
- sib.red = false;
- xp.red = true;
- rotateRight(xp);
- sib = (xp = x.parent) == null ? null : xp.left;
- }
- if (sib == null) {
- x = xp;
- } else {
- TreeNode sl = sib.left, sr = sib.right;
- if ((sl == null || !sl.red)
- && (sr == null || !sr.red)) {
- sib.red = true;
- x = xp;
- } else {
- if (sl == null || !sl.red) {
- if (sr != null) {
- sr.red = false;
- }
- sib.red = true;
- rotateLeft(sib);
- sib = (xp = x.parent) == null ?
- null : xp.left;
- }
- if (sib != null) {
- sib.red = (xp == null) ? false : xp.red;
- if ((sl = sib.left) != null) {
- sl.red = false;
- }
- }
- if (xp != null) {
- xp.red = false;
- rotateRight(xp);
- }
- x = root;
- }
- }
- }
- }
- }
- if (p == replacement && (pp = p.parent) != null) {
- if (p == pp.left) // detach pointers
- {
- pp.left = null;
- } else if (p == pp.right) {
- pp.right = null;
- }
- p.parent = null;
- }
- }
- }
+ /* ---------------- Public operations -------------- */
/**
* Constructs an empty <tt>HashMap</tt> with the specified initial
@@ -832,9 +453,7 @@
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
- threshold = initialCapacity;
- hashSeed = initHashSeed();
- init();
+ this.threshold = tableSizeFor(initialCapacity);
}
/**
@@ -853,7 +472,7 @@
* (16) and the default load factor (0.75).
*/
public HashMap() {
- this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
+ this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
/**
@@ -866,79 +485,35 @@
* @throws NullPointerException if the specified map is null
*/
public HashMap(Map<? extends K, ? extends V> m) {
- this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
- DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
- inflateTable(threshold);
-
- putAllForCreate(m);
- // assert size == m.size();
- }
-
- private static int roundUpToPowerOf2(int number) {
- // assert number >= 0 : "number must be non-negative";
- return number >= MAXIMUM_CAPACITY
- ? MAXIMUM_CAPACITY
- : (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1;
+ this.loadFactor = DEFAULT_LOAD_FACTOR;
+ putMapEntries(m, false);
}
/**
- * Inflates the table.
- */
- private void inflateTable(int toSize) {
- // Find a power of 2 >= toSize
- int capacity = roundUpToPowerOf2(toSize);
-
- threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
- table = new Object[capacity];
- }
-
- // internal utilities
-
- /**
- * Initialization hook for subclasses. This method is called
- * in all constructors and pseudo-constructors (clone, readObject)
- * after HashMap has been initialized but before any entries have
- * been inserted. (In the absence of this method, readObject would
- * require explicit knowledge of subclasses.)
- */
- void init() {
- }
-
- /**
- * Return an initial value for the hashSeed, or 0 if the random seed is not
- * enabled.
+ * Implements Map.putAll and Map constructor
+ *
+ * @param m the map
+ * @param evict false when initially constructing this map, else
+ * true (relayed to method afterNodeInsertion).
*/
- final int initHashSeed() {
- if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) {
- int seed = ThreadLocalRandom.current().nextInt();
- return (seed != 0) ? seed : 1;
+ final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
+ int s = m.size();
+ if (s > 0) {
+ if (table == null) { // pre-size
+ float ft = ((float)s / loadFactor) + 1.0F;
+ int t = ((ft < (float)MAXIMUM_CAPACITY) ?
+ (int)ft : MAXIMUM_CAPACITY);
+ if (t > threshold)
+ threshold = tableSizeFor(t);
+ }
+ else if (s > threshold)
+ resize();
+ for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
+ K key = e.getKey();
+ V value = e.getValue();
+ putVal(hash(key), key, value, false, evict);
+ }
}
- return 0;
- }
-
- /**
- * Retrieve object hash code and applies a supplemental hash function to the
- * result hash, which defends against poor quality hash functions. This is
- * critical because HashMap uses power-of-two length hash tables, that
- * otherwise encounter collisions for hashCodes that do not differ
- * in lower bits.
- */
- final int hash(Object k) {
- int h = hashSeed ^ k.hashCode();
-
- // This function ensures that hashCodes that differ only by
- // constant multiples at each bit position have a bounded
- // number of collisions (approximately 8 at default load factor).
- h ^= (h >>> 20) ^ (h >>> 12);
- return h ^ (h >>> 7) ^ (h >>> 4);
- }
-
- /**
- * Returns index for hash code h.
- */
- static int indexFor(int h, int length) {
- // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
- return h & (length-1);
}
/**
@@ -976,18 +551,36 @@
*
* @see #put(Object, Object)
*/
- @SuppressWarnings("unchecked")
public V get(Object key) {
- Entry<K,V> entry = getEntry(key);
-
- return null == entry ? null : entry.getValue();
+ Node<K,V> e;
+ return (e = getNode(hash(key), key)) == null ? null : e.value;
}
- @Override
- public V getOrDefault(Object key, V defaultValue) {
- Entry<K,V> entry = getEntry(key);
-
- return (entry == null) ? defaultValue : entry.getValue();
+ /**
+ * Implements Map.get and related methods
+ *
+ * @param hash hash for key
+ * @param key the key
+ * @return the node, or null if none
+ */
+ final Node<K,V> getNode(int hash, Object key) {
+ Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
+ if ((tab = table) != null && (n = tab.length) > 0 &&
+ (first = tab[(n - 1) & hash]) != null) {
+ if (first.hash == hash && // always check first node
+ ((k = first.key) == key || (key != null && key.equals(k))))
+ return first;
+ if ((e = first.next) != null) {
+ if (first instanceof TreeNode)
+ return ((TreeNode<K,V>)first).getTreeNode(hash, key);
+ do {
+ if (e.hash == hash &&
+ ((k = e.key) == key || (key != null && key.equals(k))))
+ return e;
+ } while ((e = e.next) != null);
+ }
+ }
+ return null;
}
/**
@@ -999,49 +592,10 @@
* key.
*/
public boolean containsKey(Object key) {
- return getEntry(key) != null;
+ return getNode(hash(key), key) != null;
}
/**
- * Returns the entry associated with the specified key in the
- * HashMap. Returns null if the HashMap contains no mapping
- * for the key.
- */
- @SuppressWarnings("unchecked")
- final Entry<K,V> getEntry(Object key) {
- if (size == 0) {
- return null;
- }
- if (key == null) {
- return nullKeyEntry;
- }
- int hash = hash(key);
- int bin = indexFor(hash, table.length);
-
- if (table[bin] instanceof Entry) {
- Entry<K,V> e = (Entry<K,V>) table[bin];
- for (; e != null; e = (Entry<K,V>)e.next) {
- Object k;
- if (e.hash == hash &&
- ((k = e.key) == key || key.equals(k))) {
- return e;
- }
- }
- } else if (table[bin] != null) {
- TreeBin e = (TreeBin)table[bin];
- TreeNode p = e.getTreeNode(hash, (K)key);
- if (p != null) {
- // assert p.entry.hash == hash && p.entry.key.equals(key);
- return (Entry<K,V>)p.entry;
- } else {
- return null;
- }
- }
- return null;
- }
-
-
- /**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
@@ -1053,202 +607,169 @@
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
- @SuppressWarnings("unchecked")
public V put(K key, V value) {
- if (table == EMPTY_TABLE) {
- inflateTable(threshold);
- }
- if (key == null)
- return putForNullKey(value);
- int hash = hash(key);
- int i = indexFor(hash, table.length);
- boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
+ return putVal(hash(key), key, value, false, true);
+ }
- if (table[i] instanceof Entry) {
- // Bin contains ordinary Entries. Search for key in the linked list
- // of entries, counting the number of entries. Only check for
- // TreeBin conversion if the list size is >= TREE_THRESHOLD.
- // (The conversion still may not happen if the table gets resized.)
- int listSize = 0;
- Entry<K,V> e = (Entry<K,V>) table[i];
- for (; e != null; e = (Entry<K,V>)e.next) {
- Object k;
- if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
- V oldValue = e.value;
+ /**
+ * Implements Map.put and related methods
+ *
+ * @param hash hash for key
+ * @param key the key
+ * @param value the value to put
+ * @param onlyIfAbsent if true, don't change existing value
+ * @param evict if false, the table is in creation mode.
+ * @return previous value, or null if none
+ */
+ final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
+ boolean evict) {
+ Node<K,V>[] tab; Node<K,V> p; int n, i;
+ if (size > threshold || (tab = table) == null ||
+ (n = tab.length) == 0)
+ n = (tab = resize()).length;
+ if ((p = tab[i = (n - 1) & hash]) == null)
+ tab[i] = newNode(hash, key, value, null);
+ else {
+ Node<K,V> e; K k;
+ if (p.hash == hash &&
+ ((k = p.key) == key || (key != null && key.equals(k))))
+ e = p;
+ else if (p instanceof TreeNode)
+ e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
+ else {
+ for (int binCount = 0; ; ++binCount) {
+ if ((e = p.next) == null) {
+ p.next = newNode(hash, key, value, null);
+ if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
+ treeifyBin(tab, hash);
+ break;
+ }
+ if (e.hash == hash &&
+ ((k = e.key) == key || (key != null && key.equals(k))))
+ break;
+ p = e;
+ }
+ }
+ if (e != null) { // existing mapping for key
+ V oldValue = e.value;
+ if (!onlyIfAbsent || oldValue == null)
e.value = value;
- e.recordAccess(this);
- return oldValue;
- }
- listSize++;
- }
- // Didn't find, so fall through and call addEntry() to add the
- // Entry and check for TreeBin conversion.
- checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
- } else if (table[i] != null) {
- TreeBin e = (TreeBin)table[i];
- TreeNode p = e.putTreeNode(hash, key, value, null);
- if (p == null) { // putTreeNode() added a new node
- modCount++;
- size++;
- if (size >= threshold) {
- resize(2 * table.length);
- }
- return null;
- } else { // putTreeNode() found an existing node
- Entry<K,V> pEntry = (Entry<K,V>)p.entry;
- V oldVal = pEntry.value;
- pEntry.value = value;
- pEntry.recordAccess(this);
- return oldVal;
+ afterNodeAccess(e);
+ return oldValue;
}
}
- modCount++;
- addEntry(hash, key, value, i, checkIfNeedTree);
+ ++modCount;
+ ++size;
+ afterNodeInsertion(evict);
return null;
}
/**
- * Offloaded version of put for null keys
+ * Initializes or doubles table size. If null, allocates in
+ * accord with initial capacity target held in field threshold.
+ * Otherwise, because we are using power-of-two expansion, the
+ * elements from each bin must either stay at same index, or move
+ * with a power of two offset in the new table.
+ *
+ * @return the table
*/
- private V putForNullKey(V value) {
- if (nullKeyEntry != null) {
- V oldValue = nullKeyEntry.value;
- nullKeyEntry.value = value;
- nullKeyEntry.recordAccess(this);
- return oldValue;
+ final Node<K,V>[] resize() {
+ Node<K,V>[] oldTab = table;
+ int oldCap = (oldTab == null) ? 0 : oldTab.length;
+ int oldThr = threshold;
+ int newCap, newThr = 0;
+ if (oldCap > 0) {
+ if (oldCap >= MAXIMUM_CAPACITY) {
+ threshold = Integer.MAX_VALUE;
+ return oldTab;
+ }
+ else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
+ oldCap >= DEFAULT_INITIAL_CAPACITY)
+ newThr = oldThr << 1; // double threshold
}
- modCount++;
- size++; // newEntry() skips size++
- nullKeyEntry = newEntry(0, null, value, null);
- return null;
- }
-
- private void putForCreateNullKey(V value) {
- // Look for preexisting entry for key. This will never happen for
- // clone or deserialize. It will only happen for construction if the
- // input Map is a sorted map whose ordering is inconsistent w/ equals.
- if (nullKeyEntry != null) {
- nullKeyEntry.value = value;
- } else {
- nullKeyEntry = newEntry(0, null, value, null);
- size++;
+ else if (oldThr > 0) // initial capacity was placed in threshold
+ newCap = oldThr;
+ else { // zero initial threshold signifies using defaults
+ newCap = DEFAULT_INITIAL_CAPACITY;
+ newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
- }
-
-
- /**
- * This method is used instead of put by constructors and
- * pseudoconstructors (clone, readObject). It does not resize the table,
- * check for comodification, etc, though it will convert bins to TreeBins
- * as needed. It calls createEntry rather than addEntry.
- */
- @SuppressWarnings("unchecked")
- private void putForCreate(K key, V value) {
- if (null == key) {
- putForCreateNullKey(value);
- return;
+ if (newThr == 0) {
+ float ft = (float)newCap * loadFactor;
+ newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
+ (int)ft : Integer.MAX_VALUE);
}
- int hash = hash(key);
- int i = indexFor(hash, table.length);
- boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
-
- /**
- * Look for preexisting entry for key. This will never happen for
- * clone or deserialize. It will only happen for construction if the
- * input Map is a sorted map whose ordering is inconsistent w/ equals.
- */
- if (table[i] instanceof Entry) {
- int listSize = 0;
- Entry<K,V> e = (Entry<K,V>) table[i];
- for (; e != null; e = (Entry<K,V>)e.next) {
- Object k;
- if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
- e.value = value;
- return;
+ threshold = newThr;
+ @SuppressWarnings({"rawtypes","unchecked"})
+ Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
+ table = newTab;
+ if (oldTab != null) {
+ for (int j = 0; j < oldCap; ++j) {
+ Node<K,V> e;
+ if ((e = oldTab[j]) != null) {
+ oldTab[j] = null;
+ if (e.next == null)
+ newTab[e.hash & (newCap - 1)] = e;
+ else if (e instanceof TreeNode)
+ ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
+ else { // preserve order
+ Node<K,V> loHead = null, loTail = null;
+ Node<K,V> hiHead = null, hiTail = null;
+ Node<K,V> next;
+ do {
+ next = e.next;
+ if ((e.hash & oldCap) == 0) {
+ if (loTail == null)
+ loHead = e;
+ else
+ loTail.next = e;
+ loTail = e;
+ }
+ else {
+ if (hiTail == null)
+ hiHead = e;
+ else
+ hiTail.next = e;
+ hiTail = e;
+ }
+ } while ((e = next) != null);
+ if (loTail != null) {
+ loTail.next = null;
+ newTab[j] = loHead;
+ }
+ if (hiTail != null) {
+ hiTail.next = null;
+ newTab[j + oldCap] = hiHead;
+ }
+ }
}
- listSize++;
}
- // Didn't find, fall through to createEntry().
- // Check for conversion to TreeBin done via createEntry().
- checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
- } else if (table[i] != null) {
- TreeBin e = (TreeBin)table[i];
- TreeNode p = e.putTreeNode(hash, key, value, null);
- if (p != null) {
- p.entry.setValue(value); // Found an existing node, set value
- } else {
- size++; // Added a new TreeNode, so update size
- }
- // don't need modCount++/check for resize - just return
- return;
}
-
- createEntry(hash, key, value, i, checkIfNeedTree);
- }
-
- private void putAllForCreate(Map<? extends K, ? extends V> m) {
- for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
- putForCreate(e.getKey(), e.getValue());
+ return newTab;
}
/**
- * Rehashes the contents of this map into a new array with a
- * larger capacity. This method is called automatically when the
- * number of keys in this map reaches its threshold.
- *
- * If current capacity is MAXIMUM_CAPACITY, this method does not
- * resize the map, but sets threshold to Integer.MAX_VALUE.
- * This has the effect of preventing future calls.
- *
- * @param newCapacity the new capacity, MUST be a power of two;
- * must be greater than current capacity unless current
- * capacity is MAXIMUM_CAPACITY (in which case value
- * is irrelevant).
+ * Replaces all linked nodes in bin at index for given hash unless
+ * table is too small, in which case resizes instead.
*/
- void resize(int newCapacity) {
- Object[] oldTable = table;
- int oldCapacity = oldTable.length;
- if (oldCapacity == MAXIMUM_CAPACITY) {
- threshold = Integer.MAX_VALUE;
- return;
+ final void treeifyBin(Node<K,V>[] tab, int hash) {
+ int n, index; Node<K,V> e;
+ if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
+ resize();
+ else if ((e = tab[index = (n - 1) & hash]) != null) {
+ TreeNode<K,V> hd = null, tl = null;
+ do {
+ TreeNode<K,V> p = replacementTreeNode(e, null);
+ if (tl == null)
+ hd = p;
+ else {
+ p.prev = tl;
+ tl.next = p;
+ }
+ tl = p;
+ } while ((e = e.next) != null);
+ if ((tab[index] = hd) != null)
+ hd.treeify(tab);
}
-
- Object[] newTable = new Object[newCapacity];
- transfer(newTable);
- table = newTable;
- threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
- }
-
- /**
- * Transfers all entries from current table to newTable.
- *
- * Assumes newTable is larger than table
- */
- @SuppressWarnings("unchecked")
- void transfer(Object[] newTable) {
- Object[] src = table;
- // assert newTable.length > src.length : "newTable.length(" +
- // newTable.length + ") expected to be > src.length("+src.length+")";
- int newCapacity = newTable.length;
- for (int j = 0; j < src.length; j++) {
- if (src[j] instanceof Entry) {
- // Assume: since wasn't TreeBin before, won't need TreeBin now
- Entry<K,V> e = (Entry<K,V>) src[j];
- while (null != e) {
- Entry<K,V> next = (Entry<K,V>)e.next;
- int i = indexFor(e.hash, newCapacity);
- e.next = (Entry<K,V>) newTable[i];
- newTable[i] = e;
- e = next;
- }
- } else if (src[j] != null) {
- TreeBin e = (TreeBin) src[j];
- TreeBin loTree = new TreeBin();
- TreeBin hiTree = new TreeBin();
- e.splitTreeBin(newTable, j, loTree, hiTree);
- }
- }
- Arrays.fill(table, null);
}
/**
@@ -1260,30 +781,8 @@
* @throws NullPointerException if the specified map is null
*/
public void putAll(Map<? extends K, ? extends V> m) {
- int numKeysToBeAdded = m.size();
- if (numKeysToBeAdded == 0)
- return;
-
- if (table == EMPTY_TABLE) {
- inflateTable((int) Math.max(numKeysToBeAdded * loadFactor, threshold));
- }
-
- /*
- * Expand the map if the map if the number of mappings to be added
- * is greater than or equal to threshold. This is conservative; the
- * obvious condition is (m.size() + size) >= threshold, but this
- * condition could result in a map with twice the appropriate capacity,
- * if the keys to be added overlap with the keys already in this map.
- * By using the conservative calculation, we subject ourself
- * to at most one extra resize.
- */
- if (numKeysToBeAdded > threshold && table.length < MAXIMUM_CAPACITY) {
- resize(table.length * 2);
- }
-
- for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
- put(e.getKey(), e.getValue());
- }
+ putMapEntries(m, true);
+ }
/**
* Removes the mapping for the specified key from this map if present.
@@ -1295,834 +794,74 @@
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
public V remove(Object key) {
- Entry<K,V> e = removeEntryForKey(key);
- return (e == null ? null : e.value);
- }
-
- // optimized implementations of default methods in Map
-
- @Override
- public void forEach(BiConsumer<? super K, ? super V> action) {
- Objects.requireNonNull(action);
- final int expectedModCount = modCount;
- if (nullKeyEntry != null) {
- forEachNullKey(expectedModCount, action);
- }
- Object[] tab = this.table;
- for (int index = 0; index < tab.length; index++) {
- Object item = tab[index];
- if (item == null) {
- continue;
- }
- if (item instanceof HashMap.TreeBin) {
- eachTreeNode(expectedModCount, ((TreeBin)item).first, action);
- continue;
- }
- @SuppressWarnings("unchecked")
- Entry<K, V> entry = (Entry<K, V>)item;
- while (entry != null) {
- action.accept(entry.key, entry.value);
- entry = (Entry<K, V>)entry.next;
-
- if (expectedModCount != modCount) {
- throw new ConcurrentModificationException();
- }
- }
- }
- }
-
- private void eachTreeNode(int expectedModCount, TreeNode<K, V> node, BiConsumer<? super K, ? super V> action) {
- while (node != null) {
- @SuppressWarnings("unchecked")
- Entry<K, V> entry = (Entry<K, V>)node.entry;
- action.accept(entry.key, entry.value);
- node = (TreeNode<K, V>)entry.next;
-
- if (expectedModCount != modCount) {
- throw new ConcurrentModificationException();
- }
- }
- }
-
- private void forEachNullKey(int expectedModCount, BiConsumer<? super K, ? super V> action) {
- action.accept(null, nullKeyEntry.value);
-
- if (expectedModCount != modCount) {
- throw new ConcurrentModificationException();
- }
- }
-
- @Override
- public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
- Objects.requireNonNull(function);
- final int expectedModCount = modCount;
- if (nullKeyEntry != null) {
- replaceforNullKey(expectedModCount, function);
- }
- Object[] tab = this.table;
- for (int index = 0; index < tab.length; index++) {
- Object item = tab[index];
- if (item == null) {
- continue;
- }
- if (item instanceof HashMap.TreeBin) {
- replaceEachTreeNode(expectedModCount, ((TreeBin)item).first, function);
- continue;
- }
- @SuppressWarnings("unchecked")
- Entry<K, V> entry = (Entry<K, V>)item;
- while (entry != null) {
- entry.value = function.apply(entry.key, entry.value);
- entry = (Entry<K, V>)entry.next;
-
- if (expectedModCount != modCount) {
- throw new ConcurrentModificationException();
- }
- }
- }
- }
-
- private void replaceEachTreeNode(int expectedModCount, TreeNode<K, V> node, BiFunction<? super K, ? super V, ? extends V> function) {
- while (node != null) {
- @SuppressWarnings("unchecked")
- Entry<K, V> entry = (Entry<K, V>)node.entry;
- entry.value = function.apply(entry.key, entry.value);
- node = (TreeNode<K, V>)entry.next;
-
- if (expectedModCount != modCount) {
- throw new ConcurrentModificationException();
- }
- }
- }
-
- private void replaceforNullKey(int expectedModCount, BiFunction<? super K, ? super V, ? extends V> function) {
- nullKeyEntry.value = function.apply(null, nullKeyEntry.value);
-
- if (expectedModCount != modCount) {
- throw new ConcurrentModificationException();
- }
+ Node<K,V> e;
+ return (e = removeNode(hash(key), key, null, false, true)) == null ?
+ null : e.value;
}
- @Override
- public V putIfAbsent(K key, V value) {
- if (table == EMPTY_TABLE) {
- inflateTable(threshold);
- }
- if (key == null) {
- if (nullKeyEntry == null || nullKeyEntry.value == null) {
- putForNullKey(value);
- return null;
- } else {
- return nullKeyEntry.value;
- }
- }
- int hash = hash(key);
- int i = indexFor(hash, table.length);
- boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
-
- if (table[i] instanceof Entry) {
- int listSize = 0;
- Entry<K,V> e = (Entry<K,V>) table[i];
- for (; e != null; e = (Entry<K,V>)e.next) {
- if (e.hash == hash && Objects.equals(e.key, key)) {
- if (e.value != null) {
- return e.value;
- }
- e.value = value;
- e.recordAccess(this);
- return null;
- }
- listSize++;
- }
- // Didn't find, so fall through and call addEntry() to add the
- // Entry and check for TreeBin conversion.
- checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
- } else if (table[i] != null) {
- TreeBin e = (TreeBin)table[i];
- TreeNode p = e.putTreeNode(hash, key, value, null);
- if (p == null) { // not found, putTreeNode() added a new node
- modCount++;
- size++;
- if (size >= threshold) {
- resize(2 * table.length);
- }
- return null;
- } else { // putTreeNode() found an existing node
- Entry<K,V> pEntry = (Entry<K,V>)p.entry;
- V oldVal = pEntry.value;
- if (oldVal == null) { // only replace if maps to null
- pEntry.value = value;
- pEntry.recordAccess(this);
- }
- return oldVal;
- }
- }
- modCount++;
- addEntry(hash, key, value, i, checkIfNeedTree);
- return null;
- }
-
- @Override
- public boolean remove(Object key, Object value) {
- if (size == 0) {
- return false;
- }
- if (key == null) {
- if (nullKeyEntry != null &&
- Objects.equals(nullKeyEntry.value, value)) {
- removeNullKey();
- return true;
- }
- return false;
- }
- int hash = hash(key);
- int i = indexFor(hash, table.length);
-
- if (table[i] instanceof Entry) {
- @SuppressWarnings("unchecked")
- Entry<K,V> prev = (Entry<K,V>) table[i];
- Entry<K,V> e = prev;
- while (e != null) {
- @SuppressWarnings("unchecked")
- Entry<K,V> next = (Entry<K,V>) e.next;
- if (e.hash == hash && Objects.equals(e.key, key)) {
- if (!Objects.equals(e.value, value)) {
- return false;
- }
- modCount++;
- size--;
- if (prev == e)
- table[i] = next;
- else
- prev.next = next;
- e.recordRemoval(this);
- return true;
- }
- prev = e;
- e = next;
- }
- } else if (table[i] != null) {
- TreeBin tb = ((TreeBin) table[i]);
- TreeNode p = tb.getTreeNode(hash, (K)key);
- if (p != null) {
- Entry<K,V> pEntry = (Entry<K,V>)p.entry;
- // assert pEntry.key.equals(key);
- if (Objects.equals(pEntry.value, value)) {
- modCount++;
- size--;
- tb.deleteTreeNode(p);
- pEntry.recordRemoval(this);
- if (tb.root == null || tb.first == null) {
- // assert tb.root == null && tb.first == null :
- // "TreeBin.first and root should both be null";
- // TreeBin is now empty, we should blank this bin
- table[i] = null;
- }
- return true;
+ /**
+ * Implements Map.remove and related methods
+ *
+ * @param hash hash for key
+ * @param key the key
+ * @param value the value to match if matchValue, else ignored
+ * @param matchValue if true only remove if value is equal
+ * @param movable if false do not move other nodes while removing
+ * @return the node, or null if none
+ */
+ final Node<K,V> removeNode(int hash, Object key, Object value,
+ boolean matchValue, boolean movable) {
+ Node<K,V>[] tab; Node<K,V> p; int n, index;
+ if ((tab = table) != null && (n = tab.length) > 0 &&
+ (p = tab[index = (n - 1) & hash]) != null) {
+ Node<K,V> node = null, e; K k; V v;
+ if (p.hash == hash &&
+ ((k = p.key) == key || (key != null && key.equals(k))))
+ node = p;
+ else if ((e = p.next) != null) {
+ if (p instanceof TreeNode)
+ node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
+ else {
+ do {
+ if (e.hash == hash &&
+ ((k = e.key) == key ||
+ (key != null && key.equals(k)))) {
+ node = e;
+ break;
+ }
+ p = e;
+ } while ((e = e.next) != null);
}
}
- }
- return false;
- }
-
- @Override
- public boolean replace(K key, V oldValue, V newValue) {
- if (size == 0) {
- return false;
- }
- if (key == null) {
- if (nullKeyEntry != null &&
- Objects.equals(nullKeyEntry.value, oldValue)) {
- putForNullKey(newValue);
- return true;
- }
- return false;
- }
- int hash = hash(key);
- int i = indexFor(hash, table.length);
-
- if (table[i] instanceof Entry) {
- @SuppressWarnings("unchecked")
- Entry<K,V> e = (Entry<K,V>) table[i];
- for (; e != null; e = (Entry<K,V>)e.next) {
- if (e.hash == hash && Objects.equals(e.key, key) && Objects.equals(e.value, oldValue)) {
- e.value = newValue;
- e.recordAccess(this);
- return true;
- }
- }
- return false;
- } else if (table[i] != null) {
- TreeBin tb = ((TreeBin) table[i]);
- TreeNode p = tb.getTreeNode(hash, key);
- if (p != null) {
- Entry<K,V> pEntry = (Entry<K,V>)p.entry;
- // assert pEntry.key.equals(key);
- if (Objects.equals(pEntry.value, oldValue)) {
- pEntry.value = newValue;
- pEntry.recordAccess(this);
- return true;
- }
- }
- }
- return false;
- }
-
- @Override
- public V replace(K key, V value) {
- if (size == 0) {
- return null;
- }
- if (key == null) {
- if (nullKeyEntry != null) {
- return putForNullKey(value);
- }
- return null;
- }
- int hash = hash(key);
- int i = indexFor(hash, table.length);
- if (table[i] instanceof Entry) {
- @SuppressWarnings("unchecked")
- Entry<K,V> e = (Entry<K,V>)table[i];
- for (; e != null; e = (Entry<K,V>)e.next) {
- if (e.hash == hash && Objects.equals(e.key, key)) {
- V oldValue = e.value;
- e.value = value;
- e.recordAccess(this);
- return oldValue;
- }
- }
-
- return null;
- } else if (table[i] != null) {
- TreeBin tb = ((TreeBin) table[i]);
- TreeNode p = tb.getTreeNode(hash, key);
- if (p != null) {
- Entry<K,V> pEntry = (Entry<K,V>)p.entry;
- // assert pEntry.key.equals(key);
- V oldValue = pEntry.value;
- pEntry.value = value;
- pEntry.recordAccess(this);
- return oldValue;
+ if (node != null && (!matchValue || (v = node.value) == value ||
+ (value != null && value.equals(v)))) {
+ if (node instanceof TreeNode)
+ ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
+ else if (node == p)
+ tab[index] = node.next;
+ else
+ p.next = node.next;
+ ++modCount;
+ --size;
+ afterNodeRemoval(node);
+ return node;
}
}
return null;
}
- @Override
- public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
- if (table == EMPTY_TABLE) {
- inflateTable(threshold);
- }
- if (key == null) {
- if (nullKeyEntry == null || nullKeyEntry.value == null) {
- V newValue = mappingFunction.apply(key);
- if (newValue != null) {
- putForNullKey(newValue);
- }
- return newValue;
- }
- return nullKeyEntry.value;
- }
- int hash = hash(key);
- int i = indexFor(hash, table.length);
- boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
-
- if (table[i] instanceof Entry) {
- int listSize = 0;
- @SuppressWarnings("unchecked")
- Entry<K,V> e = (Entry<K,V>)table[i];
- for (; e != null; e = (Entry<K,V>)e.next) {
- if (e.hash == hash && Objects.equals(e.key, key)) {
- V oldValue = e.value;
- if (oldValue == null) {
- V newValue = mappingFunction.apply(key);
- if (newValue != null) {
- e.value = newValue;
- e.recordAccess(this);
- }
- return newValue;
- }
- return oldValue;
- }
- listSize++;
- }
- // Didn't find, fall through to call the mapping function
- checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
- } else if (table[i] != null) {
- TreeBin e = (TreeBin)table[i];
- V value = mappingFunction.apply(key);
- if (value == null) { // Return the existing value, if any
- TreeNode p = e.getTreeNode(hash, key);
- if (p != null) {
- return (V) p.entry.value;
- }
- return null;
- } else { // Put the new value into the Tree, if absent
- TreeNode p = e.putTreeNode(hash, key, value, null);
- if (p == null) { // not found, new node was added
- modCount++;
- size++;
- if (size >= threshold) {
- resize(2 * table.length);
- }
- return value;
- } else { // putTreeNode() found an existing node
- Entry<K,V> pEntry = (Entry<K,V>)p.entry;
- V oldVal = pEntry.value;
- if (oldVal == null) { // only replace if maps to null
- pEntry.value = value;
- pEntry.recordAccess(this);
- return value;
- }
- return oldVal;
- }
- }
- }
- V newValue = mappingFunction.apply(key);
- if (newValue != null) { // add Entry and check for TreeBin conversion
- modCount++;
- addEntry(hash, key, newValue, i, checkIfNeedTree);
- }
-
- return newValue;
- }
-
- @Override
- public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
- if (size == 0) {
- return null;
- }
- if (key == null) {
- V oldValue;
- if (nullKeyEntry != null && (oldValue = nullKeyEntry.value) != null) {
- V newValue = remappingFunction.apply(key, oldValue);
- if (newValue != null ) {
- putForNullKey(newValue);
- return newValue;
- } else {
- removeNullKey();
- }
- }
- return null;
- }
- int hash = hash(key);
- int i = indexFor(hash, table.length);
- if (table[i] instanceof Entry) {
- @SuppressWarnings("unchecked")
- Entry<K,V> prev = (Entry<K,V>)table[i];
- Entry<K,V> e = prev;
- while (e != null) {
- Entry<K,V> next = (Entry<K,V>)e.next;
- if (e.hash == hash && Objects.equals(e.key, key)) {
- V oldValue = e.value;
- if (oldValue == null)
- break;
- V newValue = remappingFunction.apply(key, oldValue);
- if (newValue == null) {
- modCount++;
- size--;
- if (prev == e)
- table[i] = next;
- else
- prev.next = next;
- e.recordRemoval(this);
- } else {
- e.value = newValue;
- e.recordAccess(this);
- }
- return newValue;
- }
- prev = e;
- e = next;
- }
- } else if (table[i] != null) {
- TreeBin tb = (TreeBin)table[i];
- TreeNode p = tb.getTreeNode(hash, key);
- if (p != null) {
- Entry<K,V> pEntry = (Entry<K,V>)p.entry;
- // assert pEntry.key.equals(key);
- V oldValue = pEntry.value;
- if (oldValue != null) {
- V newValue = remappingFunction.apply(key, oldValue);
- if (newValue == null) { // remove mapping
- modCount++;
- size--;
- tb.deleteTreeNode(p);
- pEntry.recordRemoval(this);
- if (tb.root == null || tb.first == null) {
- // assert tb.root == null && tb.first == null :
- // "TreeBin.first and root should both be null";
- // TreeBin is now empty, we should blank this bin
- table[i] = null;
- }
- } else {
- pEntry.value = newValue;
- pEntry.recordAccess(this);
- }
- return newValue;
- }
- }
- }
- return null;
- }
-
- @Override
- public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
- if (table == EMPTY_TABLE) {
- inflateTable(threshold);
- }
- if (key == null) {
- V oldValue = nullKeyEntry == null ? null : nullKeyEntry.value;
- V newValue = remappingFunction.apply(key, oldValue);
- if (newValue != oldValue || (oldValue == null && nullKeyEntry != null)) {
- if (newValue == null) {
- removeNullKey();
- } else {
- putForNullKey(newValue);
- }
- }
- return newValue;
- }
- int hash = hash(key);
- int i = indexFor(hash, table.length);
- boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
-
- if (table[i] instanceof Entry) {
- int listSize = 0;
- @SuppressWarnings("unchecked")
- Entry<K,V> prev = (Entry<K,V>)table[i];
- Entry<K,V> e = prev;
-
- while (e != null) {
- Entry<K,V> next = (Entry<K,V>)e.next;
- if (e.hash == hash && Objects.equals(e.key, key)) {
- V oldValue = e.value;
- V newValue = remappingFunction.apply(key, oldValue);
- if (newValue != oldValue || oldValue == null) {
- if (newValue == null) {
- modCount++;
- size--;
- if (prev == e)
- table[i] = next;
- else
- prev.next = next;
- e.recordRemoval(this);
- } else {
- e.value = newValue;
- e.recordAccess(this);
- }
- }
- return newValue;
- }
- prev = e;
- e = next;
- listSize++;
- }
- checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
- } else if (table[i] != null) {
- TreeBin tb = (TreeBin)table[i];
- TreeNode p = tb.getTreeNode(hash, key);
- V oldValue = p == null ? null : (V)p.entry.value;
- V newValue = remappingFunction.apply(key, oldValue);
- if (newValue != oldValue || (oldValue == null && p != null)) {
- if (newValue == null) {
- Entry<K,V> pEntry = (Entry<K,V>)p.entry;
- modCount++;
- size--;
- tb.deleteTreeNode(p);
- pEntry.recordRemoval(this);
- if (tb.root == null || tb.first == null) {
- // assert tb.root == null && tb.first == null :
- // "TreeBin.first and root should both be null";
- // TreeBin is now empty, we should blank this bin
- table[i] = null;
- }
- } else {
- if (p != null) { // just update the value
- Entry<K,V> pEntry = (Entry<K,V>)p.entry;
- pEntry.value = newValue;
- pEntry.recordAccess(this);
- } else { // need to put new node
- p = tb.putTreeNode(hash, key, newValue, null);
- // assert p == null; // should have added a new node
- modCount++;
- size++;
- if (size >= threshold) {
- resize(2 * table.length);
- }
- }
- }
- }
- return newValue;
- }
-
- V newValue = remappingFunction.apply(key, null);
- if (newValue != null) {
- modCount++;
- addEntry(hash, key, newValue, i, checkIfNeedTree);
- }
-
- return newValue;
- }
-
- @Override
- public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
- if (table == EMPTY_TABLE) {
- inflateTable(threshold);
- }
- if (key == null) {
- V oldValue = nullKeyEntry == null ? null : nullKeyEntry.value;
- V newValue = oldValue == null ? value : remappingFunction.apply(oldValue, value);
- if (newValue != null) {
- putForNullKey(newValue);
- } else if (nullKeyEntry != null) {
- removeNullKey();
- }
- return newValue;
- }
- int hash = hash(key);
- int i = indexFor(hash, table.length);
- boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
-
- if (table[i] instanceof Entry) {
- int listSize = 0;
- @SuppressWarnings("unchecked")
- Entry<K,V> prev = (Entry<K,V>)table[i];
- Entry<K,V> e = prev;
-
- while (e != null) {
- Entry<K,V> next = (Entry<K,V>)e.next;
- if (e.hash == hash && Objects.equals(e.key, key)) {
- V oldValue = e.value;
- V newValue = (oldValue == null) ? value :
- remappingFunction.apply(oldValue, value);
- if (newValue == null) {
- modCount++;
- size--;
- if (prev == e)
- table[i] = next;
- else
- prev.next = next;
- e.recordRemoval(this);
- } else {
- e.value = newValue;
- e.recordAccess(this);
- }
- return newValue;
- }
- prev = e;
- e = next;
- listSize++;
- }
- // Didn't find, so fall through and (maybe) call addEntry() to add
- // the Entry and check for TreeBin conversion.
- checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
- } else if (table[i] != null) {
- TreeBin tb = (TreeBin)table[i];
- TreeNode p = tb.getTreeNode(hash, key);
- V oldValue = p == null ? null : (V)p.entry.value;
- V newValue = (oldValue == null) ? value :
- remappingFunction.apply(oldValue, value);
- if (newValue == null) {
- if (p != null) {
- Entry<K,V> pEntry = (Entry<K,V>)p.entry;
- modCount++;
- size--;
- tb.deleteTreeNode(p);
- pEntry.recordRemoval(this);
-
- if (tb.root == null || tb.first == null) {
- // assert tb.root == null && tb.first == null :
- // "TreeBin.first and root should both be null";
- // TreeBin is now empty, we should blank this bin
- table[i] = null;
- }
- }
- return null;
- } else if (newValue != oldValue) {
- if (p != null) { // just update the value
- Entry<K,V> pEntry = (Entry<K,V>)p.entry;
- pEntry.value = newValue;
- pEntry.recordAccess(this);
- } else { // need to put new node
- p = tb.putTreeNode(hash, key, newValue, null);
- // assert p == null; // should have added a new node
- modCount++;
- size++;
- if (size >= threshold) {
- resize(2 * table.length);
- }
- }
- }
- return newValue;
- }
- if (value != null) {
- modCount++;
- addEntry(hash, key, value, i, checkIfNeedTree);
- }
- return value;
- }
-
- // end of optimized implementations of default methods in Map
-
- /**
- * Removes and returns the entry associated with the specified key
- * in the HashMap. Returns null if the HashMap contains no mapping
- * for this key.
- *
- * We don't bother converting TreeBins back to Entry lists if the bin falls
- * back below TREE_THRESHOLD, but we do clear bins when removing the last
- * TreeNode in a TreeBin.
- */
- final Entry<K,V> removeEntryForKey(Object key) {
- if (size == 0) {
- return null;
- }
- if (key == null) {
- if (nullKeyEntry != null) {
- return removeNullKey();
- }
- return null;
- }
- int hash = hash(key);
- int i = indexFor(hash, table.length);
-
- if (table[i] instanceof Entry) {
- @SuppressWarnings("unchecked")
- Entry<K,V> prev = (Entry<K,V>)table[i];
- Entry<K,V> e = prev;
-
- while (e != null) {
- @SuppressWarnings("unchecked")
- Entry<K,V> next = (Entry<K,V>) e.next;
- if (e.hash == hash && Objects.equals(e.key, key)) {
- modCount++;
- size--;
- if (prev == e)
- table[i] = next;
- else
- prev.next = next;
- e.recordRemoval(this);
- return e;
- }
- prev = e;
- e = next;
- }
- } else if (table[i] != null) {
- TreeBin tb = ((TreeBin) table[i]);
- TreeNode p = tb.getTreeNode(hash, (K)key);
- if (p != null) {
- Entry<K,V> pEntry = (Entry<K,V>)p.entry;
- // assert pEntry.key.equals(key);
- modCount++;
- size--;
- tb.deleteTreeNode(p);
- pEntry.recordRemoval(this);
- if (tb.root == null || tb.first == null) {
- // assert tb.root == null && tb.first == null :
- // "TreeBin.first and root should both be null";
- // TreeBin is now empty, we should blank this bin
- table[i] = null;
- }
- return pEntry;
- }
- }
- return null;
- }
-
- /**
- * Special version of remove for EntrySet using {@code Map.Entry.equals()}
- * for matching.
- */
- final Entry<K,V> removeMapping(Object o) {
- if (size == 0 || !(o instanceof Map.Entry))
- return null;
-
- Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
- Object key = entry.getKey();
-
- if (key == null) {
- if (entry.equals(nullKeyEntry)) {
- return removeNullKey();
- }
- return null;
- }
-
- int hash = hash(key);
- int i = indexFor(hash, table.length);
-
- if (table[i] instanceof Entry) {
- @SuppressWarnings("unchecked")
- Entry<K,V> prev = (Entry<K,V>)table[i];
- Entry<K,V> e = prev;
-
- while (e != null) {
- @SuppressWarnings("unchecked")
- Entry<K,V> next = (Entry<K,V>)e.next;
- if (e.hash == hash && e.equals(entry)) {
- modCount++;
- size--;
- if (prev == e)
- table[i] = next;
- else
- prev.next = next;
- e.recordRemoval(this);
- return e;
- }
- prev = e;
- e = next;
- }
- } else if (table[i] != null) {
- TreeBin tb = ((TreeBin) table[i]);
- TreeNode p = tb.getTreeNode(hash, (K)key);
- if (p != null && p.entry.equals(entry)) {
- @SuppressWarnings("unchecked")
- Entry<K,V> pEntry = (Entry<K,V>)p.entry;
- // assert pEntry.key.equals(key);
- modCount++;
- size--;
- tb.deleteTreeNode(p);
- pEntry.recordRemoval(this);
- if (tb.root == null || tb.first == null) {
- // assert tb.root == null && tb.first == null :
- // "TreeBin.first and root should both be null";
- // TreeBin is now empty, we should blank this bin
- table[i] = null;
- }
- return pEntry;
- }
- }
- return null;
- }
-
- /*
- * Remove the mapping for the null key, and update internal accounting
- * (size, modcount, recordRemoval, etc).
- *
- * Assumes nullKeyEntry is non-null.
- */
- private Entry<K,V> removeNullKey() {
- // assert nullKeyEntry != null;
- Entry<K,V> retVal = nullKeyEntry;
- modCount++;
- size--;
- retVal.recordRemoval(this);
- nullKeyEntry = null;
- return retVal;
- }
-
/**
* Removes all of the mappings from this map.
* The map will be empty after this call returns.
*/
public void clear() {
+ Node<K,V>[] tab;
modCount++;
- if (nullKeyEntry != null) {
- nullKeyEntry = null;
+ if ((tab = table) != null && size > 0) {
+ size = 0;
+ for (int i = 0; i < tab.length; ++i)
+ tab[i] = null;
}
- Arrays.fill(table, null);
- size = 0;
}
/**
@@ -2134,352 +873,20 @@
* specified value
*/
public boolean containsValue(Object value) {
- if (value == null) {
- return containsNullValue();
- }
- Object[] tab = table;
- for (int i = 0; i < tab.length; i++) {
- if (tab[i] instanceof Entry) {
- Entry<?,?> e = (Entry<?,?>)tab[i];
- for (; e != null; e = (Entry<?,?>)e.next) {
- if (value.equals(e.value)) {
- return true;
- }
- }
- } else if (tab[i] != null) {
- TreeBin e = (TreeBin)tab[i];
- TreeNode p = e.first;
- for (; p != null; p = (TreeNode) p.entry.next) {
- if (value == p.entry.value || value.equals(p.entry.value)) {
+ Node<K,V>[] tab; V v;
+ if ((tab = table) != null && size > 0) {
+ for (int i = 0; i < tab.length; ++i) {
+ for (Node<K,V> e = tab[i]; e != null; e = e.next) {
+ if ((v = e.value) == value ||
+ (value != null && value.equals(v)))
return true;
- }
- }
- }
- }
- // Didn't find value in table - could be in nullKeyEntry
- return (nullKeyEntry != null && (value == nullKeyEntry.value ||
- value.equals(nullKeyEntry.value)));
- }
-
- /**
- * Special-case code for containsValue with null argument
- */
- private boolean containsNullValue() {
- Object[] tab = table;
- for (int i = 0; i < tab.length; i++) {
- if (tab[i] instanceof Entry) {
- Entry<K,V> e = (Entry<K,V>)tab[i];
- for (; e != null; e = (Entry<K,V>)e.next) {
- if (e.value == null) {
- return true;
- }
- }
- } else if (tab[i] != null) {
- TreeBin e = (TreeBin)tab[i];
- TreeNode p = e.first;
- for (; p != null; p = (TreeNode) p.entry.next) {
- if (p.entry.value == null) {
- return true;
- }
}
}
}
- // Didn't find value in table - could be in nullKeyEntry
- return (nullKeyEntry != null && nullKeyEntry.value == null);
- }
-
- /**
- * Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and
- * values themselves are not cloned.
- *
- * @return a shallow copy of this map
- */
- @SuppressWarnings("unchecked")
- public Object clone() {
- HashMap<K,V> result = null;
- try {
- result = (HashMap<K,V>)super.clone();
- } catch (CloneNotSupportedException e) {
- // assert false;
- }
- if (result.table != EMPTY_TABLE) {
- result.inflateTable(Math.min(
- (int) Math.min(
- size * Math.min(1 / loadFactor, 4.0f),
- // we have limits...
- HashMap.MAXIMUM_CAPACITY),
- table.length));
- }
- result.entrySet = null;
- result.modCount = 0;
- result.size = 0;
- result.nullKeyEntry = null;
- result.init();
- result.putAllForCreate(this);
-
- return result;
- }
-
- static class Entry<K,V> implements Map.Entry<K,V> {
- final K key;
- V value;
- Object next; // an Entry, or a TreeNode
- final int hash;
-
- /**
- * Creates new entry.
- */
- Entry(int h, K k, V v, Object n) {
- value = v;
- next = n;
- key = k;
- hash = h;
- }
-
- public final K getKey() {
- return key;
- }
-
- public final V getValue() {
- return value;
- }
-
- public final V setValue(V newValue) {
- V oldValue = value;
- value = newValue;
- return oldValue;
- }
-
- public final boolean equals(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry<?,?> e = (Map.Entry<?,?>)o;
- Object k1 = getKey();
- Object k2 = e.getKey();
- if (k1 == k2 || (k1 != null && k1.equals(k2))) {
- Object v1 = getValue();
- Object v2 = e.getValue();
- if (v1 == v2 || (v1 != null && v1.equals(v2)))
- return true;
- }
- return false;
- }
-
- public final int hashCode() {
- return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
- }
-
- public final String toString() {
- return getKey() + "=" + getValue();
- }
-
- /**
- * This method is invoked whenever the value in an entry is
- * overwritten for a key that's already in the HashMap.
- */
- void recordAccess(HashMap<K,V> m) {
- }
-
- /**
- * This method is invoked whenever the entry is
- * removed from the table.
- */
- void recordRemoval(HashMap<K,V> m) {
- }
- }
-
- void addEntry(int hash, K key, V value, int bucketIndex) {
- addEntry(hash, key, value, bucketIndex, true);
- }
-
- /**
- * Adds a new entry with the specified key, value and hash code to
- * the specified bucket. It is the responsibility of this
- * method to resize the table if appropriate. The new entry is then
- * created by calling createEntry().
- *
- * Subclass overrides this to alter the behavior of put method.
- *
- * If checkIfNeedTree is false, it is known that this bucket will not need
- * to be converted to a TreeBin, so don't bothering checking.
- *
- * Assumes key is not null.
- */
- void addEntry(int hash, K key, V value, int bucketIndex, boolean checkIfNeedTree) {
- // assert key != null;
- if ((size >= threshold) && (null != table[bucketIndex])) {
- resize(2 * table.length);
- hash = hash(key);
- bucketIndex = indexFor(hash, table.length);
- }
- createEntry(hash, key, value, bucketIndex, checkIfNeedTree);
+ return false;
}
/**
- * Called by addEntry(), and also used when creating entries
- * as part of Map construction or "pseudo-construction" (cloning,
- * deserialization). This version does not check for resizing of the table.
- *
- * This method is responsible for converting a bucket to a TreeBin once
- * TREE_THRESHOLD is reached. However if checkIfNeedTree is false, it is known
- * that this bucket will not need to be converted to a TreeBin, so don't
- * bother checking. The new entry is constructed by calling newEntry().
- *
- * Assumes key is not null.
- *
- * Note: buckets already converted to a TreeBin don't call this method, but
- * instead call TreeBin.putTreeNode() to create new entries.
- */
- void createEntry(int hash, K key, V value, int bucketIndex, boolean checkIfNeedTree) {
- // assert key != null;
- @SuppressWarnings("unchecked")
- Entry<K,V> e = (Entry<K,V>)table[bucketIndex];
- table[bucketIndex] = newEntry(hash, key, value, e);
- size++;
-
- if (checkIfNeedTree) {
- int listSize = 0;
- for (e = (Entry<K,V>) table[bucketIndex]; e != null; e = (Entry<K,V>)e.next) {
- listSize++;
- if (listSize >= TreeBin.TREE_THRESHOLD) { // Convert to TreeBin
- if (comparableClassFor(key) != null) {
- TreeBin t = new TreeBin();
- t.populate((Entry)table[bucketIndex]);
- table[bucketIndex] = t;
- }
- break;
- }
- }
- }
- }
-
- /*
- * Factory method to create a new Entry object.
- */
- Entry<K,V> newEntry(int hash, K key, V value, Object next) {
- return new HashMap.Entry<>(hash, key, value, next);
- }
-
-
- private abstract class HashIterator<E> implements Iterator<E> {
- Object next; // next entry to return, an Entry or a TreeNode
- int expectedModCount; // For fast-fail
- int index; // current slot
- Object current; // current entry, an Entry or a TreeNode
-
- HashIterator() {
- expectedModCount = modCount;
- if (size > 0) { // advance to first entry
- if (nullKeyEntry != null) {
- // assert nullKeyEntry.next == null;
- // This works with nextEntry(): nullKeyEntry isa Entry, and
- // e.next will be null, so we'll hit the findNextBin() call.
- next = nullKeyEntry;
- } else {
- findNextBin();
- }
- }
- }
-
- public final boolean hasNext() {
- return next != null;
- }
-
- @SuppressWarnings("unchecked")
- final Entry<K,V> nextEntry() {
- if (modCount != expectedModCount) {
- throw new ConcurrentModificationException();
- }
- Object e = next;
- Entry<K,V> retVal;
-
- if (e == null)
- throw new NoSuchElementException();
-
- if (e instanceof TreeNode) { // TreeBin
- retVal = (Entry<K,V>)((TreeNode)e).entry;
- next = retVal.next;
- } else {
- retVal = (Entry<K,V>)e;
- next = ((Entry<K,V>)e).next;
- }
-
- if (next == null) { // Move to next bin
- findNextBin();
- }
- current = e;
- return retVal;
- }
-
- public void remove() {
- if (current == null)
- throw new IllegalStateException();
- if (modCount != expectedModCount)
- throw new ConcurrentModificationException();
- K k;
-
- if (current instanceof Entry) {
- k = ((Entry<K,V>)current).key;
- } else {
- k = ((Entry<K,V>)((TreeNode)current).entry).key;
-
- }
- current = null;
- HashMap.this.removeEntryForKey(k);
- expectedModCount = modCount;
- }
-
- /*
- * Set 'next' to the first entry of the next non-empty bin in the table
- */
- private void findNextBin() {
- // assert next == null;
- Object[] t = table;
-
- while (index < t.length && (next = t[index++]) == null)
- ;
- if (next instanceof HashMap.TreeBin) { // Point to the first TreeNode
- next = ((TreeBin) next).first;
- // assert next != null; // There should be no empty TreeBins
- }
- }
- }
-
- private final class ValueIterator extends HashIterator<V> {
- public V next() {
- return nextEntry().value;
- }
- }
-
- private final class KeyIterator extends HashIterator<K> {
- public K next() {
- return nextEntry().getKey();
- }
- }
-
- private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
- public Map.Entry<K,V> next() {
- return nextEntry();
- }
- }
-
- // Subclass overrides these to alter behavior of views' iterator() method
- Iterator<K> newKeyIterator() {
- return new KeyIterator();
- }
- Iterator<V> newValueIterator() {
- return new ValueIterator();
- }
- Iterator<Map.Entry<K,V>> newEntryIterator() {
- return new EntryIterator();
- }
-
-
- // Views
-
- private transient Set<Map.Entry<K,V>> entrySet = null;
-
- /**
* Returns a {@link Set} view of the keys contained in this map.
* The set is backed by the map, so changes to the map are
* reflected in the set, and vice-versa. If the map is modified
@@ -2491,35 +898,38 @@
* <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
* operations. It does not support the <tt>add</tt> or <tt>addAll</tt>
* operations.
+ *
+ * @return a set view of the keys contained in this map
*/
public Set<K> keySet() {
- Set<K> ks = keySet;
- return (ks != null ? ks : (keySet = new KeySet()));
+ Set<K> ks;
+ return (ks = keySet) == null ? (keySet = new KeySet()) : ks;
}
- private final class KeySet extends AbstractSet<K> {
- public Iterator<K> iterator() {
- return newKeyIterator();
+ final class KeySet extends AbstractSet<K> {
+ public final int size() { return size; }
+ public final void clear() { HashMap.this.clear(); }
+ public final Iterator<K> iterator() { return new KeyIterator(); }
+ public final boolean contains(Object o) { return containsKey(o); }
+ public final boolean remove(Object key) {
+ return removeNode(hash(key), key, null, false, true) != null;
}
- public int size() {
- return size;
- }
- public boolean contains(Object o) {
- return containsKey(o);
+ public final Spliterator<K> spliterator() {
+ return new KeySpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
}
- public boolean remove(Object o) {
- return HashMap.this.removeEntryForKey(o) != null;
- }
- public void clear() {
- HashMap.this.clear();
- }
-
- public Spliterator<K> spliterator() {
- if (HashMap.this.getClass() == HashMap.class)
- return new KeySpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
- else
- return Spliterators.spliterator
- (this, Spliterator.SIZED | Spliterator.DISTINCT);
+ public final void forEach(Consumer<? super K> action) {
+ Node<K,V>[] tab;
+ if (action == null)
+ throw new NullPointerException();
+ if (size > 0 && (tab = table) != null) {
+ int mc = modCount;
+ for (int i = 0; i < tab.length; ++i) {
+ for (Node<K,V> e = tab[i]; e != null; e = e.next)
+ action.accept(e.key);
+ }
+ if (modCount != mc)
+ throw new ConcurrentModificationException();
+ }
}
}
@@ -2535,32 +945,35 @@
* <tt>Collection.remove</tt>, <tt>removeAll</tt>,
* <tt>retainAll</tt> and <tt>clear</tt> operations. It does not
* support the <tt>add</tt> or <tt>addAll</tt> operations.
+ *
+ * @return a view of the values contained in this map
*/
public Collection<V> values() {
- Collection<V> vs = values;
- return (vs != null ? vs : (values = new Values()));
+ Collection<V> vs;
+ return (vs = values) == null ? (values = new Values()) : vs;
}
- private final class Values extends AbstractCollection<V> {
- public Iterator<V> iterator() {
- return newValueIterator();
- }
- public int size() {
- return size;
- }
- public boolean contains(Object o) {
- return containsValue(o);
+ final class Values extends AbstractCollection<V> {
+ public final int size() { return size; }
+ public final void clear() { HashMap.this.clear(); }
+ public final Iterator<V> iterator() { return new ValueIterator(); }
+ public final boolean contains(Object o) { return containsValue(o); }
+ public final Spliterator<V> spliterator() {
+ return new ValueSpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
}
- public void clear() {
- HashMap.this.clear();
- }
-
- public Spliterator<V> spliterator() {
- if (HashMap.this.getClass() == HashMap.class)
- return new ValueSpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
- else
- return Spliterators.spliterator
- (this, Spliterator.SIZED);
+ public final void forEach(Consumer<? super V> action) {
+ Node<K,V>[] tab;
+ if (action == null)
+ throw new NullPointerException();
+ if (size > 0 && (tab = table) != null) {
+ int mc = modCount;
+ for (int i = 0; i < tab.length; ++i) {
+ for (Node<K,V> e = tab[i]; e != null; e = e.next)
+ action.accept(e.value);
+ }
+ if (modCount != mc)
+ throw new ConcurrentModificationException();
+ }
}
}
@@ -2581,42 +994,324 @@
* @return a set view of the mappings contained in this map
*/
public Set<Map.Entry<K,V>> entrySet() {
- return entrySet0();
+ Set<Map.Entry<K,V>> es;
+ return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
}
- private Set<Map.Entry<K,V>> entrySet0() {
- Set<Map.Entry<K,V>> es = entrySet;
- return es != null ? es : (entrySet = new EntrySet());
- }
-
- private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
- public Iterator<Map.Entry<K,V>> iterator() {
- return newEntryIterator();
+ final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+ public final int size() { return size; }
+ public final void clear() { HashMap.this.clear(); }
+ public final Iterator<Map.Entry<K,V>> iterator() {
+ return new EntryIterator();
}
- public boolean contains(Object o) {
+ public final boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
- Entry<K,V> candidate = getEntry(e.getKey());
+ Object key = e.getKey();
+ Node<K,V> candidate = getNode(hash(key), key);
return candidate != null && candidate.equals(e);
}
- public boolean remove(Object o) {
- return removeMapping(o) != null;
+ public final boolean remove(Object o) {
+ if (o instanceof Map.Entry) {
+ Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+ Object key = e.getKey();
+ Object value = e.getValue();
+ return removeNode(hash(key), key, value, true, true) != null;
+ }
+ return false;
+ }
+ public final Spliterator<Map.Entry<K,V>> spliterator() {
+ return new EntrySpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
+ }
+ public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
+ Node<K,V>[] tab;
+ if (action == null)
+ throw new NullPointerException();
+ if (size > 0 && (tab = table) != null) {
+ int mc = modCount;
+ for (int i = 0; i < tab.length; ++i) {
+ for (Node<K,V> e = tab[i]; e != null; e = e.next)
+ action.accept(e);
+ }
+ if (modCount != mc)
+ throw new ConcurrentModificationException();
+ }
+ }
+ }
+
+ // Overrides of JDK8 Map extension methods
+
+ public V getOrDefault(Object key, V defaultValue) {
+ Node<K,V> e;
+ return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
+ }
+
+ public V putIfAbsent(K key, V value) {
+ return putVal(hash(key), key, value, true, true);
+ }
+
+ public boolean remove(Object key, Object value) {
+ return removeNode(hash(key), key, value, true, true) != null;
+ }
+
+ public boolean replace(K key, V oldValue, V newValue) {
+ Node<K,V> e; V v;
+ if ((e = getNode(hash(key), key)) != null &&
+ ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) {
+ e.value = newValue;
+ afterNodeAccess(e);
+ return true;
+ }
+ return false;
+ }
+
+ public V replace(K key, V value) {
+ Node<K,V> e;
+ if ((e = getNode(hash(key), key)) != null) {
+ V oldValue = e.value;
+ e.value = value;
+ afterNodeAccess(e);
+ return oldValue;
}
- public int size() {
- return size;
+ return null;
+ }
+
+ public V computeIfAbsent(K key,
+ Function<? super K, ? extends V> mappingFunction) {
+ if (mappingFunction == null)
+ throw new NullPointerException();
+ int hash = hash(key);
+ Node<K,V>[] tab; Node<K,V> first; int n, i;
+ int binCount = 0;
+ TreeNode<K,V> t = null;
+ Node<K,V> old = null;
+ if (size > threshold || (tab = table) == null ||
+ (n = tab.length) == 0)
+ n = (tab = resize()).length;
+ if ((first = tab[i = (n - 1) & hash]) != null) {
+ if (first instanceof TreeNode)
+ old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
+ else {
+ Node<K,V> e = first; K k;
+ do {
+ if (e.hash == hash &&
+ ((k = e.key) == key || (key != null && key.equals(k)))) {
+ old = e;
+ break;
+ }
+ ++binCount;
+ } while ((e = e.next) != null);
+ }
+ V oldValue;
+ if (old != null && (oldValue = old.value) != null) {
+ afterNodeAccess(old);
+ return oldValue;
+ }
}
- public void clear() {
- HashMap.this.clear();
+ V v = mappingFunction.apply(key);
+ if (old != null) {
+ old.value = v;
+ afterNodeAccess(old);
+ return v;
+ }
+ else if (v == null)
+ return null;
+ else if (t != null)
+ t.putTreeVal(this, tab, hash, key, v);
+ else {
+ tab[i] = newNode(hash, key, v, first);
+ if (binCount >= TREEIFY_THRESHOLD - 1)
+ treeifyBin(tab, hash);
+ }
+ ++modCount;
+ ++size;
+ afterNodeInsertion(true);
+ return v;
+ }
+
+ public V computeIfPresent(K key,
+ BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+ Node<K,V> e; V oldValue;
+ int hash = hash(key);
+ if ((e = getNode(hash, key)) != null &&
+ (oldValue = e.value) != null) {
+ V v = remappingFunction.apply(key, oldValue);
+ if (v != null) {
+ e.value = v;
+ afterNodeAccess(e);
+ return v;
+ }
+ else
+ removeNode(hash, key, null, false, true);
}
+ return null;
+ }
- public Spliterator<Map.Entry<K,V>> spliterator() {
- if (HashMap.this.getClass() == HashMap.class)
- return new EntrySpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
+ public V compute(K key,
+ BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+ if (remappingFunction == null)
+ throw new NullPointerException();
+ int hash = hash(key);
+ Node<K,V>[] tab; Node<K,V> first; int n, i;
+ int binCount = 0;
+ TreeNode<K,V> t = null;
+ Node<K,V> old = null;
+ if (size > threshold || (tab = table) == null ||
+ (n = tab.length) == 0)
+ n = (tab = resize()).length;
+ if ((first = tab[i = (n - 1) & hash]) != null) {
+ if (first instanceof TreeNode)
+ old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
+ else {
+ Node<K,V> e = first; K k;
+ do {
+ if (e.hash == hash &&
+ ((k = e.key) == key || (key != null && key.equals(k)))) {
+ old = e;
+ break;
+ }
+ ++binCount;
+ } while ((e = e.next) != null);
+ }
+ }
+ V oldValue = (old == null) ? null : old.value;
+ V v = remappingFunction.apply(key, oldValue);
+ if (old != null) {
+ if (v != null) {
+ old.value = v;
+ afterNodeAccess(old);
+ }
else
- return Spliterators.spliterator
- (this, Spliterator.SIZED | Spliterator.DISTINCT);
+ removeNode(hash, key, null, false, true);
+ }
+ else if (v != null) {
+ if (t != null)
+ t.putTreeVal(this, tab, hash, key, v);
+ else {
+ tab[i] = newNode(hash, key, v, first);
+ if (binCount >= TREEIFY_THRESHOLD - 1)
+ treeifyBin(tab, hash);
+ }
+ ++modCount;
+ ++size;
+ afterNodeInsertion(true);
+ }
+ return v;
+ }
+
+ public V merge(K key, V value,
+ BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+ if (remappingFunction == null)
+ throw new NullPointerException();
+ int hash = hash(key);
+ Node<K,V>[] tab; Node<K,V> first; int n, i;
+ int binCount = 0;
+ TreeNode<K,V> t = null;
+ Node<K,V> old = null;
+ if (size > threshold || (tab = table) == null ||
+ (n = tab.length) == 0)
+ n = (tab = resize()).length;
+ if ((first = tab[i = (n - 1) & hash]) != null) {
+ if (first instanceof TreeNode)
+ old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
+ else {
+ Node<K,V> e = first; K k;
+ do {
+ if (e.hash == hash &&
+ ((k = e.key) == key || (key != null && key.equals(k)))) {
+ old = e;
+ break;
+ }
+ ++binCount;
+ } while ((e = e.next) != null);
+ }
+ }
+ if (old != null) {
+ V v = remappingFunction.apply(old.value, value);
+ if (v != null) {
+ old.value = v;
+ afterNodeAccess(old);
+ }
+ else
+ removeNode(hash, key, null, false, true);
+ return v;
}
+ if (value != null) {
+ if (t != null)
+ t.putTreeVal(this, tab, hash, key, value);
+ else {
+ tab[i] = newNode(hash, key, value, first);
+ if (binCount >= TREEIFY_THRESHOLD - 1)
+ treeifyBin(tab, hash);
+ }
+ ++modCount;
+ ++size;
+ afterNodeInsertion(true);
+ }
+ return value;
+ }
+
+ public void forEach(BiConsumer<? super K, ? super V> action) {
+ Node<K,V>[] tab;
+ if (action == null)
+ throw new NullPointerException();
+ if (size > 0 && (tab = table) != null) {
+ int mc = modCount;
+ for (int i = 0; i < tab.length; ++i) {
+ for (Node<K,V> e = tab[i]; e != null; e = e.next)
+ action.accept(e.key, e.value);
+ }
+ if (modCount != mc)
+ throw new ConcurrentModificationException();
+ }
+ }
+
+ public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+ Node<K,V>[] tab;
+ if (function == null)
+ throw new NullPointerException();
+ if (size > 0 && (tab = table) != null) {
+ int mc = modCount;
+ for (int i = 0; i < tab.length; ++i) {
+ for (Node<K,V> e = tab[i]; e != null; e = e.next) {
+ e.value = function.apply(e.key, e.value);
+ }
+ }
+ if (modCount != mc)
+ throw new ConcurrentModificationException();
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ // Cloning and serialization
+
+ /**
+ * Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and
+ * values themselves are not cloned.
+ *
+ * @return a shallow copy of this map
+ */
+ @SuppressWarnings("unchecked")
+ public Object clone() {
+ HashMap<K,V> result;
+ try {
+ result = (HashMap<K,V>)super.clone();
+ } catch (CloneNotSupportedException e) {
+ // this shouldn't happen, since we are Cloneable
+ throw new InternalError(e);
+ }
+ result.reinitialize();
+ result.putMapEntries(this, false);
+ return result;
+ }
+
+ // These methods are also used when serializing HashSets
+ final float loadFactor() { return loadFactor; }
+ final int capacity() {
+ return (table != null) ? table.length :
+ (threshold > 0) ? threshold :
+ DEFAULT_INITIAL_CAPACITY;
}
/**
@@ -2631,118 +1326,143 @@
* emitted in no particular order.
*/
private void writeObject(java.io.ObjectOutputStream s)
- throws IOException
- {
+ throws IOException {
+ int buckets = capacity();
// Write out the threshold, loadfactor, and any hidden stuff
s.defaultWriteObject();
-
- // Write out number of buckets
- if (table==EMPTY_TABLE) {
- s.writeInt(roundUpToPowerOf2(threshold));
- } else {
- s.writeInt(table.length);
- }
-
- // Write out size (number of Mappings)
+ s.writeInt(buckets);
s.writeInt(size);
-
- // Write out keys and values (alternating)
- if (size > 0) {
- for(Map.Entry<K,V> e : entrySet0()) {
- s.writeObject(e.getKey());
- s.writeObject(e.getValue());
- }
- }
+ internalWriteEntries(s);
}
- private static final long serialVersionUID = 362498820763181265L;
-
/**
* Reconstitute the {@code HashMap} instance from a stream (i.e.,
* deserialize it).
*/
private void readObject(java.io.ObjectInputStream s)
- throws IOException, ClassNotFoundException
- {
+ throws IOException, ClassNotFoundException {
// Read in the threshold (ignored), loadfactor, and any hidden stuff
s.defaultReadObject();
- if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
+ reinitialize();
+ if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new InvalidObjectException("Illegal load factor: " +
- loadFactor);
- }
-
- // set other fields that need values
- if (Holder.USE_HASHSEED) {
- int seed = ThreadLocalRandom.current().nextInt();
- Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET,
- (seed != 0) ? seed : 1);
- }
- table = EMPTY_TABLE;
-
- // Read in number of buckets
- s.readInt(); // ignored.
-
- // Read number of mappings
- int mappings = s.readInt();
+ loadFactor);
+ s.readInt(); // Read and ignore number of buckets
+ int mappings = s.readInt(); // Read number of mappings (size)
if (mappings < 0)
throw new InvalidObjectException("Illegal mappings count: " +
- mappings);
-
- // capacity chosen by number of mappings and desired load (if >= 0.25)
- int capacity = (int) Math.min(
- mappings * Math.min(1 / loadFactor, 4.0f),
- // we have limits...
- HashMap.MAXIMUM_CAPACITY);
+ mappings);
+ else if (mappings > 0) { // (if zero, use defaults)
+ // Size the table using given load factor only if within
+ // range of 0.25...4.0
+ float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
+ float fc = (float)mappings / lf + 1.0f;
+ int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
+ DEFAULT_INITIAL_CAPACITY :
+ (fc >= MAXIMUM_CAPACITY) ?
+ MAXIMUM_CAPACITY :
+ tableSizeFor((int)fc));
+ float ft = (float)cap * lf;
+ threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
+ (int)ft : Integer.MAX_VALUE);
+ @SuppressWarnings({"rawtypes","unchecked"})
+ Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
+ table = tab;
- // allocate the bucket array;
- if (mappings > 0) {
- inflateTable(capacity);
- } else {
- threshold = capacity;
- }
-
- init(); // Give subclass a chance to do its thing.
-
- // Read the keys and values, and put the mappings in the HashMap
- for (int i=0; i<mappings; i++) {
- @SuppressWarnings("unchecked")
- K key = (K) s.readObject();
- @SuppressWarnings("unchecked")
- V value = (V) s.readObject();
- putForCreate(key, value);
+ // Read the keys and values, and put the mappings in the HashMap
+ for (int i = 0; i < mappings; i++) {
+ @SuppressWarnings("unchecked")
+ K key = (K) s.readObject();
+ @SuppressWarnings("unchecked")
+ V value = (V) s.readObject();
+ putVal(hash(key), key, value, false, false);
+ }
}
}
- // These methods are used when serializing HashSets
- int capacity() { return table.length; }
- float loadFactor() { return loadFactor; }
+ /* ------------------------------------------------------------ */
+ // iterators
+
+ abstract class HashIterator {
+ Node<K,V> next; // next entry to return
+ Node<K,V> current; // current entry
+ int expectedModCount; // for fast-fail
+ int index; // current slot
+
+ HashIterator() {
+ expectedModCount = modCount;
+ Node<K,V>[] t = table;
+ current = next = null;
+ index = 0;
+ if (t != null && size > 0) { // advance to first entry
+ do {} while (index < t.length && (next = t[index++]) == null);
+ }
+ }
+
+ public final boolean hasNext() {
+ return next != null;
+ }
- /**
- * Standin until HM overhaul; based loosely on Weak and Identity HM.
- */
+ final Node<K,V> nextNode() {
+ Node<K,V>[] t;
+ Node<K,V> e = next;
+ if (modCount != expectedModCount)
+ throw new ConcurrentModificationException();
+ if (e == null)
+ throw new NoSuchElementException();
+ if ((next = (current = e).next) == null && (t = table) != null) {
+ do {} while (index < t.length && (next = t[index++]) == null);
+ }
+ return e;
+ }
+
+ public final void remove() {
+ Node<K,V> p = current;
+ if (p == null)
+ throw new IllegalStateException();
+ if (modCount != expectedModCount)
+ throw new ConcurrentModificationException();
+ current = null;
+ K key = p.key;
+ removeNode(hash(key), key, null, false, false);
+ expectedModCount = modCount;
+ }
+ }
+
+ final class KeyIterator extends HashIterator
+ implements Iterator<K> {
+ public final K next() { return nextNode().key; }
+ }
+
+ final class ValueIterator extends HashIterator
+ implements Iterator<V> {
+ public final V next() { return nextNode().value; }
+ }
+
+ final class EntryIterator extends HashIterator
+ implements Iterator<Map.Entry<K,V>> {
+ public final Map.Entry<K,V> next() { return nextNode(); }
+ }
+
+ /* ------------------------------------------------------------ */
+ // spliterators
+
static class HashMapSpliterator<K,V> {
final HashMap<K,V> map;
- Object current; // current node, can be Entry or TreeNode
+ Node<K,V> current; // current node
int index; // current index, modified on advance/split
int fence; // one past last index
int est; // size estimate
int expectedModCount; // for comodification checks
- boolean acceptedNull; // Have we accepted the null key?
- // Without this, we can't distinguish
- // between being at the very beginning (and
- // needing to accept null), or being at the
- // end of the list in bin 0. In both cases,
- // current == null && index == 0.
HashMapSpliterator(HashMap<K,V> m, int origin,
- int fence, int est,
- int expectedModCount) {
+ int fence, int est,
+ int expectedModCount) {
this.map = m;
this.index = origin;
this.fence = fence;
this.est = est;
this.expectedModCount = expectedModCount;
- this.acceptedNull = false;
}
final int getFence() { // initialize fence and size on first use
@@ -2751,7 +1471,8 @@
HashMap<K,V> m = map;
est = m.size;
expectedModCount = m.modCount;
- hi = fence = m.table.length;
+ Node<K,V>[] tab = m.table;
+ hi = fence = (tab == null) ? 0 : tab.length;
}
return hi;
}
@@ -2772,56 +1493,33 @@
public KeySpliterator<K,V> trySplit() {
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
- if (lo >= mid || current != null) {
- return null;
- } else {
- KeySpliterator<K,V> retVal = new KeySpliterator<K,V>(map, lo,
- index = mid, est >>>= 1, expectedModCount);
- // Only 'this' Spliterator chould check for null.
- retVal.acceptedNull = true;
- return retVal;
- }
+ return (lo >= mid || current != null) ? null :
+ new KeySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+ expectedModCount);
}
- @SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super K> action) {
int i, hi, mc;
if (action == null)
throw new NullPointerException();
HashMap<K,V> m = map;
- Object[] tab = m.table;
+ Node<K,V>[] tab = m.table;
if ((hi = fence) < 0) {
mc = expectedModCount = m.modCount;
- hi = fence = tab.length;
+ hi = fence = (tab == null) ? 0 : tab.length;
}
else
mc = expectedModCount;
-
- if (!acceptedNull) {
- acceptedNull = true;
- if (m.nullKeyEntry != null) {
- action.accept(m.nullKeyEntry.key);
- }
- }
- if (tab.length >= hi && (i = index) >= 0 &&
- (i < (index = hi) || current != null)) {
- Object p = current;
+ if (tab != null && tab.length >= hi &&
+ (i = index) >= 0 && (i < (index = hi) || current != null)) {
+ Node<K,V> p = current;
current = null;
do {
- if (p == null) {
+ if (p == null)
p = tab[i++];
- if (p instanceof HashMap.TreeBin) {
- p = ((HashMap.TreeBin)p).first;
- }
- } else {
- HashMap.Entry<K,V> entry;
- if (p instanceof HashMap.Entry) {
- entry = (HashMap.Entry<K,V>)p;
- } else {
- entry = (HashMap.Entry<K,V>)((TreeNode)p).entry;
- }
- action.accept(entry.key);
- p = entry.next;
+ else {
+ action.accept(p.key);
+ p = p.next;
}
} while (p != null || i < hi);
if (m.modCount != mc)
@@ -2829,39 +1527,18 @@
}
}
- @SuppressWarnings("unchecked")
public boolean tryAdvance(Consumer<? super K> action) {
int hi;
if (action == null)
throw new NullPointerException();
- Object[] tab = map.table;
- hi = getFence();
-
- if (!acceptedNull) {
- acceptedNull = true;
- if (map.nullKeyEntry != null) {
- action.accept(map.nullKeyEntry.key);
- if (map.modCount != expectedModCount)
- throw new ConcurrentModificationException();
- return true;
- }
- }
- if (tab.length >= hi && index >= 0) {
+ Node<K,V>[] tab = map.table;
+ if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
while (current != null || index < hi) {
- if (current == null) {
+ if (current == null)
current = tab[index++];
- if (current instanceof HashMap.TreeBin) {
- current = ((HashMap.TreeBin)current).first;
- }
- } else {
- HashMap.Entry<K,V> entry;
- if (current instanceof HashMap.Entry) {
- entry = (HashMap.Entry<K,V>)current;
- } else {
- entry = (HashMap.Entry<K,V>)((TreeNode)current).entry;
- }
- K k = entry.key;
- current = entry.next;
+ else {
+ K k = current.key;
+ current = current.next;
action.accept(k);
if (map.modCount != expectedModCount)
throw new ConcurrentModificationException();
@@ -2888,56 +1565,33 @@
public ValueSpliterator<K,V> trySplit() {
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
- if (lo >= mid || current != null) {
- return null;
- } else {
- ValueSpliterator<K,V> retVal = new ValueSpliterator<K,V>(map,
- lo, index = mid, est >>>= 1, expectedModCount);
- // Only 'this' Spliterator chould check for null.
- retVal.acceptedNull = true;
- return retVal;
- }
+ return (lo >= mid || current != null) ? null :
+ new ValueSpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+ expectedModCount);
}
- @SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super V> action) {
int i, hi, mc;
if (action == null)
throw new NullPointerException();
HashMap<K,V> m = map;
- Object[] tab = m.table;
+ Node<K,V>[] tab = m.table;
if ((hi = fence) < 0) {
mc = expectedModCount = m.modCount;
- hi = fence = tab.length;
+ hi = fence = (tab == null) ? 0 : tab.length;
}
else
mc = expectedModCount;
-
- if (!acceptedNull) {
- acceptedNull = true;
- if (m.nullKeyEntry != null) {
- action.accept(m.nullKeyEntry.value);
- }
- }
- if (tab.length >= hi && (i = index) >= 0 &&
- (i < (index = hi) || current != null)) {
- Object p = current;
+ if (tab != null && tab.length >= hi &&
+ (i = index) >= 0 && (i < (index = hi) || current != null)) {
+ Node<K,V> p = current;
current = null;
do {
- if (p == null) {
+ if (p == null)
p = tab[i++];
- if (p instanceof HashMap.TreeBin) {
- p = ((HashMap.TreeBin)p).first;
- }
- } else {
- HashMap.Entry<K,V> entry;
- if (p instanceof HashMap.Entry) {
- entry = (HashMap.Entry<K,V>)p;
- } else {
- entry = (HashMap.Entry<K,V>)((TreeNode)p).entry;
- }
- action.accept(entry.value);
- p = entry.next;
+ else {
+ action.accept(p.value);
+ p = p.next;
}
} while (p != null || i < hi);
if (m.modCount != mc)
@@ -2945,39 +1599,18 @@
}
}
- @SuppressWarnings("unchecked")
public boolean tryAdvance(Consumer<? super V> action) {
int hi;
if (action == null)
throw new NullPointerException();
- Object[] tab = map.table;
- hi = getFence();
-
- if (!acceptedNull) {
- acceptedNull = true;
- if (map.nullKeyEntry != null) {
- action.accept(map.nullKeyEntry.value);
- if (map.modCount != expectedModCount)
- throw new ConcurrentModificationException();
- return true;
- }
- }
- if (tab.length >= hi && index >= 0) {
+ Node<K,V>[] tab = map.table;
+ if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
while (current != null || index < hi) {
- if (current == null) {
+ if (current == null)
current = tab[index++];
- if (current instanceof HashMap.TreeBin) {
- current = ((HashMap.TreeBin)current).first;
- }
- } else {
- HashMap.Entry<K,V> entry;
- if (current instanceof HashMap.Entry) {
- entry = (Entry<K,V>)current;
- } else {
- entry = (Entry<K,V>)((TreeNode)current).entry;
- }
- V v = entry.value;
- current = entry.next;
+ else {
+ V v = current.value;
+ current = current.next;
action.accept(v);
if (map.modCount != expectedModCount)
throw new ConcurrentModificationException();
@@ -3003,57 +1636,33 @@
public EntrySpliterator<K,V> trySplit() {
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
- if (lo >= mid || current != null) {
- return null;
- } else {
- EntrySpliterator<K,V> retVal = new EntrySpliterator<K,V>(map,
- lo, index = mid, est >>>= 1, expectedModCount);
- // Only 'this' Spliterator chould check for null.
- retVal.acceptedNull = true;
- return retVal;
- }
+ return (lo >= mid || current != null) ? null :
+ new EntrySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+ expectedModCount);
}
- @SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {
int i, hi, mc;
if (action == null)
throw new NullPointerException();
HashMap<K,V> m = map;
- Object[] tab = m.table;
+ Node<K,V>[] tab = m.table;
if ((hi = fence) < 0) {
mc = expectedModCount = m.modCount;
- hi = fence = tab.length;
+ hi = fence = (tab == null) ? 0 : tab.length;
}
else
mc = expectedModCount;
-
- if (!acceptedNull) {
- acceptedNull = true;
- if (m.nullKeyEntry != null) {
- action.accept(m.nullKeyEntry);
- }
- }
- if (tab.length >= hi && (i = index) >= 0 &&
- (i < (index = hi) || current != null)) {
- Object p = current;
+ if (tab != null && tab.length >= hi &&
+ (i = index) >= 0 && (i < (index = hi) || current != null)) {
+ Node<K,V> p = current;
current = null;
do {
- if (p == null) {
+ if (p == null)
p = tab[i++];
- if (p instanceof HashMap.TreeBin) {
- p = ((HashMap.TreeBin)p).first;
- }
- } else {
- HashMap.Entry<K,V> entry;
- if (p instanceof HashMap.Entry) {
- entry = (HashMap.Entry<K,V>)p;
- } else {
- entry = (HashMap.Entry<K,V>)((TreeNode)p).entry;
- }
- action.accept(entry);
- p = entry.next;
-
+ else {
+ action.accept(p);
+ p = p.next;
}
} while (p != null || i < hi);
if (m.modCount != mc)
@@ -3061,38 +1670,18 @@
}
}
- @SuppressWarnings("unchecked")
public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
int hi;
if (action == null)
throw new NullPointerException();
- Object[] tab = map.table;
- hi = getFence();
-
- if (!acceptedNull) {
- acceptedNull = true;
- if (map.nullKeyEntry != null) {
- action.accept(map.nullKeyEntry);
- if (map.modCount != expectedModCount)
- throw new ConcurrentModificationException();
- return true;
- }
- }
- if (tab.length >= hi && index >= 0) {
+ Node<K,V>[] tab = map.table;
+ if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
while (current != null || index < hi) {
- if (current == null) {
+ if (current == null)
current = tab[index++];
- if (current instanceof HashMap.TreeBin) {
- current = ((HashMap.TreeBin)current).first;
- }
- } else {
- HashMap.Entry<K,V> e;
- if (current instanceof HashMap.Entry) {
- e = (Entry<K,V>)current;
- } else {
- e = (Entry<K,V>)((TreeNode)current).entry;
- }
- current = e.next;
+ else {
+ Node<K,V> e = current;
+ current = current.next;
action.accept(e);
if (map.modCount != expectedModCount)
throw new ConcurrentModificationException();
@@ -3108,4 +1697,664 @@
Spliterator.DISTINCT;
}
}
+
+ /* ------------------------------------------------------------ */
+ // LinkedHashMap support
+
+
+ /*
+ * The following package-protected methods are designed to be
+ * overridden by LinkedHashMap, but not by any other subclass.
+ * Nearly all other internal methods are also package-protected
+ * but are declared final, so can be used by LinkedHashMap, view
+ * classes, and HashSet.
+ */
+
+ // Create a regular (non-tree) node
+ Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) {
+ return new Node<K,V>(hash, key, value, next);
+ }
+
+ // For conversion from TreeNodes to plain nodes
+ Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
+ return new Node<K,V>(p.hash, p.key, p.value, next);
+ }
+
+ // Create a tree bin node
+ TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
+ return new TreeNode<K,V>(hash, key, value, next);
+ }
+
+ // For treeifyBin
+ TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
+ return new TreeNode<K,V>(p.hash, p.key, p.value, next);
+ }
+
+ /**
+ * Reset to initial default state. Called by clone and readObject.
+ */
+ void reinitialize() {
+ table = null;
+ entrySet = null;
+ keySet = null;
+ values = null;
+ modCount = 0;
+ threshold = 0;
+ size = 0;
+ }
+
+ // Callbacks to allow LinkedHashMap post-actions
+ void afterNodeAccess(Node<K,V> p) { }
+ void afterNodeInsertion(boolean evict) { }
+ void afterNodeRemoval(Node<K,V> p) { }
+
+ // Called only from writeObject, to ensure compatible ordering.
+ void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
+ Node<K,V>[] tab;
+ if (size > 0 && (tab = table) != null) {
+ for (int i = 0; i < tab.length; ++i) {
+ for (Node<K,V> e = tab[i]; e != null; e = e.next) {
+ s.writeObject(e.key);
+ s.writeObject(e.value);
+ }
+ }
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ // Tree bins
+
+ /**
+ * Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn
+ * extends Node) so can be used as extension of either regular or
+ * linked node.
+ */
+ static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
+ TreeNode<K,V> parent; // red-black tree links
+ TreeNode<K,V> left;
+ TreeNode<K,V> right;
+ TreeNode<K,V> prev; // needed to unlink next upon deletion
+ boolean red;
+ TreeNode(int hash, K key, V val, Node<K,V> next) {
+ super(hash, key, val, next);
+ }
+
+ /**
+ * Returns root of tree containing this node.
+ */
+ final TreeNode<K,V> root() {
+ for (TreeNode<K,V> r = this, p;;) {
+ if ((p = r.parent) == null)
+ return r;
+ r = p;
+ }
+ }
+
+ /**
+ * Ensures that the given root is the first node of its bin.
+ */
+ static <K,V> void moveRootToFront(Node<K,V>[] tab, TreeNode<K,V> root) {
+ int n;
+ if (root != null && tab != null && (n = tab.length) > 0) {
+ int index = (n - 1) & root.hash;
+ TreeNode<K,V> first = (TreeNode<K,V>)tab[index];
+ if (root != first) {
+ Node<K,V> rn;
+ tab[index] = root;
+ TreeNode<K,V> rp = root.prev;
+ if ((rn = root.next) != null)
+ ((TreeNode<K,V>)rn).prev = rp;
+ if (rp != null)
+ rp.next = rn;
+ if (first != null)
+ first.prev = root;
+ root.next = first;
+ root.prev = null;
+ }
+ assert checkInvariants(root);
+ }
+ }
+
+ /**
+ * Finds the node starting at root p with the given hash and key.
+ * The kc argument caches comparableClassFor(key) upon first use
+ * comparing keys.
+ */
+ final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
+ TreeNode<K,V> p = this;
+ do {
+ int ph, dir; K pk;
+ TreeNode<K,V> pl = p.left, pr = p.right, q;
+ if ((ph = p.hash) > h)
+ p = pl;
+ else if (ph < h)
+ p = pr;
+ else if ((pk = p.key) == k || (k != null && k.equals(pk)))
+ return p;
+ else if (pl == null)
+ p = pr;
+ else if (pr == null)
+ p = pl;
+ else if ((kc != null ||
+ (kc = comparableClassFor(k)) != null) &&
+ (dir = compareComparables(kc, k, pk)) != 0)
+ p = (dir < 0) ? pl : pr;
+ else if ((q = pr.find(h, k, kc)) != null)
+ return q;
+ else
+ p = pl;
+ } while (p != null);
+ return null;
+ }
+
+ /**
+ * Calls find for root node.
+ */
+ final TreeNode<K,V> getTreeNode(int h, Object k) {
+ return ((parent != null) ? root() : this).find(h, k, null);
+ }
+
+ /**
+ * Tie-breaking utility for ordering insertions when equal
+ * hashCodes and non-comparable. We don't require a total
+ * order, just a consistent insertion rule to maintain
+ * equivalence across rebalancings. Tie-breaking further than
+ * necessary simplifies testing a bit.
+ */
+ static int tieBreakOrder(Object a, Object b) {
+ int d;
+ if (a == null || b == null ||
+ (d = a.getClass().getName().
+ compareTo(b.getClass().getName())) == 0)
+ d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
+ -1 : 1);
+ return d;
+ }
+
+ /**
+ * Forms tree of the nodes linked from this node.
+ * @return root of tree
+ */
+ final void treeify(Node<K,V>[] tab) {
+ TreeNode<K,V> root = null;
+ for (TreeNode<K,V> x = this, next; x != null; x = next) {
+ next = (TreeNode<K,V>)x.next;
+ x.left = x.right = null;
+ if (root == null) {
+ x.parent = null;
+ x.red = false;
+ root = x;
+ }
+ else {
+ K k = x.key;
+ int h = x.hash;
+ Class<?> kc = null;
+ for (TreeNode<K,V> p = root;;) {
+ int dir, ph;
+ K pk = p.key;
+ if ((ph = p.hash) > h)
+ dir = -1;
+ else if (ph < h)
+ dir = 1;
+ else if ((kc == null &&
+ (kc = comparableClassFor(k)) == null) ||
+ (dir = compareComparables(kc, k, pk)) == 0)
+ dir = tieBreakOrder(k, pk);
+
+ TreeNode<K,V> xp = p;
+ if ((p = (dir <= 0) ? p.left : p.right) == null) {
+ x.parent = xp;
+ if (dir <= 0)
+ xp.left = x;
+ else
+ xp.right = x;
+ root = balanceInsertion(root, x);
+ break;
+ }
+ }
+ }
+ }
+ moveRootToFront(tab, root);
+ }
+
+ /**
+ * Returns a list of non-TreeNodes replacing those linked from
+ * this node.
+ */
+ final Node<K,V> untreeify(HashMap<K,V> map) {
+ Node<K,V> hd = null, tl = null;
+ for (Node<K,V> q = this; q != null; q = q.next) {
+ Node<K,V> p = map.replacementNode(q, null);
+ if (tl == null)
+ hd = p;
+ else
+ tl.next = p;
+ tl = p;
+ }
+ return hd;
+ }
+
+ /**
+ * Tree version of putVal.
+ */
+ final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,
+ int h, K k, V v) {
+ Class<?> kc = null;
+ boolean searched = false;
+ TreeNode<K,V> root = (parent != null) ? root() : this;
+ for (TreeNode<K,V> p = root;;) {
+ int dir, ph; K pk;
+ if ((ph = p.hash) > h)
+ dir = -1;
+ else if (ph < h)
+ dir = 1;
+ else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
+ return p;
+ else if ((kc == null &&
+ (kc = comparableClassFor(k)) == null) ||
+ (dir = compareComparables(kc, k, pk)) == 0) {
+ if (!searched) {
+ TreeNode<K,V> q, ch;
+ searched = true;
+ if (((ch = p.left) != null &&
+ (q = ch.find(h, k, kc)) != null) ||
+ ((ch = p.right) != null &&
+ (q = ch.find(h, k, kc)) != null))
+ return q;
+ }
+ dir = tieBreakOrder(k, pk);
+ }
+
+ TreeNode<K,V> xp = p;
+ if ((p = (dir <= 0) ? p.left : p.right) == null) {
+ Node<K,V> xpn = xp.next;
+ TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);
+ if (dir <= 0)
+ xp.left = x;
+ else
+ xp.right = x;
+ xp.next = x;
+ x.parent = x.prev = xp;
+ if (xpn != null)
+ ((TreeNode<K,V>)xpn).prev = x;
+ moveRootToFront(tab, balanceInsertion(root, x));
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Removes the given node, that must be present before this call.
+ * This is messier than typical red-black deletion code because we
+ * cannot swap the contents of an interior node with a leaf
+ * successor that is pinned by "next" pointers that are accessible
+ * independently during traversal. So instead we swap the tree
+ * linkages. If the current tree appears to have too few nodes,
+ * the bin is converted back to a plain bin. (The test triggers
+ * somewhere between 2 and 6 nodes, depending on tree structure).
+ */
+ final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab,
+ boolean movable) {
+ int n;
+ if (tab == null || (n = tab.length) == 0)
+ return;
+ int index = (n - 1) & hash;
+ TreeNode<K,V> first = (TreeNode<K,V>)tab[index], root = first, rl;
+ TreeNode<K,V> succ = (TreeNode<K,V>)next, pred = prev;
+ if (pred == null)
+ tab[index] = first = succ;
+ else
+ pred.next = succ;
+ if (succ != null)
+ succ.prev = pred;
+ if (first == null)
+ return;
+ if (root.parent != null)
+ root = root.root();
+ if (root == null || root.right == null ||
+ (rl = root.left) == null || rl.left == null) {
+ tab[index] = first.untreeify(map); // too small
+ return;
+ }
+ TreeNode<K,V> p = this, pl = left, pr = right, replacement;
+ if (pl != null && pr != null) {
+ TreeNode<K,V> s = pr, sl;
+ while ((sl = s.left) != null) // find successor
+ s = sl;
+ boolean c = s.red; s.red = p.red; p.red = c; // swap colors
+ TreeNode<K,V> sr = s.right;
+ TreeNode<K,V> pp = p.parent;
+ if (s == pr) { // p was s's direct parent
+ p.parent = s;
+ s.right = p;
+ }
+ else {
+ TreeNode<K,V> sp = s.parent;
+ if ((p.parent = sp) != null) {
+ if (s == sp.left)
+ sp.left = p;
+ else
+ sp.right = p;
+ }
+ if ((s.right = pr) != null)
+ pr.parent = s;
+ }
+ p.left = null;
+ if ((p.right = sr) != null)
+ sr.parent = p;
+ if ((s.left = pl) != null)
+ pl.parent = s;
+ if ((s.parent = pp) == null)
+ root = s;
+ else if (p == pp.left)
+ pp.left = s;
+ else
+ pp.right = s;
+ if (sr != null)
+ replacement = sr;
+ else
+ replacement = p;
+ }
+ else if (pl != null)
+ replacement = pl;
+ else if (pr != null)
+ replacement = pr;
+ else
+ replacement = p;
+ if (replacement != p) {
+ TreeNode<K,V> pp = replacement.parent = p.parent;
+ if (pp == null)
+ root = replacement;
+ else if (p == pp.left)
+ pp.left = replacement;
+ else
+ pp.right = replacement;
+ p.left = p.right = p.parent = null;
+ }
+
+ TreeNode<K,V> r = p.red ? root : balanceDeletion(root, replacement);
+
+ if (replacement == p) { // detach
+ TreeNode<K,V> pp = p.parent;
+ p.parent = null;
+ if (pp != null) {
+ if (p == pp.left)
+ pp.left = null;
+ else if (p == pp.right)
+ pp.right = null;
+ }
+ }
+ if (movable)
+ moveRootToFront(tab, r);
+ }
+
+ /**
+ * Splits nodes in a tree bin into lower and upper tree bins,
+ * or untreeifies if now too small. Called only from resize;
+ * see above discussion about split bits and indices.
+ *
+ * @param map the map
+ * @param tab the table for recording bin heads
+ * @param index the index of the table being split
+ * @param bit the bit of hash to split on
+ */
+ final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
+ TreeNode<K,V> b = this;
+ // Relink into lo and hi lists, preserving order
+ TreeNode<K,V> loHead = null, loTail = null;
+ TreeNode<K,V> hiHead = null, hiTail = null;
+ int lc = 0, hc = 0;
+ for (TreeNode<K,V> e = b, next; e != null; e = next) {
+ next = (TreeNode<K,V>)e.next;
+ e.next = null;
+ if ((e.hash & bit) == 0) {
+ if ((e.prev = loTail) == null)
+ loHead = e;
+ else
+ loTail.next = e;
+ loTail = e;
+ ++lc;
+ }
+ else {
+ if ((e.prev = hiTail) == null)
+ hiHead = e;
+ else
+ hiTail.next = e;
+ hiTail = e;
+ ++hc;
+ }
+ }
+
+ if (loHead != null) {
+ if (lc <= UNTREEIFY_THRESHOLD)
+ tab[index] = loHead.untreeify(map);
+ else {
+ tab[index] = loHead;
+ if (hiHead != null) // (else is already treeified)
+ loHead.treeify(tab);
+ }
+ }
+ if (hiHead != null) {
+ if (hc <= UNTREEIFY_THRESHOLD)
+ tab[index + bit] = hiHead.untreeify(map);
+ else {
+ tab[index + bit] = hiHead;
+ if (loHead != null)
+ hiHead.treeify(tab);
+ }
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ // Red-black tree methods, all adapted from CLR
+
+ static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,
+ TreeNode<K,V> p) {
+ TreeNode<K,V> r, pp, rl;
+ if (p != null && (r = p.right) != null) {
+ if ((rl = p.right = r.left) != null)
+ rl.parent = p;
+ if ((pp = r.parent = p.parent) == null)
+ (root = r).red = false;
+ else if (pp.left == p)
+ pp.left = r;
+ else
+ pp.right = r;
+ r.left = p;
+ p.parent = r;
+ }
+ return root;
+ }
+
+ static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,
+ TreeNode<K,V> p) {
+ TreeNode<K,V> l, pp, lr;
+ if (p != null && (l = p.left) != null) {
+ if ((lr = p.left = l.right) != null)
+ lr.parent = p;
+ if ((pp = l.parent = p.parent) == null)
+ (root = l).red = false;
+ else if (pp.right == p)
+ pp.right = l;
+ else
+ pp.left = l;
+ l.right = p;
+ p.parent = l;
+ }
+ return root;
+ }
+
+ static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
+ TreeNode<K,V> x) {
+ x.red = true;
+ for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
+ if ((xp = x.parent) == null) {
+ x.red = false;
+ return x;
+ }
+ else if (!xp.red || (xpp = xp.parent) == null)
+ return root;
+ if (xp == (xppl = xpp.left)) {
+ if ((xppr = xpp.right) != null && xppr.red) {
+ xppr.red = false;
+ xp.red = false;
+ xpp.red = true;
+ x = xpp;
+ }
+ else {
+ if (x == xp.right) {
+ root = rotateLeft(root, x = xp);
+ xpp = (xp = x.parent) == null ? null : xp.parent;
+ }
+ if (xp != null) {
+ xp.red = false;
+ if (xpp != null) {
+ xpp.red = true;
+ root = rotateRight(root, xpp);
+ }
+ }
+ }
+ }
+ else {
+ if (xppl != null && xppl.red) {
+ xppl.red = false;
+ xp.red = false;
+ xpp.red = true;
+ x = xpp;
+ }
+ else {
+ if (x == xp.left) {
+ root = rotateRight(root, x = xp);
+ xpp = (xp = x.parent) == null ? null : xp.parent;
+ }
+ if (xp != null) {
+ xp.red = false;
+ if (xpp != null) {
+ xpp.red = true;
+ root = rotateLeft(root, xpp);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
+ TreeNode<K,V> x) {
+ for (TreeNode<K,V> xp, xpl, xpr;;) {
+ if (x == null || x == root)
+ return root;
+ else if ((xp = x.parent) == null) {
+ x.red = false;
+ return x;
+ }
+ else if (x.red) {
+ x.red = false;
+ return root;
+ }
+ else if ((xpl = xp.left) == x) {
+ if ((xpr = xp.right) != null && xpr.red) {
+ xpr.red = false;
+ xp.red = true;
+ root = rotateLeft(root, xp);
+ xpr = (xp = x.parent) == null ? null : xp.right;
+ }
+ if (xpr == null)
+ x = xp;
+ else {
+ TreeNode<K,V> sl = xpr.left, sr = xpr.right;
+ if ((sr == null || !sr.red) &&
+ (sl == null || !sl.red)) {
+ xpr.red = true;
+ x = xp;
+ }
+ else {
+ if (sr == null || !sr.red) {
+ if (sl != null)
+ sl.red = false;
+ xpr.red = true;
+ root = rotateRight(root, xpr);
+ xpr = (xp = x.parent) == null ?
+ null : xp.right;
+ }
+ if (xpr != null) {
+ xpr.red = (xp == null) ? false : xp.red;
+ if ((sr = xpr.right) != null)
+ sr.red = false;
+ }
+ if (xp != null) {
+ xp.red = false;
+ root = rotateLeft(root, xp);
+ }
+ x = root;
+ }
+ }
+ }
+ else { // symmetric
+ if (xpl != null && xpl.red) {
+ xpl.red = false;
+ xp.red = true;
+ root = rotateRight(root, xp);
+ xpl = (xp = x.parent) == null ? null : xp.left;
+ }
+ if (xpl == null)
+ x = xp;
+ else {
+ TreeNode<K,V> sl = xpl.left, sr = xpl.right;
+ if ((sl == null || !sl.red) &&
+ (sr == null || !sr.red)) {
+ xpl.red = true;
+ x = xp;
+ }
+ else {
+ if (sl == null || !sl.red) {
+ if (sr != null)
+ sr.red = false;
+ xpl.red = true;
+ root = rotateLeft(root, xpl);
+ xpl = (xp = x.parent) == null ?
+ null : xp.left;
+ }
+ if (xpl != null) {
+ xpl.red = (xp == null) ? false : xp.red;
+ if ((sl = xpl.left) != null)
+ sl.red = false;
+ }
+ if (xp != null) {
+ xp.red = false;
+ root = rotateRight(root, xp);
+ }
+ x = root;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Recursive invariant check
+ */
+ static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
+ TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
+ tb = t.prev, tn = (TreeNode<K,V>)t.next;
+ if (tb != null && tb.next != t)
+ return false;
+ if (tn != null && tn.prev != t)
+ return false;
+ if (tp != null && t != tp.left && t != tp.right)
+ return false;
+ if (tl != null && (tl.parent != t || tl.hash > t.hash))
+ return false;
+ if (tr != null && (tr.parent != t || tr.hash < t.hash))
+ return false;
+ if (t.red && tl != null && tl.red && tr != null && tr.red)
+ return false;
+ if (tl != null && !checkInvariants(tl))
+ return false;
+ if (tr != null && !checkInvariants(tr))
+ return false;
+ return true;
+ }
+ }
+
}
--- a/jdk/src/share/classes/java/util/Hashtable.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/Hashtable.java Sat Sep 14 20:43:34 2013 +0100
@@ -168,68 +168,6 @@
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = 1421746759512286392L;
- private static class Holder {
- // Unsafe mechanics
- /**
- *
- */
- static final sun.misc.Unsafe UNSAFE;
-
- /**
- * Offset of "final" hashSeed field we must set in
- * readObject() method.
- */
- static final long HASHSEED_OFFSET;
-
- static final boolean USE_HASHSEED;
-
- static {
- String hashSeedProp = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction(
- "jdk.map.useRandomSeed"));
- boolean localBool = (null != hashSeedProp)
- ? Boolean.parseBoolean(hashSeedProp) : false;
- USE_HASHSEED = localBool;
-
- if (USE_HASHSEED) {
- try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
- HASHSEED_OFFSET = UNSAFE.objectFieldOffset(
- Hashtable.class.getDeclaredField("hashSeed"));
- } catch (NoSuchFieldException | SecurityException e) {
- throw new InternalError("Failed to record hashSeed offset", e);
- }
- } else {
- UNSAFE = null;
- HASHSEED_OFFSET = 0;
- }
- }
- }
-
- /**
- * A randomizing value associated with this instance that is applied to
- * hash code of keys to make hash collisions harder to find.
- *
- * Non-final so it can be set lazily, but be sure not to set more than once.
- */
- transient final int hashSeed;
-
- /**
- * Return an initial value for the hashSeed, or 0 if the random seed is not
- * enabled.
- */
- final int initHashSeed() {
- if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) {
- int seed = ThreadLocalRandom.current().nextInt();
- return (seed != 0) ? seed : 1;
- }
- return 0;
- }
-
- private int hash(Object k) {
- return hashSeed ^ k.hashCode();
- }
-
/**
* Constructs a new, empty hashtable with the specified initial
* capacity and the specified load factor.
@@ -251,7 +189,6 @@
this.loadFactor = loadFactor;
table = new Entry<?,?>[initialCapacity];
threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
- hashSeed = initHashSeed();
}
/**
@@ -395,7 +332,7 @@
*/
public synchronized boolean containsKey(Object key) {
Entry<?,?> tab[] = table;
- int hash = hash(key);
+ int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
@@ -423,7 +360,7 @@
@SuppressWarnings("unchecked")
public synchronized V get(Object key) {
Entry<?,?> tab[] = table;
- int hash = hash(key);
+ int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
@@ -488,7 +425,7 @@
rehash();
tab = table;
- hash = hash(key);
+ hash = key.hashCode();
index = (hash & 0x7FFFFFFF) % tab.length;
}
@@ -524,7 +461,7 @@
// Makes sure the key is not already in the hashtable.
Entry<?,?> tab[] = table;
- int hash = hash(key);
+ int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> entry = (Entry<K,V>)tab[index];
@@ -551,7 +488,7 @@
*/
public synchronized V remove(Object key) {
Entry<?,?> tab[] = table;
- int hash = hash(key);
+ int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
@@ -760,7 +697,7 @@
Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
Object key = entry.getKey();
Entry<?,?>[] tab = table;
- int hash = hash(key);
+ int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<?,?> e = tab[index]; e != null; e = e.next)
@@ -775,7 +712,7 @@
Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
Object key = entry.getKey();
Entry<?,?>[] tab = table;
- int hash = hash(key);
+ int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
@@ -975,7 +912,7 @@
// Makes sure the key is not already in the hashtable.
Entry<?,?> tab[] = table;
- int hash = hash(key);
+ int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> entry = (Entry<K,V>)tab[index];
@@ -998,7 +935,7 @@
Objects.requireNonNull(value);
Entry<?,?> tab[] = table;
- int hash = hash(key);
+ int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
@@ -1020,8 +957,10 @@
@Override
public synchronized boolean replace(K key, V oldValue, V newValue) {
+ Objects.requireNonNull(oldValue);
+ Objects.requireNonNull(newValue);
Entry<?,?> tab[] = table;
- int hash = hash(key);
+ int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
@@ -1040,8 +979,9 @@
@Override
public synchronized V replace(K key, V value) {
+ Objects.requireNonNull(value);
Entry<?,?> tab[] = table;
- int hash = hash(key);
+ int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
@@ -1060,7 +1000,7 @@
Objects.requireNonNull(mappingFunction);
Entry<?,?> tab[] = table;
- int hash = hash(key);
+ int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
@@ -1084,7 +1024,7 @@
Objects.requireNonNull(remappingFunction);
Entry<?,?> tab[] = table;
- int hash = hash(key);
+ int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
@@ -1113,7 +1053,7 @@
Objects.requireNonNull(remappingFunction);
Entry<?,?> tab[] = table;
- int hash = hash(key);
+ int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
@@ -1148,7 +1088,7 @@
Objects.requireNonNull(remappingFunction);
Entry<?,?> tab[] = table;
- int hash = hash(key);
+ int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
@@ -1228,13 +1168,6 @@
// Read in the length, threshold, and loadfactor
s.defaultReadObject();
- // set hashMask
- if (Holder.USE_HASHSEED) {
- int seed = ThreadLocalRandom.current().nextInt();
- Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET,
- (seed != 0) ? seed : 1);
- }
-
// Read the original length of the array and number of elements
int origlength = s.readInt();
int elements = s.readInt();
@@ -1282,7 +1215,7 @@
}
// Makes sure the key is not already in the hashtable.
// This should not happen in deserialized version.
- int hash = hash(key);
+ int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
@@ -1347,7 +1280,7 @@
}
public int hashCode() {
- return (Objects.hashCode(key) ^ Objects.hashCode(value));
+ return hash ^ Objects.hashCode(value);
}
public String toString() {
--- a/jdk/src/share/classes/java/util/IdentityHashMap.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/IdentityHashMap.java Sat Sep 14 20:43:34 2013 +0100
@@ -997,6 +997,7 @@
* behavior when c is a smaller "normal" (non-identity-based) Set.
*/
public boolean removeAll(Collection<?> c) {
+ Objects.requireNonNull(c);
boolean modified = false;
for (Iterator<K> i = iterator(); i.hasNext(); ) {
if (c.contains(i.next())) {
@@ -1212,6 +1213,7 @@
* behavior when c is a smaller "normal" (non-identity-based) Set.
*/
public boolean removeAll(Collection<?> c) {
+ Objects.requireNonNull(c);
boolean modified = false;
for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) {
if (c.contains(i.next())) {
--- a/jdk/src/share/classes/java/util/LinkedHashMap.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/LinkedHashMap.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -24,9 +24,12 @@
*/
package java.util;
-import java.io.*;
+
+import java.util.function.Consumer;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
+import java.io.Serializable;
+import java.io.IOException;
/**
* <p>Hash table and linked list implementation of the <tt>Map</tt> interface,
@@ -57,9 +60,9 @@
* order they were presented.)
*
* <p>A special {@link #LinkedHashMap(int,float,boolean) constructor} is
- * provided to create a <tt>LinkedHashMap</tt> whose order of iteration is the
- * order in which its entries were last accessed, from least-recently accessed
- * to most-recently (<i>access-order</i>). This kind of map is well-suited to
+ * provided to create a linked hash map whose order of iteration is the order
+ * in which its entries were last accessed, from least-recently accessed to
+ * most-recently (<i>access-order</i>). This kind of map is well-suited to
* building LRU caches. Invoking the <tt>put</tt> or <tt>get</tt> method
* results in an access to the corresponding entry (assuming it exists after
* the invocation completes). The <tt>putAll</tt> method generates one entry
@@ -155,18 +158,53 @@
* @see Hashtable
* @since 1.4
*/
-
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>
{
+ /*
+ * Implementation note. A previous version of this class was
+ * internally structured a little differently. Because superclass
+ * HashMap now uses trees for some of its nodes, class
+ * LinkedHashMap.Entry is now treated as intermediary node class
+ * that can also be converted to tree form. The name of this
+ * class, LinkedHashMap.Entry, is confusing in several ways in its
+ * current context, but cannot be changed. Otherwise, even though
+ * it is not exported outside this package, some existing source
+ * code is known to have relied on a symbol resolution corner case
+ * rule in calls to removeEldestEntry that suppressed compilation
+ * errors due to ambiguous usages. So, we keep the name to
+ * preserve unmodified compilability.
+ *
+ * The changes in node classes also require using two fields
+ * (head, tail) rather than a pointer to a header node to maintain
+ * the doubly-linked before/after list. This class also
+ * previously used a different style of callback methods upon
+ * access, insertion, and removal.
+ */
+
+ /**
+ * HashMap.Node subclass for normal LinkedHashMap entries.
+ */
+ static class Entry<K,V> extends HashMap.Node<K,V> {
+ Entry<K,V> before, after;
+ Entry(int hash, K key, V value, Node<K,V> next) {
+ super(hash, key, value, next);
+ }
+ }
+
private static final long serialVersionUID = 3801124242820219131L;
/**
- * The head of the doubly linked list.
+ * The head (eldest) of the doubly linked list.
*/
- private transient Entry<K,V> header;
+ transient LinkedHashMap.Entry<K,V> head;
+
+ /**
+ * The tail (youngest) of the doubly linked list.
+ */
+ transient LinkedHashMap.Entry<K,V> tail;
/**
* The iteration ordering method for this linked hash map: <tt>true</tt>
@@ -174,7 +212,125 @@
*
* @serial
*/
- private final boolean accessOrder;
+ final boolean accessOrder;
+
+ // internal utilities
+
+ // link at the end of list
+ private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
+ LinkedHashMap.Entry<K,V> last = tail;
+ tail = p;
+ if (last == null)
+ head = p;
+ else {
+ p.before = last;
+ last.after = p;
+ }
+ }
+
+ // apply src's links to dst
+ private void transferLinks(LinkedHashMap.Entry<K,V> src,
+ LinkedHashMap.Entry<K,V> dst) {
+ LinkedHashMap.Entry<K,V> b = dst.before = src.before;
+ LinkedHashMap.Entry<K,V> a = dst.after = src.after;
+ if (b == null)
+ head = dst;
+ else
+ b.after = dst;
+ if (a == null)
+ tail = dst;
+ else
+ a.before = dst;
+ }
+
+ // overrides of HashMap hook methods
+
+ void reinitialize() {
+ super.reinitialize();
+ head = tail = null;
+ }
+
+ Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
+ LinkedHashMap.Entry<K,V> p =
+ new LinkedHashMap.Entry<K,V>(hash, key, value, e);
+ linkNodeLast(p);
+ return p;
+ }
+
+ Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
+ LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
+ LinkedHashMap.Entry<K,V> t =
+ new LinkedHashMap.Entry<K,V>(q.hash, q.key, q.value, next);
+ transferLinks(q, t);
+ return t;
+ }
+
+ TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
+ TreeNode<K,V> p = new TreeNode<K,V>(hash, key, value, next);
+ linkNodeLast(p);
+ return p;
+ }
+
+ TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
+ LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
+ TreeNode<K,V> t = new TreeNode<K,V>(q.hash, q.key, q.value, next);
+ transferLinks(q, t);
+ return t;
+ }
+
+ void afterNodeRemoval(Node<K,V> e) { // unlink
+ LinkedHashMap.Entry<K,V> p =
+ (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
+ p.before = p.after = null;
+ if (b == null)
+ head = a;
+ else
+ b.after = a;
+ if (a == null)
+ tail = b;
+ else
+ a.before = b;
+ }
+
+ void afterNodeInsertion(boolean evict) { // possibly remove eldest
+ LinkedHashMap.Entry<K,V> first;
+ if (evict && (first = head) != null && removeEldestEntry(first)) {
+ K key = first.key;
+ removeNode(hash(key), key, null, false, true);
+ }
+ }
+
+ void afterNodeAccess(Node<K,V> e) { // move node to last
+ LinkedHashMap.Entry<K,V> last;
+ if (accessOrder && (last = tail) != e) {
+ LinkedHashMap.Entry<K,V> p =
+ (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
+ p.after = null;
+ if (b == null)
+ head = a;
+ else
+ b.after = a;
+ if (a != null)
+ a.before = b;
+ else
+ last = b;
+ if (last == null)
+ head = p;
+ else {
+ p.before = last;
+ last.after = p;
+ }
+ tail = p;
+ ++modCount;
+ }
+ }
+
+ void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
+ for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
+ s.writeObject(e.key);
+ s.writeObject(e.value);
+ }
+ }
/**
* Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
@@ -221,8 +377,9 @@
* @throws NullPointerException if the specified map is null
*/
public LinkedHashMap(Map<? extends K, ? extends V> m) {
- super(m);
+ super();
accessOrder = false;
+ putMapEntries(m, false);
}
/**
@@ -243,16 +400,6 @@
this.accessOrder = accessOrder;
}
- /**
- * Called by superclass constructors and pseudoconstructors (clone,
- * readObject) before any entries are inserted into the map. Initializes
- * the chain.
- */
- @Override
- void init() {
- header = new Entry<>(-1, null, null, null);
- header.before = header.after = header;
- }
/**
* Returns <tt>true</tt> if this map maps one or more keys to the
@@ -263,15 +410,10 @@
* specified value
*/
public boolean containsValue(Object value) {
- // Overridden to take advantage of faster iterator
- if (value==null) {
- for (Entry<?,?> e = header.after; e != header; e = e.after)
- if (e.value==null)
- return true;
- } else {
- for (Entry<?,?> e = header.after; e != header; e = e.after)
- if (value.equals(e.value))
- return true;
+ for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
+ V v = e.value;
+ if (v == value || (value != null && value.equals(v)))
+ return true;
}
return false;
}
@@ -292,10 +434,11 @@
* distinguish these two cases.
*/
public V get(Object key) {
- Entry<K,V> e = (Entry<K,V>)getEntry(key);
- if (e == null)
+ Node<K,V> e;
+ if ((e = getNode(hash(key), key)) == null)
return null;
- e.recordAccess(this);
+ if (accessOrder)
+ afterNodeAccess(e);
return e.value;
}
@@ -305,163 +448,7 @@
*/
public void clear() {
super.clear();
- header.before = header.after = header;
- }
-
- @Override
- public void forEach(BiConsumer<? super K, ? super V> action) {
- Objects.requireNonNull(action);
- int expectedModCount = modCount;
- for (Entry<K, V> entry = header.after; entry != header; entry = entry.after) {
- action.accept(entry.key, entry.value);
-
- if (expectedModCount != modCount) {
- throw new ConcurrentModificationException();
- }
- }
- }
-
- @Override
- public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
- Objects.requireNonNull(function);
- int expectedModCount = modCount;
- for (Entry<K, V> entry = header.after; entry != header; entry = entry.after) {
- entry.value = function.apply(entry.key, entry.value);
-
- if (expectedModCount != modCount) {
- throw new ConcurrentModificationException();
- }
- }
- }
-
- /**
- * LinkedHashMap entry.
- */
- private static class Entry<K,V> extends HashMap.Entry<K,V> {
- // These fields comprise the doubly linked list used for iteration.
- Entry<K,V> before, after;
-
- Entry(int hash, K key, V value, Object next) {
- super(hash, key, value, next);
- }
-
- /**
- * Removes this entry from the linked list.
- */
- private void remove() {
- before.after = after;
- after.before = before;
- }
-
- /**
- * Inserts this entry before the specified existing entry in the list.
- */
- private void addBefore(Entry<K,V> existingEntry) {
- after = existingEntry;
- before = existingEntry.before;
- before.after = this;
- after.before = this;
- }
-
- /**
- * This method is invoked by the superclass whenever the value
- * of a pre-existing entry is read by Map.get or modified by Map.put.
- * If the enclosing Map is access-ordered, it moves the entry
- * to the end of the list; otherwise, it does nothing.
- */
- void recordAccess(HashMap<K,V> m) {
- LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
- if (lm.accessOrder) {
- lm.modCount++;
- remove();
- addBefore(lm.header);
- }
- }
-
- void recordRemoval(HashMap<K,V> m) {
- remove();
- }
- }
-
- private abstract class LinkedHashIterator<T> implements Iterator<T> {
- Entry<K,V> nextEntry = header.after;
- Entry<K,V> lastReturned = null;
-
- /**
- * The modCount value that the iterator believes that the backing
- * List should have. If this expectation is violated, the iterator
- * has detected concurrent modification.
- */
- int expectedModCount = modCount;
-
- public boolean hasNext() {
- return nextEntry != header;
- }
-
- public void remove() {
- if (lastReturned == null)
- throw new IllegalStateException();
- if (modCount != expectedModCount)
- throw new ConcurrentModificationException();
-
- LinkedHashMap.this.remove(lastReturned.key);
- lastReturned = null;
- expectedModCount = modCount;
- }
-
- Entry<K,V> nextEntry() {
- if (modCount != expectedModCount)
- throw new ConcurrentModificationException();
- if (nextEntry == header)
- throw new NoSuchElementException();
-
- Entry<K,V> e = lastReturned = nextEntry;
- nextEntry = e.after;
- return e;
- }
- }
-
- private class KeyIterator extends LinkedHashIterator<K> {
- public K next() { return nextEntry().getKey(); }
- }
-
- private class ValueIterator extends LinkedHashIterator<V> {
- public V next() { return nextEntry().value; }
- }
-
- private class EntryIterator extends LinkedHashIterator<Map.Entry<K,V>> {
- public Map.Entry<K,V> next() { return nextEntry(); }
- }
-
- // These Overrides alter the behavior of superclass view iterator() methods
- Iterator<K> newKeyIterator() { return new KeyIterator(); }
- Iterator<V> newValueIterator() { return new ValueIterator(); }
- Iterator<Map.Entry<K,V>> newEntryIterator() { return new EntryIterator(); }
-
- /**
- * This override alters behavior of superclass put method. It causes newly
- * allocated entry to get inserted at the end of the linked list and
- * removes the eldest entry if appropriate.
- */
- @Override
- void addEntry(int hash, K key, V value, int bucketIndex, boolean checkIfNeedTree) {
- super.addEntry(hash, key, value, bucketIndex, checkIfNeedTree);
-
- // Remove eldest entry if instructed
- Entry<K,V> eldest = header.after;
- if (removeEldestEntry(eldest)) {
- removeEntryForKey(eldest.key);
- }
- }
-
- /*
- * Create a new LinkedHashMap.Entry and setup the before/after pointers
- */
- @Override
- HashMap.Entry<K,V> newEntry(int hash, K key, V value, Object next) {
- Entry<K,V> newEntry = new Entry<>(hash, key, value, next);
- newEntry.addBefore(header);
- return newEntry;
+ head = tail = null;
}
/**
@@ -475,13 +462,13 @@
* <p>Sample use: this override will allow the map to grow up to 100
* entries and then delete the eldest entry each time a new entry is
* added, maintaining a steady state of 100 entries.
- * <pre>{@code
+ * <pre>
* private static final int MAX_ENTRIES = 100;
*
* protected boolean removeEldestEntry(Map.Entry eldest) {
- * return size() > MAX_ENTRIES;
+ * return size() > MAX_ENTRIES;
* }
- * }</pre>
+ * </pre>
*
* <p>This method typically does not modify the map in any way,
* instead allowing the map to modify itself as directed by its
@@ -508,4 +495,241 @@
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
+
+ /**
+ * Returns a {@link Set} view of the keys contained in this map.
+ * The set is backed by the map, so changes to the map are
+ * reflected in the set, and vice-versa. If the map is modified
+ * while an iteration over the set is in progress (except through
+ * the iterator's own <tt>remove</tt> operation), the results of
+ * the iteration are undefined. The set supports element removal,
+ * which removes the corresponding mapping from the map, via the
+ * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
+ * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
+ * operations. It does not support the <tt>add</tt> or <tt>addAll</tt>
+ * operations.
+ * Its {@link Spliterator} typically provides faster sequential
+ * performance but much poorer parallel performance than that of
+ * {@code HashMap}.
+ *
+ * @return a set view of the keys contained in this map
+ */
+ public Set<K> keySet() {
+ Set<K> ks;
+ return (ks = keySet) == null ? (keySet = new LinkedKeySet()) : ks;
+ }
+
+ final class LinkedKeySet extends AbstractSet<K> {
+ public final int size() { return size; }
+ public final void clear() { LinkedHashMap.this.clear(); }
+ public final Iterator<K> iterator() {
+ return new LinkedKeyIterator();
+ }
+ public final boolean contains(Object o) { return containsKey(o); }
+ public final boolean remove(Object key) {
+ return removeNode(hash(key), key, null, false, true) != null;
+ }
+ public final Spliterator<K> spliterator() {
+ return Spliterators.spliterator(this, Spliterator.SIZED |
+ Spliterator.ORDERED |
+ Spliterator.DISTINCT);
+ }
+ public final void forEach(Consumer<? super K> action) {
+ if (action == null)
+ throw new NullPointerException();
+ int mc = modCount;
+ for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
+ action.accept(e.key);
+ if (modCount != mc)
+ throw new ConcurrentModificationException();
+ }
+ }
+
+ /**
+ * Returns a {@link Collection} view of the values contained in this map.
+ * The collection is backed by the map, so changes to the map are
+ * reflected in the collection, and vice-versa. If the map is
+ * modified while an iteration over the collection is in progress
+ * (except through the iterator's own <tt>remove</tt> operation),
+ * the results of the iteration are undefined. The collection
+ * supports element removal, which removes the corresponding
+ * mapping from the map, via the <tt>Iterator.remove</tt>,
+ * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
+ * <tt>retainAll</tt> and <tt>clear</tt> operations. It does not
+ * support the <tt>add</tt> or <tt>addAll</tt> operations.
+ * Its {@link Spliterator} typically provides faster sequential
+ * performance but much poorer parallel performance than that of
+ * {@code HashMap}.
+ *
+ * @return a view of the values contained in this map
+ */
+ public Collection<V> values() {
+ Collection<V> vs;
+ return (vs = values) == null ? (values = new LinkedValues()) : vs;
+ }
+
+ final class LinkedValues extends AbstractCollection<V> {
+ public final int size() { return size; }
+ public final void clear() { LinkedHashMap.this.clear(); }
+ public final Iterator<V> iterator() {
+ return new LinkedValueIterator();
+ }
+ public final boolean contains(Object o) { return containsValue(o); }
+ public final Spliterator<V> spliterator() {
+ return Spliterators.spliterator(this, Spliterator.SIZED |
+ Spliterator.ORDERED);
+ }
+ public final void forEach(Consumer<? super V> action) {
+ if (action == null)
+ throw new NullPointerException();
+ int mc = modCount;
+ for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
+ action.accept(e.value);
+ if (modCount != mc)
+ throw new ConcurrentModificationException();
+ }
+ }
+
+ /**
+ * Returns a {@link Set} view of the mappings contained in this map.
+ * The set is backed by the map, so changes to the map are
+ * reflected in the set, and vice-versa. If the map is modified
+ * while an iteration over the set is in progress (except through
+ * the iterator's own <tt>remove</tt> operation, or through the
+ * <tt>setValue</tt> operation on a map entry returned by the
+ * iterator) the results of the iteration are undefined. The set
+ * supports element removal, which removes the corresponding
+ * mapping from the map, via the <tt>Iterator.remove</tt>,
+ * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
+ * <tt>clear</tt> operations. It does not support the
+ * <tt>add</tt> or <tt>addAll</tt> operations.
+ * Its {@link Spliterator} typically provides faster sequential
+ * performance but much poorer parallel performance than that of
+ * {@code HashMap}.
+ *
+ * @return a set view of the mappings contained in this map
+ */
+ public Set<Map.Entry<K,V>> entrySet() {
+ Set<Map.Entry<K,V>> es;
+ return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
+ }
+
+ final class LinkedEntrySet extends AbstractSet<Map.Entry<K,V>> {
+ public final int size() { return size; }
+ public final void clear() { LinkedHashMap.this.clear(); }
+ public final Iterator<Map.Entry<K,V>> iterator() {
+ return new LinkedEntryIterator();
+ }
+ public final boolean contains(Object o) {
+ if (!(o instanceof Map.Entry))
+ return false;
+ Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+ Object key = e.getKey();
+ Node<K,V> candidate = getNode(hash(key), key);
+ return candidate != null && candidate.equals(e);
+ }
+ public final boolean remove(Object o) {
+ if (o instanceof Map.Entry) {
+ Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+ Object key = e.getKey();
+ Object value = e.getValue();
+ return removeNode(hash(key), key, value, true, true) != null;
+ }
+ return false;
+ }
+ public final Spliterator<Map.Entry<K,V>> spliterator() {
+ return Spliterators.spliterator(this, Spliterator.SIZED |
+ Spliterator.ORDERED |
+ Spliterator.DISTINCT);
+ }
+ public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
+ if (action == null)
+ throw new NullPointerException();
+ int mc = modCount;
+ for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
+ action.accept(e);
+ if (modCount != mc)
+ throw new ConcurrentModificationException();
+ }
+ }
+
+ // Map overrides
+
+ public void forEach(BiConsumer<? super K, ? super V> action) {
+ if (action == null)
+ throw new NullPointerException();
+ int mc = modCount;
+ for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
+ action.accept(e.key, e.value);
+ if (modCount != mc)
+ throw new ConcurrentModificationException();
+ }
+
+ public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+ if (function == null)
+ throw new NullPointerException();
+ int mc = modCount;
+ for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
+ e.value = function.apply(e.key, e.value);
+ if (modCount != mc)
+ throw new ConcurrentModificationException();
+ }
+
+ // Iterators
+
+ abstract class LinkedHashIterator {
+ LinkedHashMap.Entry<K,V> next;
+ LinkedHashMap.Entry<K,V> current;
+ int expectedModCount;
+
+ LinkedHashIterator() {
+ next = head;
+ expectedModCount = modCount;
+ current = null;
+ }
+
+ public final boolean hasNext() {
+ return next != null;
+ }
+
+ final LinkedHashMap.Entry<K,V> nextNode() {
+ LinkedHashMap.Entry<K,V> e = next;
+ if (modCount != expectedModCount)
+ throw new ConcurrentModificationException();
+ if (e == null)
+ throw new NoSuchElementException();
+ current = e;
+ next = e.after;
+ return e;
+ }
+
+ public final void remove() {
+ Node<K,V> p = current;
+ if (p == null)
+ throw new IllegalStateException();
+ if (modCount != expectedModCount)
+ throw new ConcurrentModificationException();
+ current = null;
+ K key = p.key;
+ removeNode(hash(key), key, null, false, false);
+ expectedModCount = modCount;
+ }
+ }
+
+ final class LinkedKeyIterator extends LinkedHashIterator
+ implements Iterator<K> {
+ public final K next() { return nextNode().getKey(); }
+ }
+
+ final class LinkedValueIterator extends LinkedHashIterator
+ implements Iterator<V> {
+ public final V next() { return nextNode().value; }
+ }
+
+ final class LinkedEntryIterator extends LinkedHashIterator
+ implements Iterator<Map.Entry<K,V>> {
+ public final Map.Entry<K,V> next() { return nextNode(); }
+ }
+
+
}
--- a/jdk/src/share/classes/java/util/Map.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/Map.java Sat Sep 14 20:43:34 2013 +0100
@@ -805,6 +805,10 @@
* return false;
* }</pre>
*
+ * The default implementation does not throw NullPointerException
+ * for maps that do not support null values if oldValue is null unless
+ * newValue is also null.
+ *
* @param key key with which the specified value is associated
* @param oldValue value expected to be associated with the specified key
* @param newValue value to be associated with the specified key
@@ -814,8 +818,11 @@
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws ClassCastException if the class of a specified key or value
* prevents it from being stored in this map
- * @throws NullPointerException if a specified key or value is null,
+ * @throws NullPointerException if a specified key or newValue is null,
* and this map does not permit null keys or values
+ * @throws NullPointerException if oldValue is null and this map does not
+ * permit null values
+ * (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws IllegalArgumentException if some property of a specified key
* or value prevents it from being stored in this map
* @since 1.8
--- a/jdk/src/share/classes/java/util/Properties.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/Properties.java Sat Sep 14 20:43:34 2013 +0100
@@ -304,7 +304,7 @@
* preceded by a backslash still yield single and double quote
* characters, respectively.
*
- * <li> Only a single 'u' character is allowed in a Uniocde escape
+ * <li> Only a single 'u' character is allowed in a Unicode escape
* sequence.
*
* </ul>
--- a/jdk/src/share/classes/java/util/TreeMap.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/TreeMap.java Sat Sep 14 20:43:34 2013 +0100
@@ -1012,7 +1012,7 @@
int expectedModCount = modCount;
for (Entry<K, V> e = getFirstEntry(); e != null; e = successor(e)) {
- e.value = Objects.requireNonNull(function.apply(e.key, e.value));
+ e.value = function.apply(e.key, e.value);
if (expectedModCount != modCount) {
throw new ConcurrentModificationException();
--- a/jdk/src/share/classes/java/util/WeakHashMap.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/WeakHashMap.java Sat Sep 14 20:43:34 2013 +0100
@@ -190,39 +190,6 @@
*/
int modCount;
- private static class Holder {
- static final boolean USE_HASHSEED;
-
- static {
- String hashSeedProp = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction(
- "jdk.map.useRandomSeed"));
- boolean localBool = (null != hashSeedProp)
- ? Boolean.parseBoolean(hashSeedProp) : false;
- USE_HASHSEED = localBool;
- }
- }
-
- /**
- * A randomizing value associated with this instance that is applied to
- * hash code of keys to make hash collisions harder to find.
- *
- * Non-final so it can be set lazily, but be sure not to set more than once.
- */
- transient int hashSeed;
-
- /**
- * Initialize the hashing mask value.
- */
- final void initHashSeed() {
- if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) {
- // Do not set hashSeed more than once!
- // assert hashSeed == 0;
- int seed = ThreadLocalRandom.current().nextInt();
- hashSeed = (seed != 0) ? seed : 1;
- }
- }
-
@SuppressWarnings("unchecked")
private Entry<K,V>[] newTable(int n) {
return (Entry<K,V>[]) new Entry<?,?>[n];
@@ -253,7 +220,6 @@
table = newTable(capacity);
this.loadFactor = loadFactor;
threshold = (int)(capacity * loadFactor);
- initHashSeed();
}
/**
@@ -329,7 +295,7 @@
* in lower bits.
*/
final int hash(Object k) {
- int h = hashSeed ^ k.hashCode();
+ int h = k.hashCode();
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
@@ -783,8 +749,7 @@
public int hashCode() {
K k = getKey();
V v = getValue();
- return ((k==null ? 0 : k.hashCode()) ^
- (v==null ? 0 : v.hashCode()));
+ return Objects.hashCode(k) ^ Objects.hashCode(v);
}
public String toString() {
--- a/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java Sat Sep 14 20:43:34 2013 +0100
@@ -49,6 +49,7 @@
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Set;
import java.util.Spliterator;
import java.util.concurrent.ConcurrentMap;
@@ -373,27 +374,26 @@
* The table is resized when occupancy exceeds a percentage
* threshold (nominally, 0.75, but see below). Any thread
* noticing an overfull bin may assist in resizing after the
- * initiating thread allocates and sets up the replacement
- * array. However, rather than stalling, these other threads may
- * proceed with insertions etc. The use of TreeBins shields us
- * from the worst case effects of overfilling while resizes are in
+ * initiating thread allocates and sets up the replacement array.
+ * However, rather than stalling, these other threads may proceed
+ * with insertions etc. The use of TreeBins shields us from the
+ * worst case effects of overfilling while resizes are in
* progress. Resizing proceeds by transferring bins, one by one,
- * from the table to the next table. To enable concurrency, the
- * next table must be (incrementally) prefilled with place-holders
- * serving as reverse forwarders to the old table. Because we are
- * using power-of-two expansion, the elements from each bin must
- * either stay at same index, or move with a power of two
- * offset. We eliminate unnecessary node creation by catching
- * cases where old nodes can be reused because their next fields
- * won't change. On average, only about one-sixth of them need
- * cloning when a table doubles. The nodes they replace will be
- * garbage collectable as soon as they are no longer referenced by
- * any reader thread that may be in the midst of concurrently
- * traversing table. Upon transfer, the old table bin contains
- * only a special forwarding node (with hash field "MOVED") that
- * contains the next table as its key. On encountering a
- * forwarding node, access and update operations restart, using
- * the new table.
+ * from the table to the next table. However, threads claim small
+ * blocks of indices to transfer (via field transferIndex) before
+ * doing so, reducing contention. Because we are using
+ * power-of-two expansion, the elements from each bin must either
+ * stay at same index, or move with a power of two offset. We
+ * eliminate unnecessary node creation by catching cases where old
+ * nodes can be reused because their next fields won't change. On
+ * average, only about one-sixth of them need cloning when a table
+ * doubles. The nodes they replace will be garbage collectable as
+ * soon as they are no longer referenced by any reader thread that
+ * may be in the midst of concurrently traversing table. Upon
+ * transfer, the old table bin contains only a special forwarding
+ * node (with hash field "MOVED") that contains the next table as
+ * its key. On encountering a forwarding node, access and update
+ * operations restart, using the new table.
*
* Each bin transfer requires its bin lock, which can stall
* waiting for locks while resizing. However, because other
@@ -401,13 +401,19 @@
* locks, average aggregate waits become shorter as resizing
* progresses. The transfer operation must also ensure that all
* accessible bins in both the old and new table are usable by any
- * traversal. This is arranged by proceeding from the last bin
- * (table.length - 1) up towards the first. Upon seeing a
- * forwarding node, traversals (see class Traverser) arrange to
- * move to the new table without revisiting nodes. However, to
- * ensure that no intervening nodes are skipped, bin splitting can
- * only begin after the associated reverse-forwarders are in
- * place.
+ * traversal. This is arranged in part by proceeding from the
+ * last bin (table.length - 1) up towards the first. Upon seeing
+ * a forwarding node, traversals (see class Traverser) arrange to
+ * move to the new table without revisiting nodes. To ensure that
+ * no intervening nodes are skipped even when moved out of order,
+ * a stack (see class TableStack) is created on first encounter of
+ * a forwarding node during a traversal, to maintain its place if
+ * later processing the current table. The need for these
+ * save/restore mechanics is relatively rare, but when one
+ * forwarding node is encountered, typically many more will be.
+ * So Traversers use a simple caching scheme to avoid creating so
+ * many new TableStack nodes. (Thanks to Peter Levart for
+ * suggesting use of a stack here.)
*
* The traversal scheme also applies to partial traversals of
* ranges of bins (via an alternate Traverser constructor)
@@ -776,11 +782,6 @@
private transient volatile int transferIndex;
/**
- * The least available table index to split while resizing.
- */
- private transient volatile int transferOrigin;
-
- /**
* Spinlock (locked via CAS) used when resizing and/or creating CounterCells.
*/
private transient volatile int cellsBusy;
@@ -1376,7 +1377,8 @@
}
int segmentShift = 32 - sshift;
int segmentMask = ssize - 1;
- @SuppressWarnings("unchecked") Segment<K,V>[] segments = (Segment<K,V>[])
+ @SuppressWarnings("unchecked")
+ Segment<K,V>[] segments = (Segment<K,V>[])
new Segment<?,?>[DEFAULT_CONCURRENCY_LEVEL];
for (int i = 0; i < segments.length; ++i)
segments[i] = new Segment<K,V>(LOAD_FACTOR);
@@ -1419,8 +1421,10 @@
long size = 0L;
Node<K,V> p = null;
for (;;) {
- @SuppressWarnings("unchecked") K k = (K) s.readObject();
- @SuppressWarnings("unchecked") V v = (V) s.readObject();
+ @SuppressWarnings("unchecked")
+ K k = (K) s.readObject();
+ @SuppressWarnings("unchecked")
+ V v = (V) s.readObject();
if (k != null && v != null) {
p = new Node<K,V>(spread(k.hashCode()), k, v, p);
++size;
@@ -1438,8 +1442,8 @@
int sz = (int)size;
n = tableSizeFor(sz + (sz >>> 1) + 1);
}
- @SuppressWarnings({"rawtypes","unchecked"})
- Node<K,V>[] tab = (Node<K,V>[])new Node[n];
+ @SuppressWarnings("unchecked")
+ Node<K,V>[] tab = (Node<K,V>[])new Node<?,?>[n];
int mask = n - 1;
long added = 0L;
while (p != null) {
@@ -2199,8 +2203,8 @@
try {
if ((tab = table) == null || tab.length == 0) {
int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
- @SuppressWarnings({"rawtypes","unchecked"})
- Node<K,V>[] nt = (Node<K,V>[])new Node[n];
+ @SuppressWarnings("unchecked")
+ Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
table = tab = nt;
sc = n - (n >>> 2);
}
@@ -2245,7 +2249,7 @@
while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
tab.length < MAXIMUM_CAPACITY) {
if (sc < 0) {
- if (sc == -1 || transferIndex <= transferOrigin ||
+ if (sc == -1 || transferIndex <= 0 ||
(nt = nextTable) == null)
break;
if (U.compareAndSwapInt(this, SIZECTL, sc, sc - 1))
@@ -2265,10 +2269,13 @@
Node<K,V>[] nextTab; int sc;
if ((f instanceof ForwardingNode) &&
(nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {
- if (nextTab == nextTable && tab == table &&
- transferIndex > transferOrigin && (sc = sizeCtl) < -1 &&
- U.compareAndSwapInt(this, SIZECTL, sc, sc - 1))
- transfer(tab, nextTab);
+ while (transferIndex > 0 && nextTab == nextTable &&
+ (sc = sizeCtl) < -1) {
+ if (U.compareAndSwapInt(this, SIZECTL, sc, sc - 1)) {
+ transfer(tab, nextTab);
+ break;
+ }
+ }
return nextTab;
}
return table;
@@ -2290,8 +2297,8 @@
if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
try {
if (table == tab) {
- @SuppressWarnings({"rawtypes","unchecked"})
- Node<K,V>[] nt = (Node<K,V>[])new Node[n];
+ @SuppressWarnings("unchecked")
+ Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
table = nt;
sc = n - (n >>> 2);
}
@@ -2318,36 +2325,27 @@
stride = MIN_TRANSFER_STRIDE; // subdivide range
if (nextTab == null) { // initiating
try {
- @SuppressWarnings({"rawtypes","unchecked"})
- Node<K,V>[] nt = (Node<K,V>[])new Node[n << 1];
+ @SuppressWarnings("unchecked")
+ Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];
nextTab = nt;
} catch (Throwable ex) { // try to cope with OOME
sizeCtl = Integer.MAX_VALUE;
return;
}
nextTable = nextTab;
- transferOrigin = n;
transferIndex = n;
- ForwardingNode<K,V> rev = new ForwardingNode<K,V>(tab);
- for (int k = n; k > 0;) { // progressively reveal ready slots
- int nextk = (k > stride) ? k - stride : 0;
- for (int m = nextk; m < k; ++m)
- nextTab[m] = rev;
- for (int m = n + nextk; m < n + k; ++m)
- nextTab[m] = rev;
- U.putOrderedInt(this, TRANSFERORIGIN, k = nextk);
- }
}
int nextn = nextTab.length;
ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);
boolean advance = true;
boolean finishing = false; // to ensure sweep before committing nextTab
for (int i = 0, bound = 0;;) {
- int nextIndex, nextBound, fh; Node<K,V> f;
+ Node<K,V> f; int fh;
while (advance) {
+ int nextIndex, nextBound;
if (--i >= bound || finishing)
advance = false;
- else if ((nextIndex = transferIndex) <= transferOrigin) {
+ else if ((nextIndex = transferIndex) <= 0) {
i = -1;
advance = false;
}
@@ -2361,29 +2359,22 @@
}
}
if (i < 0 || i >= n || i + n >= nextn) {
+ int sc;
if (finishing) {
nextTable = null;
table = nextTab;
sizeCtl = (n << 1) - (n >>> 1);
return;
}
- for (int sc;;) {
- if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, ++sc)) {
- if (sc != -1)
- return;
- finishing = advance = true;
- i = n; // recheck before commit
- break;
- }
+ if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, ++sc)) {
+ if (sc != -1)
+ return;
+ finishing = advance = true;
+ i = n; // recheck before commit
}
}
- else if ((f = tabAt(tab, i)) == null) {
- if (casTabAt(tab, i, null, fwd)) {
- setTabAt(nextTab, i, null);
- setTabAt(nextTab, i + n, null);
- advance = true;
- }
- }
+ else if ((f = tabAt(tab, i)) == null)
+ advance = casTabAt(tab, i, null, fwd);
else if ((fh = f.hash) == MOVED)
advance = true; // already processed
else {
@@ -3223,6 +3214,18 @@
/* ----------------Table Traversal -------------- */
/**
+ * Records the table, its length, and current traversal index for a
+ * traverser that must process a region of a forwarded table before
+ * proceeding with current table.
+ */
+ static final class TableStack<K,V> {
+ int length;
+ int index;
+ Node<K,V>[] tab;
+ TableStack<K,V> next;
+ }
+
+ /**
* Encapsulates traversal for methods such as containsValue; also
* serves as a base class for other iterators and spliterators.
*
@@ -3246,6 +3249,7 @@
static class Traverser<K,V> {
Node<K,V>[] tab; // current table; updated if resized
Node<K,V> next; // the next entry to use
+ TableStack<K,V> stack, spare; // to save/restore on ForwardingNodes
int index; // index of bin to use next
int baseIndex; // current index of initial table
int baseLimit; // index bound for initial table
@@ -3267,16 +3271,17 @@
if ((e = next) != null)
e = e.next;
for (;;) {
- Node<K,V>[] t; int i, n; K ek; // must use locals in checks
+ Node<K,V>[] t; int i, n; // must use locals in checks
if (e != null)
return next = e;
if (baseIndex >= baseLimit || (t = tab) == null ||
(n = t.length) <= (i = index) || i < 0)
return next = null;
- if ((e = tabAt(t, index)) != null && e.hash < 0) {
+ if ((e = tabAt(t, i)) != null && e.hash < 0) {
if (e instanceof ForwardingNode) {
tab = ((ForwardingNode<K,V>)e).nextTable;
e = null;
+ pushState(t, i, n);
continue;
}
else if (e instanceof TreeBin)
@@ -3284,10 +3289,49 @@
else
e = null;
}
- if ((index += baseSize) >= n)
- index = ++baseIndex; // visit upper slots if present
+ if (stack != null)
+ recoverState(n);
+ else if ((index = i + baseSize) >= n)
+ index = ++baseIndex; // visit upper slots if present
}
}
+
+ /**
+ * Saves traversal state upon encountering a forwarding node.
+ */
+ private void pushState(Node<K,V>[] t, int i, int n) {
+ TableStack<K,V> s = spare; // reuse if possible
+ if (s != null)
+ spare = s.next;
+ else
+ s = new TableStack<K,V>();
+ s.tab = t;
+ s.length = n;
+ s.index = i;
+ s.next = stack;
+ stack = s;
+ }
+
+ /**
+ * Possibly pops traversal state.
+ *
+ * @param n length of current table
+ */
+ private void recoverState(int n) {
+ TableStack<K,V> s; int len;
+ while ((s = stack) != null && (index += (len = s.length)) >= n) {
+ n = len;
+ index = s.index;
+ tab = s.tab;
+ s.tab = null;
+ TableStack<K,V> next = s.next;
+ s.next = spare; // save for reuse
+ stack = next;
+ spare = s;
+ }
+ if (s == null && (index += baseSize) >= n)
+ index = ++baseIndex;
+ }
}
/**
@@ -4410,6 +4454,7 @@
}
public final boolean removeAll(Collection<?> c) {
+ Objects.requireNonNull(c);
boolean modified = false;
for (Iterator<E> it = iterator(); it.hasNext();) {
if (c.contains(it.next())) {
@@ -4421,6 +4466,7 @@
}
public final boolean retainAll(Collection<?> c) {
+ Objects.requireNonNull(c);
boolean modified = false;
for (Iterator<E> it = iterator(); it.hasNext();) {
if (!c.contains(it.next())) {
@@ -4719,6 +4765,7 @@
abstract static class BulkTask<K,V,R> extends CountedCompleter<R> {
Node<K,V>[] tab; // same as Traverser
Node<K,V> next;
+ TableStack<K,V> stack, spare;
int index;
int baseIndex;
int baseLimit;
@@ -4747,16 +4794,17 @@
if ((e = next) != null)
e = e.next;
for (;;) {
- Node<K,V>[] t; int i, n; K ek; // must use locals in checks
+ Node<K,V>[] t; int i, n;
if (e != null)
return next = e;
if (baseIndex >= baseLimit || (t = tab) == null ||
(n = t.length) <= (i = index) || i < 0)
return next = null;
- if ((e = tabAt(t, index)) != null && e.hash < 0) {
+ if ((e = tabAt(t, i)) != null && e.hash < 0) {
if (e instanceof ForwardingNode) {
tab = ((ForwardingNode<K,V>)e).nextTable;
e = null;
+ pushState(t, i, n);
continue;
}
else if (e instanceof TreeBin)
@@ -4764,10 +4812,41 @@
else
e = null;
}
- if ((index += baseSize) >= n)
- index = ++baseIndex; // visit upper slots if present
+ if (stack != null)
+ recoverState(n);
+ else if ((index = i + baseSize) >= n)
+ index = ++baseIndex;
}
}
+
+ private void pushState(Node<K,V>[] t, int i, int n) {
+ TableStack<K,V> s = spare;
+ if (s != null)
+ spare = s.next;
+ else
+ s = new TableStack<K,V>();
+ s.tab = t;
+ s.length = n;
+ s.index = i;
+ s.next = stack;
+ stack = s;
+ }
+
+ private void recoverState(int n) {
+ TableStack<K,V> s; int len;
+ while ((s = stack) != null && (index += (len = s.length)) >= n) {
+ n = len;
+ index = s.index;
+ tab = s.tab;
+ s.tab = null;
+ TableStack<K,V> next = s.next;
+ s.next = spare; // save for reuse
+ stack = next;
+ spare = s;
+ }
+ if (s == null && (index += baseSize) >= n)
+ index = ++baseIndex;
+ }
}
/*
@@ -5226,7 +5305,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") ReduceKeysTask<K,V>
+ @SuppressWarnings("unchecked")
+ ReduceKeysTask<K,V>
t = (ReduceKeysTask<K,V>)c,
s = t.rights;
while (s != null) {
@@ -5273,7 +5353,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") ReduceValuesTask<K,V>
+ @SuppressWarnings("unchecked")
+ ReduceValuesTask<K,V>
t = (ReduceValuesTask<K,V>)c,
s = t.rights;
while (s != null) {
@@ -5318,7 +5399,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") ReduceEntriesTask<K,V>
+ @SuppressWarnings("unchecked")
+ ReduceEntriesTask<K,V>
t = (ReduceEntriesTask<K,V>)c,
s = t.rights;
while (s != null) {
@@ -5371,7 +5453,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") MapReduceKeysTask<K,V,U>
+ @SuppressWarnings("unchecked")
+ MapReduceKeysTask<K,V,U>
t = (MapReduceKeysTask<K,V,U>)c,
s = t.rights;
while (s != null) {
@@ -5424,7 +5507,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") MapReduceValuesTask<K,V,U>
+ @SuppressWarnings("unchecked")
+ MapReduceValuesTask<K,V,U>
t = (MapReduceValuesTask<K,V,U>)c,
s = t.rights;
while (s != null) {
@@ -5477,7 +5561,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") MapReduceEntriesTask<K,V,U>
+ @SuppressWarnings("unchecked")
+ MapReduceEntriesTask<K,V,U>
t = (MapReduceEntriesTask<K,V,U>)c,
s = t.rights;
while (s != null) {
@@ -5530,7 +5615,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") MapReduceMappingsTask<K,V,U>
+ @SuppressWarnings("unchecked")
+ MapReduceMappingsTask<K,V,U>
t = (MapReduceMappingsTask<K,V,U>)c,
s = t.rights;
while (s != null) {
@@ -5582,7 +5668,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") MapReduceKeysToDoubleTask<K,V>
+ @SuppressWarnings("unchecked")
+ MapReduceKeysToDoubleTask<K,V>
t = (MapReduceKeysToDoubleTask<K,V>)c,
s = t.rights;
while (s != null) {
@@ -5631,7 +5718,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") MapReduceValuesToDoubleTask<K,V>
+ @SuppressWarnings("unchecked")
+ MapReduceValuesToDoubleTask<K,V>
t = (MapReduceValuesToDoubleTask<K,V>)c,
s = t.rights;
while (s != null) {
@@ -5680,7 +5768,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") MapReduceEntriesToDoubleTask<K,V>
+ @SuppressWarnings("unchecked")
+ MapReduceEntriesToDoubleTask<K,V>
t = (MapReduceEntriesToDoubleTask<K,V>)c,
s = t.rights;
while (s != null) {
@@ -5729,7 +5818,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") MapReduceMappingsToDoubleTask<K,V>
+ @SuppressWarnings("unchecked")
+ MapReduceMappingsToDoubleTask<K,V>
t = (MapReduceMappingsToDoubleTask<K,V>)c,
s = t.rights;
while (s != null) {
@@ -5778,7 +5868,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") MapReduceKeysToLongTask<K,V>
+ @SuppressWarnings("unchecked")
+ MapReduceKeysToLongTask<K,V>
t = (MapReduceKeysToLongTask<K,V>)c,
s = t.rights;
while (s != null) {
@@ -5827,7 +5918,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") MapReduceValuesToLongTask<K,V>
+ @SuppressWarnings("unchecked")
+ MapReduceValuesToLongTask<K,V>
t = (MapReduceValuesToLongTask<K,V>)c,
s = t.rights;
while (s != null) {
@@ -5876,7 +5968,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") MapReduceEntriesToLongTask<K,V>
+ @SuppressWarnings("unchecked")
+ MapReduceEntriesToLongTask<K,V>
t = (MapReduceEntriesToLongTask<K,V>)c,
s = t.rights;
while (s != null) {
@@ -5925,7 +6018,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") MapReduceMappingsToLongTask<K,V>
+ @SuppressWarnings("unchecked")
+ MapReduceMappingsToLongTask<K,V>
t = (MapReduceMappingsToLongTask<K,V>)c,
s = t.rights;
while (s != null) {
@@ -5974,7 +6068,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") MapReduceKeysToIntTask<K,V>
+ @SuppressWarnings("unchecked")
+ MapReduceKeysToIntTask<K,V>
t = (MapReduceKeysToIntTask<K,V>)c,
s = t.rights;
while (s != null) {
@@ -6023,7 +6118,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") MapReduceValuesToIntTask<K,V>
+ @SuppressWarnings("unchecked")
+ MapReduceValuesToIntTask<K,V>
t = (MapReduceValuesToIntTask<K,V>)c,
s = t.rights;
while (s != null) {
@@ -6072,7 +6168,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") MapReduceEntriesToIntTask<K,V>
+ @SuppressWarnings("unchecked")
+ MapReduceEntriesToIntTask<K,V>
t = (MapReduceEntriesToIntTask<K,V>)c,
s = t.rights;
while (s != null) {
@@ -6121,7 +6218,8 @@
result = r;
CountedCompleter<?> c;
for (c = firstComplete(); c != null; c = c.nextComplete()) {
- @SuppressWarnings("unchecked") MapReduceMappingsToIntTask<K,V>
+ @SuppressWarnings("unchecked")
+ MapReduceMappingsToIntTask<K,V>
t = (MapReduceMappingsToIntTask<K,V>)c,
s = t.rights;
while (s != null) {
@@ -6137,7 +6235,6 @@
private static final sun.misc.Unsafe U;
private static final long SIZECTL;
private static final long TRANSFERINDEX;
- private static final long TRANSFERORIGIN;
private static final long BASECOUNT;
private static final long CELLSBUSY;
private static final long CELLVALUE;
@@ -6152,8 +6249,6 @@
(k.getDeclaredField("sizeCtl"));
TRANSFERINDEX = U.objectFieldOffset
(k.getDeclaredField("transferIndex"));
- TRANSFERORIGIN = U.objectFieldOffset
- (k.getDeclaredField("transferOrigin"));
BASECOUNT = U.objectFieldOffset
(k.getDeclaredField("baseCount"));
CELLSBUSY = U.objectFieldOffset
--- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java Sat Sep 14 20:43:34 2013 +0100
@@ -303,7 +303,7 @@
* @return the previous value
* @since 1.8
*/
- public final long getAndAccumulate(int i, int x,
+ public final long getAndAccumulate(int i, long x,
LongBinaryOperator accumulatorFunction) {
long offset = checkedByteOffset(i);
long prev, next;
@@ -329,7 +329,7 @@
* @return the updated value
* @since 1.8
*/
- public final long accumulateAndGet(int i, int x,
+ public final long accumulateAndGet(int i, long x,
LongBinaryOperator accumulatorFunction) {
long offset = checkedByteOffset(i);
long prev, next;
--- a/jdk/src/share/classes/java/util/function/package-info.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/function/package-info.java Sat Sep 14 20:43:34 2013 +0100
@@ -105,5 +105,6 @@
* </ul>
*
* @see java.lang.FunctionalInterface
+ * @since 1.8
*/
package java.util.function;
--- a/jdk/src/share/classes/java/util/logging/ConsoleHandler.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/logging/ConsoleHandler.java Sat Sep 14 20:43:34 2013 +0100
@@ -26,9 +26,6 @@
package java.util.logging;
-import java.io.*;
-import java.net.*;
-
/**
* This <tt>Handler</tt> publishes log records to <tt>System.err</tt>.
* By default the <tt>SimpleFormatter</tt> is used to generate brief summaries.
@@ -114,6 +111,7 @@
* @param record description of the log event. A null record is
* silently ignored and is not published
*/
+ @Override
public void publish(LogRecord record) {
super.publish(record);
flush();
@@ -124,6 +122,7 @@
* to close the output stream. That is, we do <b>not</b>
* close <tt>System.err</tt>.
*/
+ @Override
public void close() {
flush();
}
--- a/jdk/src/share/classes/java/util/logging/FileHandler.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/logging/FileHandler.java Sat Sep 14 20:43:34 2013 +0100
@@ -149,7 +149,7 @@
private FileChannel lockFileChannel;
private File files[];
private static final int MAX_LOCKS = 100;
- private static java.util.HashMap<String, String> locks = new java.util.HashMap<>();
+ private static final java.util.HashMap<String, String> locks = new java.util.HashMap<>();
/**
* A metered stream is a subclass of OutputStream that
@@ -157,7 +157,7 @@
* (b) keeps track of how many bytes have been written
*/
private class MeteredStream extends OutputStream {
- OutputStream out;
+ final OutputStream out;
int written;
MeteredStream(OutputStream out, int written) {
@@ -165,25 +165,30 @@
this.written = written;
}
+ @Override
public void write(int b) throws IOException {
out.write(b);
written++;
}
+ @Override
public void write(byte buff[]) throws IOException {
out.write(buff);
written += buff.length;
}
+ @Override
public void write(byte buff[], int off, int len) throws IOException {
out.write(buff,off,len);
written += len;
}
+ @Override
public void flush() throws IOException {
out.flush();
}
+ @Override
public void close() throws IOException {
out.close();
}
@@ -607,6 +612,7 @@
* @param record description of the log event. A null record is
* silently ignored and is not published
*/
+ @Override
public synchronized void publish(LogRecord record) {
if (!isLoggable(record)) {
return;
@@ -620,6 +626,7 @@
// currently being called from untrusted code.
// So it is safe to raise privilege here.
AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
public Object run() {
rotate();
return null;
@@ -634,6 +641,7 @@
* @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>.
*/
+ @Override
public synchronized void close() throws SecurityException {
super.close();
// Unlock any lock file.
@@ -656,6 +664,7 @@
private static class InitializationErrorManager extends ErrorManager {
Exception lastException;
+ @Override
public void error(String msg, Exception ex, int code) {
lastException = ex;
}
--- a/jdk/src/share/classes/java/util/logging/Handler.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/logging/Handler.java Sat Sep 14 20:43:34 2013 +0100
@@ -47,12 +47,20 @@
public abstract class Handler {
private static final int offValue = Level.OFF.intValue();
- private LogManager manager = LogManager.getLogManager();
- private Filter filter;
- private Formatter formatter;
- private Level logLevel = Level.ALL;
- private ErrorManager errorManager = new ErrorManager();
- private String encoding;
+ private final LogManager manager = LogManager.getLogManager();
+
+ // We're using volatile here to avoid synchronizing getters, which
+ // would prevent other threads from calling isLoggable()
+ // while publish() is executing.
+ // On the other hand, setters will be synchronized to exclude concurrent
+ // execution with more complex methods, such as StreamHandler.publish().
+ // We wouldn't want 'level' to be changed by another thread in the middle
+ // of the execution of a 'publish' call.
+ private volatile Filter filter;
+ private volatile Formatter formatter;
+ private volatile Level logLevel = Level.ALL;
+ private volatile ErrorManager errorManager = new ErrorManager();
+ private volatile String encoding;
// Package private support for security checking. When sealed
// is true, we access check updates to the class.
@@ -110,7 +118,7 @@
* @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>.
*/
- public void setFormatter(Formatter newFormatter) throws SecurityException {
+ public synchronized void setFormatter(Formatter newFormatter) throws SecurityException {
checkPermission();
// Check for a null pointer:
newFormatter.getClass();
@@ -138,7 +146,7 @@
* @exception UnsupportedEncodingException if the named encoding is
* not supported.
*/
- public void setEncoding(String encoding)
+ public synchronized void setEncoding(String encoding)
throws SecurityException, java.io.UnsupportedEncodingException {
checkPermission();
if (encoding != null) {
@@ -174,7 +182,7 @@
* @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>.
*/
- public void setFilter(Filter newFilter) throws SecurityException {
+ public synchronized void setFilter(Filter newFilter) throws SecurityException {
checkPermission();
filter = newFilter;
}
@@ -198,7 +206,7 @@
* @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>.
*/
- public void setErrorManager(ErrorManager em) {
+ public synchronized void setErrorManager(ErrorManager em) {
checkPermission();
if (em == null) {
throw new NullPointerException();
@@ -264,7 +272,7 @@
* than this level will be discarded.
* @return the level of messages being logged.
*/
- public synchronized Level getLevel() {
+ public Level getLevel() {
return logLevel;
}
@@ -282,11 +290,11 @@
*
*/
public boolean isLoggable(LogRecord record) {
- int levelValue = getLevel().intValue();
+ final int levelValue = getLevel().intValue();
if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
return false;
}
- Filter filter = getFilter();
+ final Filter filter = getFilter();
if (filter == null) {
return true;
}
--- a/jdk/src/share/classes/java/util/logging/Level.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/logging/Level.java Sat Sep 14 20:43:34 2013 +0100
@@ -27,6 +27,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
@@ -63,7 +64,7 @@
*/
public class Level implements java.io.Serializable {
- private static String defaultBundle = "sun.util.logging.resources.logging";
+ private static final String defaultBundle = "sun.util.logging.resources.logging";
/**
* @serial The non-localized name of the level.
@@ -81,7 +82,8 @@
private final String resourceBundleName;
// localized level name
- private String localizedLevelName;
+ private transient String localizedLevelName;
+ private transient Locale cachedLocale;
/**
* OFF is a special level that can be used to turn off logging.
@@ -209,6 +211,7 @@
this.value = value;
this.resourceBundleName = resourceBundleName;
this.localizedLevelName = resourceBundleName == null ? name : null;
+ this.cachedLocale = null;
KnownLevel.add(this);
}
@@ -250,17 +253,71 @@
return this.name;
}
- final synchronized String getLocalizedLevelName() {
+ private String computeLocalizedLevelName(Locale newLocale) {
+ ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName, newLocale);
+ final String localizedName = rb.getString(name);
+
+ final boolean isDefaultBundle = defaultBundle.equals(resourceBundleName);
+ if (!isDefaultBundle) return localizedName;
+
+ // This is a trick to determine whether the name has been translated
+ // or not. If it has not been translated, we need to use Locale.ROOT
+ // when calling toUpperCase().
+ final Locale rbLocale = rb.getLocale();
+ final Locale locale =
+ Locale.ROOT.equals(rbLocale)
+ || name.equals(localizedName.toUpperCase(Locale.ROOT))
+ ? Locale.ROOT : rbLocale;
+
+ // ALL CAPS in a resource bundle's message indicates no translation
+ // needed per Oracle translation guideline. To workaround this
+ // in Oracle JDK implementation, convert the localized level name
+ // to uppercase for compatibility reason.
+ return Locale.ROOT.equals(locale) ? name : localizedName.toUpperCase(locale);
+ }
+
+ // Avoid looking up the localizedLevelName twice if we already
+ // have it.
+ final String getCachedLocalizedLevelName() {
+
if (localizedLevelName != null) {
- return localizedLevelName;
+ if (cachedLocale != null) {
+ if (cachedLocale.equals(Locale.getDefault())) {
+ // OK: our cached value was looked up with the same
+ // locale. We can use it.
+ return localizedLevelName;
+ }
+ }
}
+ if (resourceBundleName == null) {
+ // No resource bundle: just use the name.
+ return name;
+ }
+
+ // We need to compute the localized name.
+ // Either because it's the first time, or because our cached
+ // value is for a different locale. Just return null.
+ return null;
+ }
+
+ final synchronized String getLocalizedLevelName() {
+
+ // See if we have a cached localized name
+ final String cachedLocalizedName = getCachedLocalizedLevelName();
+ if (cachedLocalizedName != null) {
+ return cachedLocalizedName;
+ }
+
+ // No cached localized name or cache invalid.
+ // Need to compute the localized name.
+ final Locale newLocale = Locale.getDefault();
try {
- ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName);
- localizedLevelName = rb.getString(name);
+ localizedLevelName = computeLocalizedLevelName(newLocale);
} catch (Exception ex) {
localizedLevelName = name;
}
+ cachedLocale = newLocale;
return localizedLevelName;
}
@@ -318,6 +375,7 @@
*
* @return the non-localized name of the Level, for example "INFO".
*/
+ @Override
public final String toString() {
return name;
}
@@ -420,6 +478,7 @@
* Compare two objects for value equality.
* @return true if and only if the two objects have the same level value.
*/
+ @Override
public boolean equals(Object ox) {
try {
Level lx = (Level)ox;
@@ -433,6 +492,7 @@
* Generate a hashcode.
* @return a hashcode based on the level value
*/
+ @Override
public int hashCode() {
return this.value;
}
--- a/jdk/src/share/classes/java/util/logging/LogManager.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/logging/LogManager.java Sat Sep 14 20:43:34 2013 +0100
@@ -144,7 +144,7 @@
public class LogManager {
// The global LogManager object
- private static LogManager manager;
+ private static final LogManager manager;
private Properties props = new Properties();
private final static Level defaultLevel = Level.INFO;
@@ -156,8 +156,10 @@
// LoggerContext for system loggers and user loggers
private final LoggerContext systemContext = new SystemLoggerContext();
private final LoggerContext userContext = new LoggerContext();
- private Logger rootLogger;
-
+ // non final field - make it volatile to make sure that other threads
+ // will see the new value once ensureLogManagerInitialized() has finished
+ // executing.
+ private volatile Logger rootLogger;
// Have we done the primordial reading of the configuration file?
// (Must be done after a suitable amount of java.lang.System
// initialization has been done)
@@ -169,58 +171,35 @@
private boolean deathImminent;
static {
- AccessController.doPrivileged(new PrivilegedAction<Object>() {
- public Object run() {
- String cname = null;
- try {
- cname = System.getProperty("java.util.logging.manager");
- if (cname != null) {
- try {
- Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(cname);
- manager = (LogManager) clz.newInstance();
- } catch (ClassNotFoundException ex) {
- Class<?> clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
- manager = (LogManager) clz.newInstance();
- }
+ manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() {
+ @Override
+ public LogManager run() {
+ LogManager mgr = null;
+ String cname = null;
+ try {
+ cname = System.getProperty("java.util.logging.manager");
+ if (cname != null) {
+ try {
+ Class<?> clz = ClassLoader.getSystemClassLoader()
+ .loadClass(cname);
+ mgr = (LogManager) clz.newInstance();
+ } catch (ClassNotFoundException ex) {
+ Class<?> clz = Thread.currentThread()
+ .getContextClassLoader().loadClass(cname);
+ mgr = (LogManager) clz.newInstance();
}
- } catch (Exception ex) {
- System.err.println("Could not load Logmanager \"" + cname + "\"");
- ex.printStackTrace();
}
- if (manager == null) {
- manager = new LogManager();
- }
+ } catch (Exception ex) {
+ System.err.println("Could not load Logmanager \"" + cname + "\"");
+ ex.printStackTrace();
+ }
+ if (mgr == null) {
+ mgr = new LogManager();
+ }
+ return mgr;
- // Create and retain Logger for the root of the namespace.
- manager.rootLogger = manager.new RootLogger();
- // since by design the global manager's userContext and
- // systemContext don't have their requiresDefaultLoggers
- // flag set - we make sure to add the root logger to
- // the global manager's default contexts here.
- manager.addLogger(manager.rootLogger);
- manager.systemContext.addLocalLogger(manager.rootLogger, false);
- manager.userContext.addLocalLogger(manager.rootLogger, false);
-
- // Adding the global Logger. Doing so in the Logger.<clinit>
- // would deadlock with the LogManager.<clinit>.
- // Do not call Logger.getGlobal() here as this might trigger
- // the deadlock too.
- @SuppressWarnings("deprecation")
- final Logger global = Logger.global;
- global.setLogManager(manager);
-
- // Make sure the global logger will be registered in the
- // global manager's default contexts.
- manager.addLogger(global);
- manager.systemContext.addLocalLogger(global, false);
- manager.userContext.addLocalLogger(global, false);
-
- // We don't call readConfiguration() here, as we may be running
- // very early in the JVM startup sequence. Instead readConfiguration
- // will be called lazily in getLogManager().
- return null;
- }
- });
+ }
+ });
}
@@ -235,6 +214,7 @@
this.setContextClassLoader(null);
}
+ @Override
public void run() {
// This is to ensure the LogManager.<clinit> is completed
// before synchronized block. Otherwise deadlocks are possible.
@@ -271,12 +251,103 @@
}
/**
+ * Lazy initialization: if this instance of manager is the global
+ * manager then this method will read the initial configuration and
+ * add the root logger and global logger by calling addLogger().
+ *
+ * Note that it is subtly different from what we do in LoggerContext.
+ * In LoggerContext we're patching up the logger context tree in order to add
+ * the root and global logger *to the context tree*.
+ *
+ * For this to work, addLogger() must have already have been called
+ * once on the LogManager instance for the default logger being
+ * added.
+ *
+ * This is why ensureLogManagerInitialized() needs to be called before
+ * any logger is added to any logger context.
+ *
+ */
+ private boolean initializedCalled = false;
+ private volatile boolean initializationDone = false;
+ final void ensureLogManagerInitialized() {
+ final LogManager owner = this;
+ if (initializationDone || owner != manager) {
+ // we don't want to do this twice, and we don't want to do
+ // this on private manager instances.
+ return;
+ }
+
+ // Maybe another thread has called ensureLogManagerInitialized()
+ // before us and is still executing it. If so we will block until
+ // the log manager has finished initialized, then acquire the monitor,
+ // notice that initializationDone is now true and return.
+ // Otherwise - we have come here first! We will acquire the monitor,
+ // see that initializationDone is still false, and perform the
+ // initialization.
+ //
+ synchronized(this) {
+ // If initializedCalled is true it means that we're already in
+ // the process of initializing the LogManager in this thread.
+ // There has been a recursive call to ensureLogManagerInitialized().
+ final boolean isRecursiveInitialization = (initializedCalled == true);
+
+ assert initializedCalled || !initializationDone
+ : "Initialization can't be done if initialized has not been called!";
+
+ if (isRecursiveInitialization || initializationDone) {
+ // If isRecursiveInitialization is true it means that we're
+ // already in the process of initializing the LogManager in
+ // this thread. There has been a recursive call to
+ // ensureLogManagerInitialized(). We should not proceed as
+ // it would lead to infinite recursion.
+ //
+ // If initializationDone is true then it means the manager
+ // has finished initializing; just return: we're done.
+ return;
+ }
+ // Calling addLogger below will in turn call requiresDefaultLogger()
+ // which will call ensureLogManagerInitialized().
+ // We use initializedCalled to break the recursion.
+ initializedCalled = true;
+ try {
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
+ public Object run() {
+ assert rootLogger == null;
+ assert initializedCalled && !initializationDone;
+
+ // Read configuration.
+ owner.readPrimordialConfiguration();
+
+ // Create and retain Logger for the root of the namespace.
+ owner.rootLogger = owner.new RootLogger();
+ owner.addLogger(owner.rootLogger);
+
+ // Adding the global Logger.
+ // Do not call Logger.getGlobal() here as this might trigger
+ // subtle inter-dependency issues.
+ @SuppressWarnings("deprecation")
+ final Logger global = Logger.global;
+
+ // Make sure the global logger will be registered in the
+ // global manager
+ owner.addLogger(global);
+ return null;
+ }
+ });
+ } finally {
+ initializationDone = true;
+ }
+ }
+ }
+
+ /**
* Returns the global LogManager object.
* @return the global LogManager object
*/
public static LogManager getLogManager() {
if (manager != null) {
- manager.readPrimordialConfiguration();
+ manager.ensureLogManagerInitialized();
}
return manager;
}
@@ -295,6 +366,7 @@
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+ @Override
public Void run() throws Exception {
readConfiguration();
@@ -304,8 +376,7 @@
}
});
} catch (Exception ex) {
- // System.err.println("Can't read logging configuration:");
- // ex.printStackTrace();
+ assert false : "Exception raised while reading logging configuration: " + ex;
}
}
}
@@ -391,6 +462,9 @@
}
}
+ // LoggerContext maps from AppContext
+ private WeakHashMap<Object, LoggerContext> contextsMap = null;
+
// Returns the LoggerContext for the user code (i.e. application or AppContext).
// Loggers are isolated from each AppContext.
private LoggerContext getUserContext() {
@@ -399,39 +473,36 @@
SecurityManager sm = System.getSecurityManager();
JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess();
if (sm != null && javaAwtAccess != null) {
+ // for each applet, it has its own LoggerContext isolated from others
synchronized (javaAwtAccess) {
- // AppContext.getAppContext() returns the system AppContext if called
- // from a system thread but Logger.getLogger might be called from
- // an applet code. Instead, find the AppContext of the applet code
- // from the execution stack.
- Object ecx = javaAwtAccess.getExecutionContext();
- if (ecx == null) {
- // fall back to thread group seach of AppContext
- ecx = javaAwtAccess.getContext();
- }
+ // find the AppContext of the applet code
+ // will be null if we are in the main app context.
+ final Object ecx = javaAwtAccess.getAppletContext();
if (ecx != null) {
- context = (LoggerContext)javaAwtAccess.get(ecx, LoggerContext.class);
+ if (contextsMap == null) {
+ contextsMap = new WeakHashMap<>();
+ }
+ context = contextsMap.get(ecx);
if (context == null) {
- if (javaAwtAccess.isMainAppContext()) {
- context = userContext;
- } else {
- // Create a new LoggerContext for the applet.
- // The new logger context has its requiresDefaultLoggers
- // flag set to true - so that these loggers will be
- // lazily added when the context is firt accessed.
- context = new LoggerContext(true);
- }
- javaAwtAccess.put(ecx, LoggerContext.class, context);
+ // Create a new LoggerContext for the applet.
+ context = new LoggerContext();
+ contextsMap.put(ecx, context);
}
}
}
}
+ // for standalone app, return userContext
return context != null ? context : userContext;
}
+ // The system context.
+ final LoggerContext getSystemContext() {
+ return systemContext;
+ }
+
private List<LoggerContext> contexts() {
List<LoggerContext> cxs = new ArrayList<>();
- cxs.add(systemContext);
+ cxs.add(getSystemContext());
cxs.add(getUserContext());
return cxs;
}
@@ -452,7 +523,7 @@
Logger result = getLogger(name);
if (result == null) {
// only allocate the new logger once
- Logger newLogger = new Logger(name, resourceBundleName, caller);
+ Logger newLogger = new Logger(name, resourceBundleName, caller, this);
do {
if (addLogger(newLogger)) {
// We successfully added the new Logger that we
@@ -479,7 +550,7 @@
Logger demandSystemLogger(String name, String resourceBundleName) {
// Add a system logger in the system context's namespace
- final Logger sysLogger = systemContext.demandLogger(name, resourceBundleName);
+ final Logger sysLogger = getSystemContext().demandLogger(name, resourceBundleName);
// Add the system logger to the LogManager's namespace if not exist
// so that there is only one single logger of the given name.
@@ -503,6 +574,7 @@
// if logger already exists but handlers not set
final Logger l = logger;
AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ @Override
public Void run() {
for (Handler hdl : l.getHandlers()) {
sysLogger.addHandler(hdl);
@@ -521,24 +593,52 @@
// doesn't exist in the user context, it'll also be added to the user context.
// The user context is queried by the user code and all other loggers are
// added in the user context.
- static class LoggerContext {
+ class LoggerContext {
// Table of named Loggers that maps names to Loggers.
private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
// Tree of named Loggers
private final LogNode root;
- private final boolean requiresDefaultLoggers;
private LoggerContext() {
- this(false);
+ this.root = new LogNode(null, this);
+ }
+
+
+ // Tells whether default loggers are required in this context.
+ // If true, the default loggers will be lazily added.
+ final boolean requiresDefaultLoggers() {
+ final boolean requiresDefaultLoggers = (getOwner() == manager);
+ if (requiresDefaultLoggers) {
+ getOwner().ensureLogManagerInitialized();
+ }
+ return requiresDefaultLoggers;
}
- private LoggerContext(boolean requiresDefaultLoggers) {
- this.root = new LogNode(null, this);
- this.requiresDefaultLoggers = requiresDefaultLoggers;
+
+ // This context's LogManager.
+ final LogManager getOwner() {
+ return LogManager.this;
+ }
+
+ // This context owner's root logger, which if not null, and if
+ // the context requires default loggers, will be added to the context
+ // logger's tree.
+ final Logger getRootLogger() {
+ return getOwner().rootLogger;
+ }
+
+ // The global logger, which if not null, and if
+ // the context requires default loggers, will be added to the context
+ // logger's tree.
+ final Logger getGlobalLogger() {
+ @SuppressWarnings("deprecated") // avoids initialization cycles.
+ final Logger global = Logger.global;
+ return global;
}
Logger demandLogger(String name, String resourceBundleName) {
// a LogManager subclass may have its own implementation to add and
// get a Logger. So delegate to the LogManager to do the work.
- return manager.demandLogger(name, resourceBundleName, null);
+ final LogManager owner = getOwner();
+ return owner.demandLogger(name, resourceBundleName, null);
}
@@ -550,10 +650,10 @@
// or getLoggerNames()
//
private void ensureInitialized() {
- if (requiresDefaultLoggers) {
+ if (requiresDefaultLoggers()) {
// Ensure that the root and global loggers are set.
- ensureDefaultLogger(manager.rootLogger);
- ensureDefaultLogger(Logger.global);
+ ensureDefaultLogger(getRootLogger());
+ ensureDefaultLogger(getGlobalLogger());
}
}
@@ -582,13 +682,13 @@
// before adding 'logger'.
//
private void ensureAllDefaultLoggers(Logger logger) {
- if (requiresDefaultLoggers) {
+ if (requiresDefaultLoggers()) {
final String name = logger.getName();
if (!name.isEmpty()) {
- ensureDefaultLogger(manager.rootLogger);
- }
- if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
- ensureDefaultLogger(Logger.global);
+ ensureDefaultLogger(getRootLogger());
+ if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
+ ensureDefaultLogger(getGlobalLogger());
+ }
}
}
}
@@ -600,8 +700,8 @@
// This check is simple sanity: we do not want that this
// method be called for anything else than Logger.global
// or owner.rootLogger.
- if (!requiresDefaultLoggers || logger == null
- || logger != Logger.global && logger != manager.rootLogger) {
+ if (!requiresDefaultLoggers() || logger == null
+ || logger != Logger.global && logger != LogManager.this.rootLogger) {
// the case where we have a non null logger which is neither
// Logger.global nor manager.rootLogger indicates a serious
@@ -627,7 +727,7 @@
boolean addLocalLogger(Logger logger) {
// no need to add default loggers if it's not required
- return addLocalLogger(logger, requiresDefaultLoggers);
+ return addLocalLogger(logger, requiresDefaultLoggers());
}
// Add a logger to this context. This method will only set its level
@@ -665,11 +765,13 @@
// We're adding a new logger.
// Note that we are creating a weak reference here.
- ref = manager.new LoggerWeakRef(logger);
+ final LogManager owner = getOwner();
+ logger.setLogManager(owner);
+ ref = owner.new LoggerWeakRef(logger);
namedLoggers.put(name, ref);
// Apply any initial level defined for the new logger.
- Level level = manager.getLevelProperty(name + ".level", null);
+ Level level = owner.getLevelProperty(name + ".level", null);
if (level != null) {
doSetLevel(logger, level);
}
@@ -721,10 +823,12 @@
// If logger.getUseParentHandlers() returns 'true' and any of the logger's
// parents have levels or handlers defined, make sure they are instantiated.
private void processParentHandlers(final Logger logger, final String name) {
+ final LogManager owner = getOwner();
AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ @Override
public Void run() {
- if (logger != manager.rootLogger) {
- boolean useParent = manager.getBooleanProperty(name + ".useParentHandlers", true);
+ if (logger != owner.rootLogger) {
+ boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true);
if (!useParent) {
logger.setUseParentHandlers(false);
}
@@ -740,8 +844,8 @@
break;
}
String pname = name.substring(0, ix2);
- if (manager.getProperty(pname + ".level") != null ||
- manager.getProperty(pname + ".handlers") != null) {
+ if (owner.getProperty(pname + ".level") != null ||
+ owner.getProperty(pname + ".handlers") != null) {
// This pname has a level/handlers definition.
// Make sure it exists.
demandLogger(pname, null);
@@ -781,16 +885,17 @@
}
}
- static class SystemLoggerContext extends LoggerContext {
+ final class SystemLoggerContext extends LoggerContext {
// Add a system logger in the system context's namespace as well as
// in the LogManager's namespace if not exist so that there is only
// one single logger of the given name. System loggers are visible
// to applications unless a logger of the same name has been added.
+ @Override
Logger demandLogger(String name, String resourceBundleName) {
Logger result = findLogger(name);
if (result == null) {
// only allocate the new system logger once
- Logger newLogger = new Logger(name, resourceBundleName);
+ Logger newLogger = new Logger(name, resourceBundleName, null, getOwner());
do {
if (addLocalLogger(newLogger)) {
// We successfully added the new Logger that we
@@ -824,6 +929,7 @@
final String handlersPropertyName)
{
AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
public Object run() {
String names[] = parseClassNames(handlersPropertyName);
for (int i = 0; i < names.length; i++) {
@@ -1016,6 +1122,7 @@
// There is a security manager. Raise privilege before
// calling setLevel.
AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
public Object run() {
logger.setLevel(level);
return null;
@@ -1034,6 +1141,7 @@
// There is a security manager. Raise privilege before
// calling setParent.
AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
public Object run() {
logger.setParent(parent);
return null;
@@ -1131,14 +1239,9 @@
f = new File(f, "logging.properties");
fname = f.getCanonicalPath();
}
- InputStream in = new FileInputStream(fname);
- BufferedInputStream bin = new BufferedInputStream(in);
- try {
+ try (final InputStream in = new FileInputStream(fname)) {
+ final BufferedInputStream bin = new BufferedInputStream(in);
readConfiguration(bin);
- } finally {
- if (in != null) {
- in.close();
- }
}
}
@@ -1203,7 +1306,7 @@
}
hands = hands.trim();
int ix = 0;
- Vector<String> result = new Vector<>();
+ final List<String> result = new ArrayList<>();
while (ix < hands.length()) {
int end = ix;
while (end < hands.length()) {
@@ -1473,28 +1576,35 @@
// We use a subclass of Logger for the root logger, so
// that we only instantiate the global handlers when they
// are first needed.
- private class RootLogger extends Logger {
+ private final class RootLogger extends Logger {
private RootLogger() {
- super("", null);
+ // We do not call the protected Logger two args constructor here,
+ // to avoid calling LogManager.getLogManager() from within the
+ // RootLogger constructor.
+ super("", null, null, LogManager.this);
setLevel(defaultLevel);
}
+ @Override
public void log(LogRecord record) {
// Make sure that the global handlers have been instantiated.
initializeGlobalHandlers();
super.log(record);
}
+ @Override
public void addHandler(Handler h) {
initializeGlobalHandlers();
super.addHandler(h);
}
+ @Override
public void removeHandler(Handler h) {
initializeGlobalHandlers();
super.removeHandler(h);
}
+ @Override
public Handler[] getHandlers() {
initializeGlobalHandlers();
return super.getHandlers();
--- a/jdk/src/share/classes/java/util/logging/Logger.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/logging/Logger.java Sat Sep 14 20:43:34 2013 +0100
@@ -245,14 +245,26 @@
// In order to finish the initialization of the global logger, we
// will therefore call LogManager.getLogManager() here.
//
- // Care must be taken *not* to call Logger.getGlobal() in
- // LogManager static initializers in order to avoid such
- // deadlocks.
- //
- if (global != null && global.manager == null) {
- // Complete initialization of the global Logger.
- global.manager = LogManager.getLogManager();
- }
+ // To prevent race conditions we also need to call
+ // LogManager.getLogManager() unconditionally here.
+ // Indeed we cannot rely on the observed value of global.manager,
+ // because global.manager will become not null somewhere during
+ // the initialization of LogManager.
+ // If two threads are calling getGlobal() concurrently, one thread
+ // will see global.manager null and call LogManager.getLogManager(),
+ // but the other thread could come in at a time when global.manager
+ // is already set although ensureLogManagerInitialized is not finished
+ // yet...
+ // Calling LogManager.getLogManager() unconditionally will fix that.
+
+ LogManager.getLogManager();
+
+ // Now the global LogManager should be initialized,
+ // and the global logger should have been added to
+ // it, unless we were called within the constructor of a LogManager
+ // subclass installed as LogManager, in which case global.manager
+ // would still be null, and global will be lazily initialized later on.
+
return global;
}
@@ -298,11 +310,11 @@
* no corresponding resource can be found.
*/
protected Logger(String name, String resourceBundleName) {
- this(name, resourceBundleName, null);
+ this(name, resourceBundleName, null, LogManager.getLogManager());
}
- Logger(String name, String resourceBundleName, Class<?> caller) {
- this.manager = LogManager.getLogManager();
+ Logger(String name, String resourceBundleName, Class<?> caller, LogManager manager) {
+ this.manager = manager;
setupResourceInfo(resourceBundleName, caller);
this.name = name;
levelValue = Level.INFO.intValue();
@@ -332,8 +344,8 @@
levelValue = Level.INFO.intValue();
}
- // It is called from the LogManager.<clinit> to complete
- // initialization of the global Logger.
+ // It is called from LoggerContext.addLocalLogger() when the logger
+ // is actually added to a LogManager.
void setLogManager(LogManager manager) {
this.manager = manager;
}
@@ -558,7 +570,7 @@
// cleanup some Loggers that have been GC'ed
manager.drainLoggerRefQueueBounded();
Logger result = new Logger(null, resourceBundleName,
- Reflection.getCallerClass());
+ Reflection.getCallerClass(), manager);
result.anonymous = true;
Logger root = manager.getLogger("");
result.doSetParent(root);
@@ -623,7 +635,7 @@
* @param record the LogRecord to be published
*/
public void log(LogRecord record) {
- if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(record.getLevel())) {
return;
}
Filter theFilter = filter;
@@ -677,7 +689,7 @@
* @param msg The string message (or a key in the message catalog)
*/
public void log(Level level, String msg) {
- if (level.intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msg);
@@ -698,7 +710,7 @@
* desired log message
*/
public void log(Level level, Supplier<String> msgSupplier) {
- if (level.intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msgSupplier.get());
@@ -717,7 +729,7 @@
* @param param1 parameter to the message
*/
public void log(Level level, String msg, Object param1) {
- if (level.intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msg);
@@ -738,7 +750,7 @@
* @param params array of parameters to the message
*/
public void log(Level level, String msg, Object params[]) {
- if (level.intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msg);
@@ -763,7 +775,7 @@
* @param thrown Throwable associated with log message.
*/
public void log(Level level, String msg, Throwable thrown) {
- if (level.intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msg);
@@ -791,7 +803,7 @@
* @since 1.8
*/
public void log(Level level, Throwable thrown, Supplier<String> msgSupplier) {
- if (level.intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msgSupplier.get());
@@ -817,7 +829,7 @@
* @param msg The string message (or a key in the message catalog)
*/
public void logp(Level level, String sourceClass, String sourceMethod, String msg) {
- if (level.intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msg);
@@ -844,7 +856,7 @@
*/
public void logp(Level level, String sourceClass, String sourceMethod,
Supplier<String> msgSupplier) {
- if (level.intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msgSupplier.get());
@@ -869,7 +881,7 @@
*/
public void logp(Level level, String sourceClass, String sourceMethod,
String msg, Object param1) {
- if (level.intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msg);
@@ -896,7 +908,7 @@
*/
public void logp(Level level, String sourceClass, String sourceMethod,
String msg, Object params[]) {
- if (level.intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msg);
@@ -927,7 +939,7 @@
*/
public void logp(Level level, String sourceClass, String sourceMethod,
String msg, Throwable thrown) {
- if (level.intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msg);
@@ -961,7 +973,7 @@
*/
public void logp(Level level, String sourceClass, String sourceMethod,
Throwable thrown, Supplier<String> msgSupplier) {
- if (level.intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msgSupplier.get());
@@ -1009,7 +1021,7 @@
*/
public void logrb(Level level, String sourceClass, String sourceMethod,
String bundleName, String msg) {
- if (level.intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msg);
@@ -1040,7 +1052,7 @@
*/
public void logrb(Level level, String sourceClass, String sourceMethod,
String bundleName, String msg, Object param1) {
- if (level.intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msg);
@@ -1073,7 +1085,7 @@
*/
public void logrb(Level level, String sourceClass, String sourceMethod,
String bundleName, String msg, Object params[]) {
- if (level.intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msg);
@@ -1110,7 +1122,7 @@
*/
public void logrb(Level level, String sourceClass, String sourceMethod,
String bundleName, String msg, Throwable thrown) {
- if (level.intValue() < levelValue || levelValue == offValue) {
+ if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msg);
@@ -1136,9 +1148,6 @@
* @param sourceMethod name of method that is being entered
*/
public void entering(String sourceClass, String sourceMethod) {
- if (Level.FINER.intValue() < levelValue) {
- return;
- }
logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
}
@@ -1155,11 +1164,7 @@
* @param param1 parameter to the method being entered
*/
public void entering(String sourceClass, String sourceMethod, Object param1) {
- if (Level.FINER.intValue() < levelValue) {
- return;
- }
- Object params[] = { param1 };
- logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", params);
+ logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param1);
}
/**
@@ -1176,14 +1181,12 @@
* @param params array of parameters to the method being entered
*/
public void entering(String sourceClass, String sourceMethod, Object params[]) {
- if (Level.FINER.intValue() < levelValue) {
- return;
- }
String msg = "ENTRY";
if (params == null ) {
logp(Level.FINER, sourceClass, sourceMethod, msg);
return;
}
+ if (!isLoggable(Level.FINER)) return;
for (int i = 0; i < params.length; i++) {
msg = msg + " {" + i + "}";
}
@@ -1201,9 +1204,6 @@
* @param sourceMethod name of the method
*/
public void exiting(String sourceClass, String sourceMethod) {
- if (Level.FINER.intValue() < levelValue) {
- return;
- }
logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
}
@@ -1221,10 +1221,6 @@
* @param result Object that is being returned
*/
public void exiting(String sourceClass, String sourceMethod, Object result) {
- if (Level.FINER.intValue() < levelValue) {
- return;
- }
- Object params[] = { result };
logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
}
@@ -1250,7 +1246,7 @@
* @param thrown The Throwable that is being thrown.
*/
public void throwing(String sourceClass, String sourceMethod, Throwable thrown) {
- if (Level.FINER.intValue() < levelValue || levelValue == offValue ) {
+ if (!isLoggable(Level.FINER)) {
return;
}
LogRecord lr = new LogRecord(Level.FINER, "THROW");
@@ -1274,9 +1270,6 @@
* @param msg The string message (or a key in the message catalog)
*/
public void severe(String msg) {
- if (Level.SEVERE.intValue() < levelValue) {
- return;
- }
log(Level.SEVERE, msg);
}
@@ -1290,9 +1283,6 @@
* @param msg The string message (or a key in the message catalog)
*/
public void warning(String msg) {
- if (Level.WARNING.intValue() < levelValue) {
- return;
- }
log(Level.WARNING, msg);
}
@@ -1306,9 +1296,6 @@
* @param msg The string message (or a key in the message catalog)
*/
public void info(String msg) {
- if (Level.INFO.intValue() < levelValue) {
- return;
- }
log(Level.INFO, msg);
}
@@ -1322,9 +1309,6 @@
* @param msg The string message (or a key in the message catalog)
*/
public void config(String msg) {
- if (Level.CONFIG.intValue() < levelValue) {
- return;
- }
log(Level.CONFIG, msg);
}
@@ -1338,9 +1322,6 @@
* @param msg The string message (or a key in the message catalog)
*/
public void fine(String msg) {
- if (Level.FINE.intValue() < levelValue) {
- return;
- }
log(Level.FINE, msg);
}
@@ -1354,9 +1335,6 @@
* @param msg The string message (or a key in the message catalog)
*/
public void finer(String msg) {
- if (Level.FINER.intValue() < levelValue) {
- return;
- }
log(Level.FINER, msg);
}
@@ -1370,9 +1348,6 @@
* @param msg The string message (or a key in the message catalog)
*/
public void finest(String msg) {
- if (Level.FINEST.intValue() < levelValue) {
- return;
- }
log(Level.FINEST, msg);
}
@@ -1798,7 +1773,7 @@
if (parent == null) {
throw new NullPointerException();
}
- manager.checkPermission();
+ checkPermission();
doSetParent(parent);
}
--- a/jdk/src/share/classes/java/util/logging/MemoryHandler.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/logging/MemoryHandler.java Sat Sep 14 20:43:34 2013 +0100
@@ -88,7 +88,7 @@
public class MemoryHandler extends Handler {
private final static int DEFAULT_SIZE = 1000;
- private Level pushLevel;
+ private volatile Level pushLevel;
private int size;
private Handler target;
private LogRecord buffer[];
@@ -188,6 +188,7 @@
* @param record description of the log event. A null record is
* silently ignored and is not published
*/
+ @Override
public synchronized void publish(LogRecord record) {
if (!isLoggable(record)) {
return;
@@ -227,6 +228,7 @@
* Note that the current contents of the <tt>MemoryHandler</tt>
* buffer are <b>not</b> written out. That requires a "push".
*/
+ @Override
public void flush() {
target.flush();
}
@@ -238,6 +240,7 @@
* @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>.
*/
+ @Override
public void close() throws SecurityException {
target.close();
setLevel(Level.OFF);
@@ -252,11 +255,10 @@
* @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>.
*/
- public void setPushLevel(Level newLevel) throws SecurityException {
+ public synchronized void setPushLevel(Level newLevel) throws SecurityException {
if (newLevel == null) {
throw new NullPointerException();
}
- LogManager manager = LogManager.getLogManager();
checkPermission();
pushLevel = newLevel;
}
@@ -266,7 +268,7 @@
*
* @return the value of the <tt>pushLevel</tt>
*/
- public synchronized Level getPushLevel() {
+ public Level getPushLevel() {
return pushLevel;
}
@@ -283,6 +285,7 @@
* @return true if the <tt>LogRecord</tt> would be logged.
*
*/
+ @Override
public boolean isLoggable(LogRecord record) {
return super.isLoggable(record);
}
--- a/jdk/src/share/classes/java/util/logging/SocketHandler.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/logging/SocketHandler.java Sat Sep 14 20:43:34 2013 +0100
@@ -82,7 +82,6 @@
private Socket sock;
private String host;
private int port;
- private String portProperty;
// Private method to configure a SocketHandler from LogManager
// properties and/or default values as specified in the class
@@ -177,6 +176,7 @@
* @exception SecurityException if a security manager exists and if
* the caller does not have <tt>LoggingPermission("control")</tt>.
*/
+ @Override
public synchronized void close() throws SecurityException {
super.close();
if (sock != null) {
@@ -195,6 +195,7 @@
* @param record description of the log event. A null record is
* silently ignored and is not published
*/
+ @Override
public synchronized void publish(LogRecord record) {
if (!isLoggable(record)) {
return;
--- a/jdk/src/share/classes/java/util/logging/StreamHandler.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/logging/StreamHandler.java Sat Sep 14 20:43:34 2013 +0100
@@ -73,10 +73,9 @@
*/
public class StreamHandler extends Handler {
- private LogManager manager = LogManager.getLogManager();
private OutputStream output;
private boolean doneHeader;
- private Writer writer;
+ private volatile Writer writer;
// Private method to configure a StreamHandler from LogManager
// properties and/or default values as specified in the class
@@ -169,7 +168,8 @@
* @exception UnsupportedEncodingException if the named encoding is
* not supported.
*/
- public void setEncoding(String encoding)
+ @Override
+ public synchronized void setEncoding(String encoding)
throws SecurityException, java.io.UnsupportedEncodingException {
super.setEncoding(encoding);
if (output == null) {
@@ -201,6 +201,7 @@
* @param record description of the log event. A null record is
* silently ignored and is not published
*/
+ @Override
public synchronized void publish(LogRecord record) {
if (!isLoggable(record)) {
return;
@@ -240,6 +241,7 @@
* @return true if the <tt>LogRecord</tt> would be logged.
*
*/
+ @Override
public boolean isLoggable(LogRecord record) {
if (writer == null || record == null) {
return false;
@@ -250,6 +252,7 @@
/**
* Flush any buffered messages.
*/
+ @Override
public synchronized void flush() {
if (writer != null) {
try {
@@ -294,6 +297,7 @@
* @exception SecurityException if a security manager exists and if
* the caller does not have LoggingPermission("control").
*/
+ @Override
public synchronized void close() throws SecurityException {
flushAndClose();
}
--- a/jdk/src/share/classes/java/util/stream/AbstractPipeline.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/AbstractPipeline.java Sat Sep 14 20:43:34 2013 +0100
@@ -71,6 +71,9 @@
*/
abstract class AbstractPipeline<E_IN, E_OUT, S extends BaseStream<E_OUT, S>>
extends PipelineHelper<E_OUT> implements BaseStream<E_OUT, S> {
+ private static final String MSG_STREAM_LINKED = "stream has already been operated upon or closed";
+ private static final String MSG_CONSUMED = "source already consumed or closed";
+
/**
* Backlink to the head of the pipeline chain (self if this is the source
* stage).
@@ -137,6 +140,8 @@
*/
private boolean sourceAnyStateful;
+ private Runnable sourceCloseAction;
+
/**
* True if pipeline is parallel, otherwise the pipeline is sequential; only
* valid for the source stage.
@@ -195,7 +200,7 @@
*/
AbstractPipeline(AbstractPipeline<?, E_IN, ?> previousStage, int opFlags) {
if (previousStage.linkedOrConsumed)
- throw new IllegalStateException("stream has already been operated upon");
+ throw new IllegalStateException(MSG_STREAM_LINKED);
previousStage.linkedOrConsumed = true;
previousStage.nextStage = this;
@@ -221,7 +226,7 @@
final <R> R evaluate(TerminalOp<E_OUT, R> terminalOp) {
assert getOutputShape() == terminalOp.inputShape();
if (linkedOrConsumed)
- throw new IllegalStateException("stream has already been operated upon");
+ throw new IllegalStateException(MSG_STREAM_LINKED);
linkedOrConsumed = true;
return isParallel()
@@ -238,7 +243,7 @@
@SuppressWarnings("unchecked")
final Node<E_OUT> evaluateToArrayNode(IntFunction<E_OUT[]> generator) {
if (linkedOrConsumed)
- throw new IllegalStateException("stream has already been operated upon");
+ throw new IllegalStateException(MSG_STREAM_LINKED);
linkedOrConsumed = true;
// If the last intermediate operation is stateful then
@@ -266,7 +271,7 @@
throw new IllegalStateException();
if (linkedOrConsumed)
- throw new IllegalStateException("stream has already been operated upon");
+ throw new IllegalStateException(MSG_STREAM_LINKED);
linkedOrConsumed = true;
if (sourceStage.sourceSpliterator != null) {
@@ -282,7 +287,7 @@
return s;
}
else {
- throw new IllegalStateException("source already consumed");
+ throw new IllegalStateException(MSG_CONSUMED);
}
}
@@ -302,12 +307,35 @@
return (S) this;
}
+ @Override
+ public void close() {
+ linkedOrConsumed = true;
+ sourceSupplier = null;
+ sourceSpliterator = null;
+ if (sourceStage.sourceCloseAction != null) {
+ Runnable closeAction = sourceStage.sourceCloseAction;
+ sourceStage.sourceCloseAction = null;
+ closeAction.run();
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public S onClose(Runnable closeHandler) {
+ Runnable existingHandler = sourceStage.sourceCloseAction;
+ sourceStage.sourceCloseAction =
+ (existingHandler == null)
+ ? closeHandler
+ : Streams.composeWithExceptions(existingHandler, closeHandler);
+ return (S) this;
+ }
+
// Primitive specialization use co-variant overrides, hence is not final
@Override
@SuppressWarnings("unchecked")
public Spliterator<E_OUT> spliterator() {
if (linkedOrConsumed)
- throw new IllegalStateException("stream has already been operated upon");
+ throw new IllegalStateException(MSG_STREAM_LINKED);
linkedOrConsumed = true;
if (this == sourceStage) {
@@ -324,7 +352,7 @@
return lazySpliterator(s);
}
else {
- throw new IllegalStateException("source already consumed");
+ throw new IllegalStateException(MSG_CONSUMED);
}
}
else {
@@ -424,7 +452,7 @@
sourceStage.sourceSupplier = null;
}
else {
- throw new IllegalStateException("source already consumed");
+ throw new IllegalStateException(MSG_CONSUMED);
}
if (isParallel()) {
--- a/jdk/src/share/classes/java/util/stream/BaseStream.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/BaseStream.java Sat Sep 14 20:43:34 2013 +0100
@@ -24,18 +24,106 @@
*/
package java.util.stream;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collection;
import java.util.Iterator;
import java.util.Spliterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.IntConsumer;
+import java.util.function.Predicate;
/**
- * Base interface for stream types such as {@link Stream}, {@link IntStream},
- * etc. Contains methods common to all stream types.
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations. The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link IntStream}:
+ *
+ * <pre>{@code
+ * int sum = widgets.stream()
+ * .filter(w -> w.getColor() == RED)
+ * .mapToInt(w -> w.getWeight())
+ * .sum();
+ * }</pre>
+ *
+ * In this example, {@code widgets} is a {@code Collection<Widget>}. We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code int} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
+ *
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>. A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an IO channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link Stream#filter(Predicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link IntStream#sum()} or {@link IntStream#forEach(IntConsumer)}).
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
+ *
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals. Collections are primarily concerned with the efficient
+ * management of, and access to, their elements. By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
+ *
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source. Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
*
- * @param <T> type of stream elements
- * @param <S> type of stream implementing {@code BaseStream}
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToInt} in the example above. Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references. These parameters can never be null, should not modify the
+ * stream source, and should be
+ * <a href="package-summary.html#NonInterference">effectively stateless</a>
+ * (their result should not depend on any state that might change during
+ * execution of the stream pipeline.)
+ *
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once. This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream. A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
+ *
+ * <p>Streams have a {@link #close()} method and implement {@link AutoCloseable},
+ * but nearly all stream instances do not actually need to be closed after use.
+ * Generally, only streams whose source is an IO channel (such as those returned
+ * by {@link Files#lines(Path, Charset)}) will require closing. Most streams
+ * are backed by collections, arrays, or generating functions, which require no
+ * special resource management. (If a stream does require closing, it can be
+ * declared as a resource in a {@code try}-with-resources statement.)
+ *
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>. This
+ * execution mode is a property of the stream. Streams are created
+ * with an initial choice of sequential or parallel execution. (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.) This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
+ *
+ * @param <T> the type of the stream elements
+ * @param <S> the type of of the stream implementing {@code BaseStream}
* @since 1.8
+ * @see <a href="package-summary.html">java.util.stream</a>
*/
-public interface BaseStream<T, S extends BaseStream<T, S>> {
+public interface BaseStream<T, S extends BaseStream<T, S>>
+ extends AutoCloseable {
/**
* Returns an iterator for the elements of this stream.
*
@@ -57,14 +145,11 @@
Spliterator<T> spliterator();
/**
- * Returns whether this stream, when executed, would execute in parallel
- * (assuming no further modification of the stream, such as appending
- * further intermediate operations or changing its parallelism). Calling
- * this method after invoking an intermediate or terminal stream operation
- * method may yield unpredictable results.
+ * Returns whether this stream, if a terminal operation were to be executed,
+ * would execute in parallel. Calling this method after invoking an
+ * terminal stream operation method may yield unpredictable results.
*
* @return {@code true} if this stream would execute in parallel if executed
- * without further modification otherwise {@code false}
*/
boolean isParallel();
@@ -95,7 +180,8 @@
/**
* Returns an equivalent stream that is
* <a href="package-summary.html#Ordering">unordered</a>. May return
- * itself if the stream was already unordered.
+ * itself, either because the stream was already unordered, or because
+ * the underlying stream state was modified to be unordered.
*
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
@@ -103,4 +189,33 @@
* @return an unordered stream
*/
S unordered();
+
+ /**
+ * Returns an equivalent stream with an additional close handler. Close
+ * handlers are run when the {@link #close()} method
+ * is called on the stream, and are executed in the order they were
+ * added. All close handlers are run, even if earlier close handlers throw
+ * exceptions. If any close handler throws an exception, the first
+ * exception thrown will be relayed to the caller of {@code close()}, with
+ * any remaining exceptions added to that exception as suppressed exceptions
+ * (unless one of the remaining exceptions is the same exception as the
+ * first exception, since an exception cannot suppress itself.) May
+ * return itself.
+ *
+ * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+ * operation</a>.
+ *
+ * @param closeHandler A task to execute when the stream is closed
+ * @return a stream with a handler that is run if the stream is closed
+ */
+ S onClose(Runnable closeHandler);
+
+ /**
+ * Closes this stream, causing all close handlers for this stream pipeline
+ * to be called.
+ *
+ * @see AutoCloseable#close()
+ */
+ @Override
+ void close();
}
--- a/jdk/src/share/classes/java/util/stream/CloseableStream.java Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +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. 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;
-
-/**
- * A {@code CloseableStream} is a {@code Stream} that can be closed.
- * The close method is invoked to release resources that the object is
- * holding (such as open files).
- *
- * @param <T> The type of stream elements
- * @since 1.8
- */
-public interface CloseableStream<T> extends Stream<T>, AutoCloseable {
-
- /**
- * Closes this resource, relinquishing any underlying resources.
- * This method is invoked automatically on objects managed by the
- * {@code try}-with-resources statement. Does nothing if called when
- * the resource has already been closed.
- *
- * This method does not allow throwing checked {@code Exception}s like
- * {@link AutoCloseable#close() AutoCloseable.close()}. Cases where the
- * close operation may fail require careful attention by implementers. It
- * is strongly advised to relinquish the underlying resources and to
- * internally <em>mark</em> the resource as closed. The {@code close}
- * method is unlikely to be invoked more than once and so this ensures
- * that the resources are released in a timely manner. Furthermore it
- * reduces problems that could arise when the resource wraps, or is
- * wrapped, by another resource.
- *
- * @see AutoCloseable#close()
- */
- void close();
-}
--- a/jdk/src/share/classes/java/util/stream/Collector.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/Collector.java Sat Sep 14 20:43:34 2013 +0100
@@ -26,6 +26,7 @@
import java.util.Collections;
import java.util.EnumSet;
+import java.util.Objects;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
@@ -33,71 +34,74 @@
import java.util.function.Supplier;
/**
- * A <a href="package-summary.html#Reduction">reduction operation</a> that
- * folds input elements into a mutable result container, optionally transforming
+ * A <a href="package-summary.html#Reduction">mutable reduction operation</a> that
+ * accumulates input elements into a mutable result container, optionally transforming
* the accumulated result into a final representation after all input elements
- * have been processed.
+ * have been processed. Reduction operations can be performed either sequentially
+ * or in parallel.
*
* <p>Examples of mutable reduction operations include:
* accumulating elements into a {@code Collection}; concatenating
* strings using a {@code StringBuilder}; computing summary information about
* elements such as sum, min, max, or average; computing "pivot table" summaries
- * such as "maximum valued transaction by seller", etc. Reduction operations
- * can be performed either sequentially or in parallel.
- *
- * <p>The following are examples of using the predefined {@code Collector}
- * implementations in {@link Collectors} with the {@code Stream} API to perform
- * mutable reduction tasks:
- * <pre>{@code
- * // Accumulate names into a List
- * List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
- *
- * // Accumulate names into a TreeSet
- * Set<String> list = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
- *
- * // Convert elements to strings and concatenate them, separated by commas
- * String joined = things.stream()
- * .map(Object::toString)
- * .collect(Collectors.joining(", "));
- *
- * // Find highest-paid employee
- * Employee highestPaid = employees.stream()
- * .collect(Collectors.maxBy(Comparators.comparing(Employee::getSalary)))
- * .get();
- *
- * // Group employees by department
- * Map<Department, List<Employee>> byDept
- * = employees.stream()
- * .collect(Collectors.groupingBy(Employee::getDepartment));
- *
- * // Find highest-paid employee by department
- * Map<Department, Optional<Employee>> highestPaidByDept
- * = employees.stream()
- * .collect(Collectors.groupingBy(Employee::getDepartment,
- * Collectors.maxBy(Comparators.comparing(Employee::getSalary))));
- *
- * // Partition students into passing and failing
- * Map<Boolean, List<Student>> passingFailing =
- * students.stream()
- * .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
- *
- * }</pre>
+ * such as "maximum valued transaction by seller", etc. The class {@link Collectors}
+ * provides implementations of many common mutable reductions.
*
* <p>A {@code Collector} is specified by four functions that work together to
* accumulate entries into a mutable result container, and optionally perform
- * a final transform on the result. They are: creation of a new result container,
- * incorporating a new data element into a result container, combining two
- * result containers into one, and performing a final transform on the container.
- * The combiner function is used during parallel operations, where
- * subsets of the input are accumulated into separate result
- * containers, and then the subresults merged into a combined result. The
- * combiner function may merge one set of subresults into the other and return
- * that, or it may return a new object to describe the combined results.
+ * a final transform on the result. They are: <ul>
+ * <li>creation of a new result container ({@link #supplier()})</li>
+ * <li>incorporating a new data element into a result container ({@link #accumulator()})</li>
+ * <li>combining two result containers into one ({@link #combiner()})</li>
+ * <li>performing an optional final transform on the container ({@link #finisher()})</li>
+ * </ul>
*
* <p>Collectors also have a set of characteristics, such as
- * {@link Characteristics#CONCURRENT}. These characteristics provide
- * hints that can be used by a reduction implementation to provide better
- * performance.
+ * {@link Characteristics#CONCURRENT}, that provide hints that can be used by a
+ * reduction implementation to provide better performance.
+ *
+ * <p>A sequential implementation of a reduction using a collector would
+ * create a single result container using the supplier function, and invoke the
+ * accumulator function once for each input element. A parallel implementation
+ * would partition the input, create a result container for each partition,
+ * accumulate the contents of each partition into a subresult for that partition,
+ * and then use the combiner function to merge the subresults into a combined
+ * result.
+ *
+ * <p>To ensure that sequential and parallel executions produce equivalent
+ * results, the collector functions must satisfy an <em>identity</em> and an
+ * <a href="package-summary.html#Associativity">associativity</a> constraints.
+ *
+ * <p>The identity constraint says that for any partially accumulated result,
+ * combining it with an empty result container must produce an equivalent
+ * result. That is, for a partially accumulated result {@code a} that is the
+ * result of any series of accumulator and combiner invocations, {@code a} must
+ * be equivalent to {@code combiner.apply(a, supplier.get())}.
+ *
+ * <p>The associativity constraint says that splitting the computation must
+ * produce an equivalent result. That is, for any input elements {@code t1}
+ * and {@code t2}, the results {@code r1} and {@code r2} in the computation
+ * below must be equivalent:
+ * <pre>{@code
+ * A a1 = supplier.get();
+ * accumulator.accept(a1, t1);
+ * accumulator.accept(a1, t2);
+ * R r1 = finisher.apply(a1); // result without splitting
+ *
+ * A a2 = supplier.get();
+ * accumulator.accept(a2, t1);
+ * A a3 = supplier.get();
+ * accumulator.accept(a3, t2);
+ * R r2 = finisher.apply(combiner.apply(a2, a3)); // result with splitting
+ * } </pre>
+ *
+ * <p>For collectors that do not have the {@code UNORDERED} characteristic,
+ * two accumulated results {@code a1} and {@code a2} are equivalent if
+ * {@code finisher.apply(a1).equals(finisher.apply(a2))}. For unordered
+ * collectors, equivalence is relaxed to allow for non-equality related to
+ * differences in order. (For example, an unordered collector that accumulated
+ * elements to a {@code List} would consider two lists equivalent if they
+ * contained the same elements, ignoring order.)
*
* <p>Libraries that implement reduction based on {@code Collector}, such as
* {@link Stream#collect(Collector)}, must adhere to the following constraints:
@@ -132,6 +136,20 @@
* originating data is unordered.</li>
* </ul>
*
+ * <p>In addition to the predefined implementations in {@link Collectors}, the
+ * static factory methods {@link #of(Supplier, BiConsumer, BinaryOperator, Characteristics...)}
+ * can be used to construct collectors. For example, you could create a collector
+ * that accumulates widgets into a {@code TreeSet} with:
+ *
+ * <pre>{@code
+ * Collector<Widget, ?, TreeSet<Widget>> intoSet =
+ * Collector.of(TreeSet::new, TreeSet::add,
+ * (left, right) -> { left.addAll(right); return left; });
+ * }</pre>
+ *
+ * (This behavior is also implemented by the predefined collector
+ * {@link Collectors#toCollection(Supplier)}).
+ *
* @apiNote
* Performing a reduction operation with a {@code Collector} should produce a
* result equivalent to:
@@ -144,27 +162,35 @@
*
* <p>However, the library is free to partition the input, perform the reduction
* on the partitions, and then use the combiner function to combine the partial
- * results to achieve a parallel reduction. Depending on the specific reduction
+ * results to achieve a parallel reduction. (Depending on the specific reduction
* operation, this may perform better or worse, depending on the relative cost
- * of the accumulator and combiner functions.
+ * of the accumulator and combiner functions.)
+ *
+ * <p>Collectors are designed to be <em>composed</em>; many of the methods
+ * in {@link Collectors} are functions that take a collector and produce
+ * a new collector. For example, given the following collector that computes
+ * the sum of the salaries of a stream of employees:
*
- * <p>An example of an operation that can be easily modeled by {@code Collector}
- * is accumulating elements into a {@code TreeSet}. In this case, the {@code
- * resultSupplier()} function is {@code () -> new Treeset<T>()}, the
- * {@code accumulator} function is
- * {@code (set, element) -> set.add(element) }, and the combiner
- * function is {@code (left, right) -> { left.addAll(right); return left; }}.
- * (This behavior is implemented by
- * {@code Collectors.toCollection(TreeSet::new)}).
+ * <pre>{@code
+ * Collector<Employee, ?, Integer> summingSalaries
+ * = Collectors.summingInt(Employee::getSalary))
+ * }</pre>
*
- * TODO Associativity and commutativity
+ * If we wanted to create a collector to tabulate the sum of salaries by
+ * department, we could reuse the "sum of salaries" logic using
+ * {@link Collectors#groupingBy(Function, Collector)}:
+ *
+ * <pre>{@code
+ * Collector<Employee, ?, Map<Department, Integer>> summingSalariesByDept
+ * = Collectors.groupingBy(Employee::getDepartment, summingSalaries);
+ * }</pre>
*
* @see Stream#collect(Collector)
* @see Collectors
*
* @param <T> the type of input elements to the reduction operation
* @param <A> the mutable accumulation type of the reduction operation (often
- * hidden as an implementation detail)
+ * hidden as an implementation detail)
* @param <R> the result type of the reduction operation
* @since 1.8
*/
@@ -177,25 +203,25 @@
Supplier<A> supplier();
/**
- * A function that folds a new value into a mutable result container.
+ * A function that folds a value into a mutable result container.
*
- * @return a function which folds a new value into a mutable result container
+ * @return a function which folds a value into a mutable result container
*/
BiConsumer<A, T> accumulator();
/**
* A function that accepts two partial results and merges them. The
* combiner function may fold state from one argument into the other and
- * return that, or may return a new result object.
+ * return that, or may return a new result container.
*
- * @return a function which combines two partial results into a cumulative
+ * @return a function which combines two partial results into a combined
* result
*/
BinaryOperator<A> combiner();
/**
* Perform the final transformation from the intermediate accumulation type
- * {@code A} to the final result representation {@code R}.
+ * {@code A} to the final result type {@code R}.
*
* <p>If the characteristic {@code IDENTITY_TRANSFORM} is
* set, this function may be presumed to be an identity transform with an
@@ -228,12 +254,17 @@
* @param <T> The type of input elements for the new collector
* @param <R> The type of intermediate accumulation result, and final result,
* for the new collector
+ * @throws NullPointerException if any argument is null
* @return the new {@code Collector}
*/
public static<T, R> Collector<T, R, R> of(Supplier<R> supplier,
BiConsumer<R, T> accumulator,
BinaryOperator<R> combiner,
Characteristics... characteristics) {
+ Objects.requireNonNull(supplier);
+ Objects.requireNonNull(accumulator);
+ Objects.requireNonNull(combiner);
+ Objects.requireNonNull(characteristics);
Set<Characteristics> cs = (characteristics.length == 0)
? Collectors.CH_ID
: Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH,
@@ -254,6 +285,7 @@
* @param <T> The type of input elements for the new collector
* @param <A> The intermediate accumulation type of the new collector
* @param <R> The final result type of the new collector
+ * @throws NullPointerException if any argument is null
* @return the new {@code Collector}
*/
public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,
@@ -261,6 +293,11 @@
BinaryOperator<A> combiner,
Function<A, R> finisher,
Characteristics... characteristics) {
+ Objects.requireNonNull(supplier);
+ Objects.requireNonNull(accumulator);
+ Objects.requireNonNull(combiner);
+ Objects.requireNonNull(finisher);
+ Objects.requireNonNull(characteristics);
Set<Characteristics> cs = Collectors.CH_NOID;
if (characteristics.length > 0) {
cs = EnumSet.noneOf(Characteristics.class);
@@ -288,8 +325,9 @@
CONCURRENT,
/**
- * Indicates that the result container has no intrinsic order, such as
- * a {@link Set}.
+ * Indicates that the collection operation does not commit to preserving
+ * the encounter order of input elements. (This might be true if the
+ * result container has no intrinsic order, such as a {@link Set}.)
*/
UNORDERED,
--- a/jdk/src/share/classes/java/util/stream/Collectors.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/Collectors.java Sat Sep 14 20:43:34 2013 +0100
@@ -62,37 +62,35 @@
* operations, such as accumulating elements into collections, summarizing
* elements according to various criteria, etc.
*
- * <p>The following are examples of using the predefined {@code Collector}
- * implementations in {@link Collectors} with the {@code Stream} API to perform
- * mutable reduction tasks:
+ * <p>The following are examples of using the predefined collectors to perform
+ * common mutable reduction tasks:
*
* <pre>{@code
* // Accumulate names into a List
* List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
*
* // Accumulate names into a TreeSet
- * Set<String> list = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
+ * Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
*
* // Convert elements to strings and concatenate them, separated by commas
* String joined = things.stream()
* .map(Object::toString)
* .collect(Collectors.joining(", "));
*
- * // Find highest-paid employee
- * Employee highestPaid = employees.stream()
- * .collect(Collectors.maxBy(Comparator.comparing(Employee::getSalary)))
- * .get();
+ * // Compute sum of salaries of employee
+ * int total = employees.stream()
+ * .collect(Collectors.summingInt(Employee::getSalary)));
*
* // Group employees by department
* Map<Department, List<Employee>> byDept
* = employees.stream()
* .collect(Collectors.groupingBy(Employee::getDepartment));
*
- * // Find highest-paid employee by department
- * Map<Department, Optional<Employee>> highestPaidByDept
+ * // Compute sum of salaries by department
+ * Map<Department, Integer> totalByDept
* = employees.stream()
* .collect(Collectors.groupingBy(Employee::getDepartment,
- * Collectors.maxBy(Comparator.comparing(Employee::getSalary))));
+ * Collectors.summingInt(Employee::getSalary)));
*
* // Partition students into passing and failing
* Map<Boolean, List<Student>> passingFailing =
@@ -101,8 +99,6 @@
*
* }</pre>
*
- * TODO explanation of parallel collection
- *
* @since 1.8
*/
public final class Collectors {
@@ -222,7 +218,8 @@
/**
* Returns a {@code Collector} that accumulates the input elements into a
* new {@code List}. There are no guarantees on the type, mutability,
- * serializability, or thread-safety of the {@code List} returned.
+ * serializability, or thread-safety of the {@code List} returned; if more
+ * control over the returned {@code List} is required, use {@link #toCollection(Supplier)}.
*
* @param <T> the type of the input elements
* @return a {@code Collector} which collects all the input elements into a
@@ -238,7 +235,9 @@
/**
* Returns a {@code Collector} that accumulates the input elements into a
* new {@code Set}. There are no guarantees on the type, mutability,
- * serializability, or thread-safety of the {@code Set} returned.
+ * serializability, or thread-safety of the {@code Set} returned; if more
+ * control over the returned {@code Set} is required, use
+ * {@link #toCollection(Supplier)}.
*
* <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
* Collector.
@@ -903,7 +902,7 @@
* where the city names are sorted:
* <pre>{@code
* ConcurrentMap<City, Set<String>> namesByCity
- * = people.stream().collect(groupingByConcurrent(Person::getCity, ConcurrentSkipListMap::new,
+ * = people.stream().collect(groupingByConcurrent(Person::getCity,
* mapping(Person::getLastName, toSet())));
* }</pre>
*
--- a/jdk/src/share/classes/java/util/stream/DelegatingStream.java Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,270 +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. 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.util.Comparator;
-import java.util.Iterator;
-import java.util.Objects;
-import java.util.Optional;
-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.Function;
-import java.util.function.IntFunction;
-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;
-
-/**
- * A {@code Stream} implementation that delegates operations to another {@code
- * Stream}.
- *
- * @param <T> type of stream elements for this stream and underlying delegate
- * stream
- *
- * @since 1.8
- */
-public class DelegatingStream<T> implements Stream<T> {
- final private Stream<T> delegate;
-
- /**
- * Construct a {@code Stream} that delegates operations to another {@code
- * Stream}.
- *
- * @param delegate the underlying {@link Stream} to which we delegate all
- * {@code Stream} methods
- * @throws NullPointerException if the delegate is null
- */
- public DelegatingStream(Stream<T> delegate) {
- this.delegate = Objects.requireNonNull(delegate);
- }
-
- // -- BaseStream methods --
-
- @Override
- public Spliterator<T> spliterator() {
- return delegate.spliterator();
- }
-
- @Override
- public boolean isParallel() {
- return delegate.isParallel();
- }
-
- @Override
- public Iterator<T> iterator() {
- return delegate.iterator();
- }
-
- // -- Stream methods --
-
- @Override
- public Stream<T> filter(Predicate<? super T> predicate) {
- return delegate.filter(predicate);
- }
-
- @Override
- public <R> Stream<R> map(Function<? super T, ? extends R> mapper) {
- return delegate.map(mapper);
- }
-
- @Override
- public IntStream mapToInt(ToIntFunction<? super T> mapper) {
- return delegate.mapToInt(mapper);
- }
-
- @Override
- public LongStream mapToLong(ToLongFunction<? super T> mapper) {
- return delegate.mapToLong(mapper);
- }
-
- @Override
- public DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper) {
- return delegate.mapToDouble(mapper);
- }
-
- @Override
- public <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) {
- return delegate.flatMap(mapper);
- }
-
- @Override
- public IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper) {
- return delegate.flatMapToInt(mapper);
- }
-
- @Override
- public LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper) {
- return delegate.flatMapToLong(mapper);
- }
-
- @Override
- public DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper) {
- return delegate.flatMapToDouble(mapper);
- }
-
- @Override
- public Stream<T> distinct() {
- return delegate.distinct();
- }
-
- @Override
- public Stream<T> sorted() {
- return delegate.sorted();
- }
-
- @Override
- public Stream<T> sorted(Comparator<? super T> comparator) {
- return delegate.sorted(comparator);
- }
-
- @Override
- public void forEach(Consumer<? super T> action) {
- delegate.forEach(action);
- }
-
- @Override
- public void forEachOrdered(Consumer<? super T> action) {
- delegate.forEachOrdered(action);
- }
-
- @Override
- public Stream<T> peek(Consumer<? super T> consumer) {
- return delegate.peek(consumer);
- }
-
- @Override
- public Stream<T> limit(long maxSize) {
- return delegate.limit(maxSize);
- }
-
- @Override
- public Stream<T> substream(long startingOffset) {
- return delegate.substream(startingOffset);
- }
-
- @Override
- public Stream<T> substream(long startingOffset, long endingOffset) {
- return delegate.substream(startingOffset, endingOffset);
- }
-
- @Override
- public <A> A[] toArray(IntFunction<A[]> generator) {
- return delegate.toArray(generator);
- }
-
- @Override
- public Object[] toArray() {
- return delegate.toArray();
- }
-
- @Override
- public T reduce(T identity, BinaryOperator<T> accumulator) {
- return delegate.reduce(identity, accumulator);
- }
-
- @Override
- public Optional<T> reduce(BinaryOperator<T> accumulator) {
- return delegate.reduce(accumulator);
- }
-
- @Override
- public <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator,
- BinaryOperator<U> combiner) {
- return delegate.reduce(identity, accumulator, combiner);
- }
-
- @Override
- public <R> R collect(Supplier<R> resultFactory,
- BiConsumer<R, ? super T> accumulator,
- BiConsumer<R, R> combiner) {
- return delegate.collect(resultFactory, accumulator, combiner);
- }
-
- @Override
- public <R, A> R collect(Collector<? super T, A, ? extends R> collector) {
- return delegate.collect(collector);
- }
-
- @Override
- public Optional<T> max(Comparator<? super T> comparator) {
- return delegate.max(comparator);
- }
-
- @Override
- public Optional<T> min(Comparator<? super T> comparator) {
- return delegate.min(comparator);
- }
-
- @Override
- public long count() {
- return delegate.count();
- }
-
- @Override
- public boolean anyMatch(Predicate<? super T> predicate) {
- return delegate.anyMatch(predicate);
- }
-
- @Override
- public boolean allMatch(Predicate<? super T> predicate) {
- return delegate.allMatch(predicate);
- }
-
- @Override
- public boolean noneMatch(Predicate<? super T> predicate) {
- return delegate.noneMatch(predicate);
- }
-
- @Override
- public Optional<T> findFirst() {
- return delegate.findFirst();
- }
-
- @Override
- public Optional<T> findAny() {
- return delegate.findAny();
- }
-
- @Override
- public Stream<T> unordered() {
- return delegate.unordered();
- }
-
- @Override
- public Stream<T> sequential() {
- return delegate.sequential();
- }
-
- @Override
- public Stream<T> parallel() {
- return delegate.parallel();
- }
-}
--- a/jdk/src/share/classes/java/util/stream/DoublePipeline.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/DoublePipeline.java Sat Sep 14 20:43:34 2013 +0100
@@ -266,10 +266,11 @@
@Override
public void accept(double t) {
- // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
- DoubleStream result = mapper.apply(t);
- if (result != null)
- result.sequential().forEach(i -> downstream.accept(i));
+ try (DoubleStream result = mapper.apply(t)) {
+ // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+ if (result != null)
+ result.sequential().forEach(i -> downstream.accept(i));
+ }
}
};
}
@@ -312,8 +313,8 @@
}
@Override
- public final DoubleStream peek(DoubleConsumer consumer) {
- Objects.requireNonNull(consumer);
+ public final DoubleStream peek(DoubleConsumer action) {
+ Objects.requireNonNull(action);
return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
0) {
@Override
@@ -321,7 +322,7 @@
return new Sink.ChainedDouble<Double>(sink) {
@Override
public void accept(double t) {
- consumer.accept(t);
+ action.accept(t);
downstream.accept(t);
}
};
@@ -435,14 +436,14 @@
}
@Override
- public final <R> R collect(Supplier<R> resultFactory,
+ public final <R> R collect(Supplier<R> supplier,
ObjDoubleConsumer<R> accumulator,
BiConsumer<R, R> combiner) {
BinaryOperator<R> operator = (left, right) -> {
combiner.accept(left, right);
return left;
};
- return evaluate(ReduceOps.makeDouble(resultFactory, accumulator, operator));
+ return evaluate(ReduceOps.makeDouble(supplier, accumulator, operator));
}
@Override
--- a/jdk/src/share/classes/java/util/stream/DoubleStream.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/DoubleStream.java Sat Sep 14 20:43:34 2013 +0100
@@ -24,13 +24,18 @@
*/
package java.util.stream;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Arrays;
+import java.util.Collection;
import java.util.DoubleSummaryStatistics;
import java.util.Objects;
import java.util.OptionalDouble;
import java.util.PrimitiveIterator;
import java.util.Spliterator;
import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.DoubleBinaryOperator;
import java.util.function.DoubleConsumer;
@@ -45,40 +50,87 @@
import java.util.function.Supplier;
/**
- * A sequence of primitive double elements supporting sequential and parallel
- * bulk operations. Streams support lazy intermediate operations (transforming
- * a stream to another stream) such as {@code filter} and {@code map}, and terminal
- * operations (consuming the contents of a stream to produce a result or
- * side-effect), such as {@code forEach}, {@code findFirst}, and {@code
- * iterator}. Once an operation has been performed on a stream, it
- * is considered <em>consumed</em> and no longer usable for other operations.
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations. The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link DoubleStream}:
+ *
+ * <pre>{@code
+ * double sum = widgets.stream()
+ * .filter(w -> w.getColor() == RED)
+ * .mapToDouble(w -> w.getWeight())
+ * .sum();
+ * }</pre>
+ *
+ * In this example, {@code widgets} is a {@code Collection<Widget>}. We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code double} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
*
- * <p>For sequential stream pipelines, all operations are performed in the
- * <a href="package-summary.html#Ordering">encounter order</a> of the pipeline
- * source, if the pipeline source has a defined encounter order.
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>. A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an IO channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link DoubleStream#filter(DoublePredicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link DoubleStream#sum()} or {@link DoubleStream#forEach(DoubleConsumer)}.
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
+ *
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals. Collections are primarily concerned with the efficient
+ * management of, and access to, their elements. By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
*
- * <p>For parallel stream pipelines, unless otherwise specified, intermediate
- * stream operations preserve the <a href="package-summary.html#Ordering">
- * encounter order</a> of their source, and terminal operations
- * respect the encounter order of their source, if the source
- * has an encounter order. Provided that and parameters to stream operations
- * satisfy the <a href="package-summary.html#NonInterference">non-interference
- * requirements</a>, and excepting differences arising from the absence of
- * a defined encounter order, the result of a stream pipeline should be the
- * stable across multiple executions of the same operations on the same source.
- * However, the timing and thread in which side-effects occur (for those
- * operations which are allowed to produce side-effects, such as
- * {@link #forEach(DoubleConsumer)}), are explicitly nondeterministic for parallel
- * execution of stream pipelines.
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source. Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
+ *
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToDouble} in the example above. Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references. These parameters can never be null, should not modify the
+ * stream source, and should be
+ * <a href="package-summary.html#NonInterference">effectively stateless</a>
+ * (their result should not depend on any state that might change during
+ * execution of the stream pipeline.)
*
- * <p>Unless otherwise noted, passing a {@code null} argument to any stream
- * method may result in a {@link NullPointerException}.
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once. This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream. A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
*
- * @apiNote
- * Streams are not data structures; they do not manage the storage for their
- * elements, nor do they support access to individual elements. However,
- * you can use the {@link #iterator()} or {@link #spliterator()} operations to
- * perform a controlled traversal.
+ * <p>Streams have a {@link #close()} method and implement {@link AutoCloseable},
+ * but nearly all stream instances do not actually need to be closed after use.
+ * Generally, only streams whose source is an IO channel (such as those returned
+ * by {@link Files#lines(Path, Charset)}) will require closing. Most streams
+ * are backed by collections, arrays, or generating functions, which require no
+ * special resource management. (If a stream does require closing, it can be
+ * declared as a resource in a {@code try}-with-resources statement.)
+ *
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>. This
+ * execution mode is a property of the stream. Streams are created
+ * with an initial choice of sequential or parallel execution. (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.) This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
*
* @since 1.8
* @see <a href="package-summary.html">java.util.stream</a>
@@ -159,22 +211,13 @@
/**
* Returns a stream consisting of the results of replacing each element of
* this stream with the contents of the stream produced by applying the
- * provided mapping function to each element.
+ * provided mapping function to each element. (If the result of the mapping
+ * function is {@code null}, this is treated as if the result was an empty
+ * stream.)
*
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
- * @apiNote
- * The {@code flatMap()} operation has the effect of applying a one-to-many
- * tranformation to the elements of the stream, and then flattening the
- * resulting elements into a new stream. For example, if {@code orders}
- * is a stream of purchase orders, and each purchase order contains a
- * collection of line items, then the following produces a stream of line
- * items:
- * <pre>{@code
- * orderStream.flatMap(order -> order.getLineItems().stream())...
- * }</pre>
- *
* @param mapper a <a href="package-summary.html#NonInterference">
* non-interfering, stateless</a> function to apply to
* each element which produces an {@code DoubleStream} of new
@@ -226,18 +269,18 @@
* <pre>{@code
* list.stream()
* .filter(filteringFunction)
- * .peek(e -> {System.out.println("Filtered value: " + e); });
+ * .peek(e -> System.out.println("Filtered value: " + e));
* .map(mappingFunction)
- * .peek(e -> {System.out.println("Mapped value: " + e); });
+ * .peek(e -> System.out.println("Mapped value: " + e));
* .collect(Collectors.toDoubleSummaryStastistics());
* }</pre>
*
- * @param consumer a <a href="package-summary.html#NonInterference">
+ * @param action a <a href="package-summary.html#NonInterference">
* non-interfering</a> action to perform on the elements as
* they are consumed from the stream
* @return the new stream
*/
- DoubleStream peek(DoubleConsumer consumer);
+ DoubleStream peek(DoubleConsumer action);
/**
* Returns a stream consisting of the elements of this stream, truncated
@@ -254,8 +297,8 @@
/**
* Returns a stream consisting of the remaining elements of this stream
- * after indexing {@code startInclusive} elements into the stream. If the
- * {@code startInclusive} index lies past the end of this stream then an
+ * after discarding the first {@code startInclusive} elements of the stream.
+ * If this stream contains fewer than {@code startInclusive} elements then an
* empty stream will be returned.
*
* <p>This is a <a href="package-summary.html#StreamOps">stateful
@@ -269,10 +312,10 @@
/**
* Returns a stream consisting of the remaining elements of this stream
- * after indexing {@code startInclusive} elements into the stream and
- * truncated to contain no more than {@code endExclusive - startInclusive}
- * elements. If the {@code startInclusive} index lies past the end
- * of this stream then an empty stream will be returned.
+ * after discarding the first {@code startInclusive} elements and truncating
+ * the result to be no longer than {@code endExclusive - startInclusive}
+ * elements in length. If this stream contains fewer than
+ * {@code startInclusive} elements then an empty stream will be returned.
*
* <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
* stateful intermediate operation</a>.
@@ -421,12 +464,12 @@
/**
* Performs a <a href="package-summary.html#MutableReduction">mutable
* reduction</a> operation on the elements of this stream. A mutable
- * reduction is one in which the reduced value is a mutable value holder,
+ * reduction is one in which the reduced value is a mutable result container,
* such as an {@code ArrayList}, and elements are incorporated by updating
- * the state of the result, rather than by replacing the result. This
+ * the state of the result rather than by replacing the result. This
* produces a result equivalent to:
* <pre>{@code
- * R result = resultFactory.get();
+ * R result = supplier.get();
* for (double element : this stream)
* accumulator.accept(result, element);
* return result;
@@ -440,10 +483,9 @@
* operation</a>.
*
* @param <R> type of the result
- * @param resultFactory a function that creates a new result container.
- * For a parallel execution, this function may be
- * called multiple times and must return a fresh value
- * each time.
+ * @param supplier a function that creates a new result container. For a
+ * parallel execution, this function may be called
+ * multiple times and must return a fresh value each time.
* @param accumulator an <a href="package-summary.html#Associativity">associative</a>
* <a href="package-summary.html#NonInterference">non-interfering,
* stateless</a> function for incorporating an additional
@@ -455,7 +497,7 @@
* @return the result of the reduction
* @see Stream#collect(Supplier, BiConsumer, BiConsumer)
*/
- <R> R collect(Supplier<R> resultFactory,
+ <R> R collect(Supplier<R> supplier,
ObjDoubleConsumer<R> accumulator,
BiConsumer<R, R> combiner);
@@ -467,12 +509,15 @@
* yield more accurate results. If any stream element is a {@code NaN} or
* the sum is at any point a {@code NaN} then the sum will be {@code NaN}.
* This is a special case of a
- * <a href="package-summary.html#MutableReduction">reduction</a> and is
+ * <a href="package-summary.html#Reduction">reduction</a> and is
* equivalent to:
* <pre>{@code
* return reduce(0, Double::sum);
* }</pre>
*
+ * <p>This is a <a href="package-summary.html#StreamOps">terminal
+ * operation</a>.
+ *
* @return the sum of elements in this stream
*/
double sum();
@@ -483,12 +528,15 @@
* element will be {@code Double.NaN} if any stream element was NaN. Unlike
* the numerical comparison operators, this method considers negative zero
* to be strictly smaller than positive zero. This is a special case of a
- * <a href="package-summary.html#MutableReduction">reduction</a> and is
+ * <a href="package-summary.html#Reduction">reduction</a> and is
* equivalent to:
* <pre>{@code
* return reduce(Double::min);
* }</pre>
*
+ * <p>This is a <a href="package-summary.html#StreamOps">terminal
+ * operation</a>.
+ *
* @return an {@code OptionalDouble} containing the minimum element of this
* stream, or an empty optional if the stream is empty
*/
@@ -501,12 +549,15 @@
* the numerical comparison operators, this method considers negative zero
* to be strictly smaller than positive zero. This is a
* special case of a
- * <a href="package-summary.html#MutableReduction">reduction</a> and is
+ * <a href="package-summary.html#Reduction">reduction</a> and is
* equivalent to:
* <pre>{@code
* return reduce(Double::max);
* }</pre>
*
+ * <p>This is a <a href="package-summary.html#StreamOps">terminal
+ * operation</a>.
+ *
* @return an {@code OptionalDouble} containing the maximum element of this
* stream, or an empty optional if the stream is empty
*/
@@ -514,7 +565,7 @@
/**
* Returns the count of elements in this stream. This is a special case of
- * a <a href="package-summary.html#MutableReduction">reduction</a> and is
+ * a <a href="package-summary.html#Reduction">reduction</a> and is
* equivalent to:
* <pre>{@code
* return mapToLong(e -> 1L).sum();
@@ -535,7 +586,10 @@
* magnitude tend to yield more accurate results. If any recorded value is
* a {@code NaN} or the sum is at any point a {@code NaN} then the average
* will be {@code NaN}. This is a special case of a
- * <a href="package-summary.html#MutableReduction">reduction</a>.
+ * <a href="package-summary.html#Reduction">reduction</a>.
+ *
+ * <p>This is a <a href="package-summary.html#StreamOps">terminal
+ * operation</a>.
*
* @return an {@code OptionalDouble} containing the average element of this
* stream, or an empty optional if the stream is empty
@@ -545,7 +599,10 @@
/**
* Returns a {@code DoubleSummaryStatistics} describing various summary data
* about the elements of this stream. This is a special
- * case of a <a href="package-summary.html#MutableReduction">reduction</a>.
+ * case of a <a href="package-summary.html#Reduction">reduction</a>.
+ *
+ * <p>This is a <a href="package-summary.html#StreamOps">terminal
+ * operation</a>.
*
* @return a {@code DoubleSummaryStatistics} describing various summary data
* about the elements of this stream
@@ -602,9 +659,8 @@
/**
* Returns an {@link OptionalDouble} describing the first element of this
- * stream (in the encounter order), or an empty {@code OptionalDouble} if
- * the stream is empty. If the stream has no encounter order, then any
- * element may be returned.
+ * stream, or an empty {@code OptionalDouble} if the stream is empty. If
+ * the stream has no encounter order, then any element may be returned.
*
* <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
* terminal operation</a>.
@@ -624,8 +680,8 @@
* <p>The behavior of this operation is explicitly nondeterministic; it is
* free to select any element in the stream. This is to allow for maximal
* performance in parallel operations; the cost is that multiple invocations
- * on the same source may not return the same result. (If the first element
- * in the encounter order is desired, use {@link #findFirst()} instead.)
+ * on the same source may not return the same result. (If a stable result
+ * is desired, use {@link #findFirst()} instead.)
*
* @return an {@code OptionalDouble} describing some element of this stream,
* or an empty {@code OptionalDouble} if the stream is empty
@@ -637,6 +693,9 @@
* Returns a {@code Stream} consisting of the elements of this stream,
* boxed to {@code Double}.
*
+ * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+ * operation</a>.
+ *
* @return a {@code Stream} consistent of the elements of this stream,
* each boxed to a {@code Double}
*/
@@ -686,7 +745,7 @@
}
/**
- * Returns a sequential stream whose elements are the specified values.
+ * Returns a sequential ordered stream whose elements are the specified values.
*
* @param values the elements of the new stream
* @return the new stream
@@ -696,7 +755,7 @@
}
/**
- * Returns an infinite sequential {@code DoubleStream} produced by iterative
+ * Returns an infinite sequential ordered {@code DoubleStream} produced by iterative
* application of a function {@code f} to an initial element {@code seed},
* producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
* {@code f(f(seed))}, etc.
@@ -734,8 +793,8 @@
}
/**
- * Returns a sequential {@code DoubleStream} where each element is
- * generated by an {@code DoubleSupplier}. This is suitable for generating
+ * Returns a sequential stream where each element is generated by
+ * the provided {@code DoubleSupplier}. This is suitable for generating
* constant streams, streams of random elements, etc.
*
* @param s the {@code DoubleSupplier} for generated elements
@@ -748,15 +807,16 @@
}
/**
- * Creates a lazy concatenated {@code DoubleStream} whose elements are all the
- * elements of a first {@code DoubleStream} succeeded by all the elements of the
- * second {@code DoubleStream}. The resulting stream is ordered if both
+ * Creates a lazily concatenated stream whose elements are all the
+ * elements of the first stream followed by all the elements of the
+ * second stream. The resulting stream is ordered if both
* of the input streams are ordered, and parallel if either of the input
- * streams is parallel.
+ * streams is parallel. When the resulting stream is closed, the close
+ * handlers for both input streams are invoked.
*
* @param a the first stream
- * @param b the second stream to concatenate on to end of the first stream
- * @return the concatenation of the two streams
+ * @param b the second stream
+ * @return the concatenation of the two input streams
*/
public static DoubleStream concat(DoubleStream a, DoubleStream b) {
Objects.requireNonNull(a);
@@ -764,15 +824,16 @@
Spliterator.OfDouble split = new Streams.ConcatSpliterator.OfDouble(
a.spliterator(), b.spliterator());
- return StreamSupport.doubleStream(split, a.isParallel() || b.isParallel());
+ DoubleStream stream = StreamSupport.doubleStream(split, a.isParallel() || b.isParallel());
+ return stream.onClose(Streams.composedClose(a, b));
}
/**
* A mutable builder for a {@code DoubleStream}.
*
- * <p>A stream builder has a lifecycle, where it starts in a building
- * phase, during which elements can be added, and then transitions to a
- * built phase, after which elements may not be added. The built phase
+ * <p>A stream builder has a lifecycle, which starts in a building
+ * phase, during which elements can be added, and then transitions to a built
+ * phase, after which elements may not be added. The built phase
* begins when the {@link #build()} method is called, which creates an
* ordered stream whose elements are the elements that were added to the
* stream builder, in the order they were added.
--- a/jdk/src/share/classes/java/util/stream/IntPipeline.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/IntPipeline.java Sat Sep 14 20:43:34 2013 +0100
@@ -302,10 +302,11 @@
@Override
public void accept(int t) {
- // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
- IntStream result = mapper.apply(t);
- if (result != null)
- result.sequential().forEach(i -> downstream.accept(i));
+ try (IntStream result = mapper.apply(t)) {
+ // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+ if (result != null)
+ result.sequential().forEach(i -> downstream.accept(i));
+ }
}
};
}
@@ -348,8 +349,8 @@
}
@Override
- public final IntStream peek(IntConsumer consumer) {
- Objects.requireNonNull(consumer);
+ public final IntStream peek(IntConsumer action) {
+ Objects.requireNonNull(action);
return new StatelessOp<Integer>(this, StreamShape.INT_VALUE,
0) {
@Override
@@ -357,7 +358,7 @@
return new Sink.ChainedInt<Integer>(sink) {
@Override
public void accept(int t) {
- consumer.accept(t);
+ action.accept(t);
downstream.accept(t);
}
};
@@ -472,14 +473,14 @@
}
@Override
- public final <R> R collect(Supplier<R> resultFactory,
+ public final <R> R collect(Supplier<R> supplier,
ObjIntConsumer<R> accumulator,
BiConsumer<R, R> combiner) {
BinaryOperator<R> operator = (left, right) -> {
combiner.accept(left, right);
return left;
};
- return evaluate(ReduceOps.makeInt(resultFactory, accumulator, operator));
+ return evaluate(ReduceOps.makeInt(supplier, accumulator, operator));
}
@Override
--- a/jdk/src/share/classes/java/util/stream/IntStream.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/IntStream.java Sat Sep 14 20:43:34 2013 +0100
@@ -24,7 +24,11 @@
*/
package java.util.stream;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Arrays;
+import java.util.Collection;
import java.util.IntSummaryStatistics;
import java.util.Objects;
import java.util.OptionalDouble;
@@ -32,6 +36,7 @@
import java.util.PrimitiveIterator;
import java.util.Spliterator;
import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.IntBinaryOperator;
@@ -46,40 +51,87 @@
import java.util.function.Supplier;
/**
- * A sequence of primitive integer elements supporting sequential and parallel
- * bulk operations. Streams support lazy intermediate operations (transforming
- * a stream to another stream) such as {@code filter} and {@code map}, and terminal
- * operations (consuming the contents of a stream to produce a result or
- * side-effect), such as {@code forEach}, {@code findFirst}, and {@code
- * iterator}. Once an operation has been performed on a stream, it
- * is considered <em>consumed</em> and no longer usable for other operations.
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations. The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link IntStream}:
+ *
+ * <pre>{@code
+ * int sum = widgets.stream()
+ * .filter(w -> w.getColor() == RED)
+ * .mapToInt(w -> w.getWeight())
+ * .sum();
+ * }</pre>
+ *
+ * In this example, {@code widgets} is a {@code Collection<Widget>}. We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code int} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
*
- * <p>For sequential stream pipelines, all operations are performed in the
- * <a href="package-summary.html#Ordering">encounter order</a> of the pipeline
- * source, if the pipeline source has a defined encounter order.
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>. A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an IO channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link IntStream#filter(IntPredicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link IntStream#sum()} or {@link IntStream#forEach(IntConsumer)}).
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
+ *
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals. Collections are primarily concerned with the efficient
+ * management of, and access to, their elements. By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
*
- * <p>For parallel stream pipelines, unless otherwise specified, intermediate
- * stream operations preserve the <a href="package-summary.html#Ordering">
- * encounter order</a> of their source, and terminal operations
- * respect the encounter order of their source, if the source
- * has an encounter order. Provided that and parameters to stream operations
- * satisfy the <a href="package-summary.html#NonInterference">non-interference
- * requirements</a>, and excepting differences arising from the absence of
- * a defined encounter order, the result of a stream pipeline should be the
- * stable across multiple executions of the same operations on the same source.
- * However, the timing and thread in which side-effects occur (for those
- * operations which are allowed to produce side-effects, such as
- * {@link #forEach(IntConsumer)}), are explicitly nondeterministic for parallel
- * execution of stream pipelines.
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source. Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
+ *
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToInt} in the example above. Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references. These parameters can never be null, should not modify the
+ * stream source, and should be
+ * <a href="package-summary.html#NonInterference">effectively stateless</a>
+ * (their result should not depend on any state that might change during
+ * execution of the stream pipeline.)
*
- * <p>Unless otherwise noted, passing a {@code null} argument to any stream
- * method may result in a {@link NullPointerException}.
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once. This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream. A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
*
- * @apiNote
- * Streams are not data structures; they do not manage the storage for their
- * elements, nor do they support access to individual elements. However,
- * you can use the {@link #iterator()} or {@link #spliterator()} operations to
- * perform a controlled traversal.
+ * <p>Streams have a {@link #close()} method and implement {@link AutoCloseable},
+ * but nearly all stream instances do not actually need to be closed after use.
+ * Generally, only streams whose source is an IO channel (such as those returned
+ * by {@link Files#lines(Path, Charset)}) will require closing. Most streams
+ * are backed by collections, arrays, or generating functions, which require no
+ * special resource management. (If a stream does require closing, it can be
+ * declared as a resource in a {@code try}-with-resources statement.)
+ *
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>. This
+ * execution mode is a property of the stream. Streams are created
+ * with an initial choice of sequential or parallel execution. (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.) This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
*
* @since 1.8
* @see <a href="package-summary.html">java.util.stream</a>
@@ -160,22 +212,13 @@
/**
* Returns a stream consisting of the results of replacing each element of
* this stream with the contents of the stream produced by applying the
- * provided mapping function to each element.
+ * provided mapping function to each element. (If the result of the mapping
+ * function is {@code null}, this is treated as if the result was an empty
+ * stream.)
*
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
- * @apiNote
- * The {@code flatMap()} operation has the effect of applying a one-to-many
- * tranformation to the elements of the stream, and then flattening the
- * resulting elements into a new stream. For example, if {@code orders}
- * is a stream of purchase orders, and each purchase order contains a
- * collection of line items, then the following produces a stream of line
- * items:
- * <pre>{@code
- * orderStream.flatMap(order -> order.getLineItems().stream())...
- * }</pre>
- *
* @param mapper a <a href="package-summary.html#NonInterference">
* non-interfering, stateless</a> function to apply to
* each element which produces an {@code IntStream} of new
@@ -224,18 +267,18 @@
* <pre>{@code
* list.stream()
* .filter(filteringFunction)
- * .peek(e -> {System.out.println("Filtered value: " + e); });
+ * .peek(e -> System.out.println("Filtered value: " + e));
* .map(mappingFunction)
- * .peek(e -> {System.out.println("Mapped value: " + e); });
+ * .peek(e -> System.out.println("Mapped value: " + e));
* .collect(Collectors.toIntSummaryStastistics());
* }</pre>
*
- * @param consumer a <a href="package-summary.html#NonInterference">
- * non-interfering</a> action to perform on the elements as
- * they are consumed from the stream
+ * @param action a <a href="package-summary.html#NonInterference">
+ * non-interfering</a> action to perform on the elements as
+ * they are consumed from the stream
* @return the new stream
*/
- IntStream peek(IntConsumer consumer);
+ IntStream peek(IntConsumer action);
/**
* Returns a stream consisting of the elements of this stream, truncated
@@ -252,8 +295,8 @@
/**
* Returns a stream consisting of the remaining elements of this stream
- * after indexing {@code startInclusive} elements into the stream. If the
- * {@code startInclusive} index lies past the end of this stream then an
+ * after discarding the first {@code startInclusive} elements of the stream.
+ * If this stream contains fewer than {@code startInclusive} elements then an
* empty stream will be returned.
*
* <p>This is a <a href="package-summary.html#StreamOps">stateful
@@ -267,10 +310,10 @@
/**
* Returns a stream consisting of the remaining elements of this stream
- * after indexing {@code startInclusive} elements into the stream and
- * truncated to contain no more than {@code endExclusive - startInclusive}
- * elements. If the {@code startInclusive} index lies past the end
- * of this stream then an empty stream will be returned.
+ * after discarding the first {@code startInclusive} elements and truncating
+ * the result to be no longer than {@code endExclusive - startInclusive}
+ * elements in length. If this stream contains fewer than
+ * {@code startInclusive} elements then an empty stream will be returned.
*
* <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
* stateful intermediate operation</a>.
@@ -419,12 +462,12 @@
/**
* Performs a <a href="package-summary.html#MutableReduction">mutable
* reduction</a> operation on the elements of this stream. A mutable
- * reduction is one in which the reduced value is a mutable value holder,
+ * reduction is one in which the reduced value is a mutable result container,
* such as an {@code ArrayList}, and elements are incorporated by updating
- * the state of the result, rather than by replacing the result. This
+ * the state of the result rather than by replacing the result. This
* produces a result equivalent to:
* <pre>{@code
- * R result = resultFactory.get();
+ * R result = supplier.get();
* for (int element : this stream)
* accumulator.accept(result, element);
* return result;
@@ -437,10 +480,9 @@
* operation</a>.
*
* @param <R> type of the result
- * @param resultFactory a function that creates a new result container.
- * For a parallel execution, this function may be
- * called multiple times and must return a fresh value
- * each time.
+ * @param supplier a function that creates a new result container. For a
+ * parallel execution, this function may be called
+ * multiple times and must return a fresh value each time.
* @param accumulator an <a href="package-summary.html#Associativity">associative</a>
* <a href="package-summary.html#NonInterference">non-interfering,
* stateless</a> function for incorporating an additional
@@ -452,18 +494,21 @@
* @return the result of the reduction
* @see Stream#collect(Supplier, BiConsumer, BiConsumer)
*/
- <R> R collect(Supplier<R> resultFactory,
+ <R> R collect(Supplier<R> supplier,
ObjIntConsumer<R> accumulator,
BiConsumer<R, R> combiner);
/**
* Returns the sum of elements in this stream. This is a special case
- * of a <a href="package-summary.html#MutableReduction">reduction</a>
+ * of a <a href="package-summary.html#Reduction">reduction</a>
* and is equivalent to:
* <pre>{@code
* return reduce(0, Integer::sum);
* }</pre>
*
+ * <p>This is a <a href="package-summary.html#StreamOps">terminal
+ * operation</a>.
+ *
* @return the sum of elements in this stream
*/
int sum();
@@ -471,7 +516,7 @@
/**
* Returns an {@code OptionalInt} describing the minimum element of this
* stream, or an empty optional if this stream is empty. This is a special
- * case of a <a href="package-summary.html#MutableReduction">reduction</a>
+ * case of a <a href="package-summary.html#Reduction">reduction</a>
* and is equivalent to:
* <pre>{@code
* return reduce(Integer::min);
@@ -479,7 +524,6 @@
*
* <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
*
-
* @return an {@code OptionalInt} containing the minimum element of this
* stream, or an empty {@code OptionalInt} if the stream is empty
*/
@@ -488,7 +532,7 @@
/**
* Returns an {@code OptionalInt} describing the maximum element of this
* stream, or an empty optional if this stream is empty. This is a special
- * case of a <a href="package-summary.html#MutableReduction">reduction</a>
+ * case of a <a href="package-summary.html#Reduction">reduction</a>
* and is equivalent to:
* <pre>{@code
* return reduce(Integer::max);
@@ -504,7 +548,7 @@
/**
* Returns the count of elements in this stream. This is a special case of
- * a <a href="package-summary.html#MutableReduction">reduction</a> and is
+ * a <a href="package-summary.html#Reduction">reduction</a> and is
* equivalent to:
* <pre>{@code
* return mapToLong(e -> 1L).sum();
@@ -520,7 +564,10 @@
* Returns an {@code OptionalDouble} describing the arithmetic mean of elements of
* this stream, or an empty optional if this stream is empty. This is a
* special case of a
- * <a href="package-summary.html#MutableReduction">reduction</a>.
+ * <a href="package-summary.html#Reduction">reduction</a>.
+ *
+ * <p>This is a <a href="package-summary.html#StreamOps">terminal
+ * operation</a>.
*
* @return an {@code OptionalDouble} containing the average element of this
* stream, or an empty optional if the stream is empty
@@ -530,7 +577,10 @@
/**
* Returns an {@code IntSummaryStatistics} describing various
* summary data about the elements of this stream. This is a special
- * case of a <a href="package-summary.html#MutableReduction">reduction</a>.
+ * case of a <a href="package-summary.html#Reduction">reduction</a>.
+ *
+ * <p>This is a <a href="package-summary.html#StreamOps">terminal
+ * operation</a>.
*
* @return an {@code IntSummaryStatistics} describing various summary data
* about the elements of this stream
@@ -587,9 +637,8 @@
/**
* Returns an {@link OptionalInt} describing the first element of this
- * stream (in the encounter order), or an empty {@code OptionalInt} if the
- * stream is empty. If the stream has no encounter order, then any element
- * may be returned.
+ * stream, or an empty {@code OptionalInt} if the stream is empty. If the
+ * stream has no encounter order, then any element may be returned.
*
* <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
* terminal operation</a>.
@@ -609,8 +658,8 @@
* <p>The behavior of this operation is explicitly nondeterministic; it is
* free to select any element in the stream. This is to allow for maximal
* performance in parallel operations; the cost is that multiple invocations
- * on the same source may not return the same result. (If the first element
- * in the encounter order is desired, use {@link #findFirst()} instead.)
+ * on the same source may not return the same result. (If a stable result
+ * is desired, use {@link #findFirst()} instead.)
*
* @return an {@code OptionalInt} describing some element of this stream, or
* an empty {@code OptionalInt} if the stream is empty
@@ -622,6 +671,9 @@
* Returns a {@code LongStream} consisting of the elements of this stream,
* converted to {@code long}.
*
+ * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+ * operation</a>.
+ *
* @return a {@code LongStream} consisting of the elements of this stream,
* converted to {@code long}
*/
@@ -631,6 +683,9 @@
* Returns a {@code DoubleStream} consisting of the elements of this stream,
* converted to {@code double}.
*
+ * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+ * operation</a>.
+ *
* @return a {@code DoubleStream} consisting of the elements of this stream,
* converted to {@code double}
*/
@@ -640,6 +695,9 @@
* Returns a {@code Stream} consisting of the elements of this stream,
* each boxed to an {@code Integer}.
*
+ * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+ * operation</a>.
+ *
* @return a {@code Stream} consistent of the elements of this stream,
* each boxed to an {@code Integer}
*/
@@ -688,7 +746,7 @@
}
/**
- * Returns a sequential stream whose elements are the specified values.
+ * Returns a sequential ordered stream whose elements are the specified values.
*
* @param values the elements of the new stream
* @return the new stream
@@ -698,7 +756,7 @@
}
/**
- * Returns an infinite sequential {@code IntStream} produced by iterative
+ * Returns an infinite sequential ordered {@code IntStream} produced by iterative
* application of a function {@code f} to an initial element {@code seed},
* producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
* {@code f(f(seed))}, etc.
@@ -736,8 +794,8 @@
}
/**
- * Returns a sequential {@code IntStream} where each element is
- * generated by an {@code IntSupplier}. This is suitable for generating
+ * Returns a sequential stream where each element is generated by
+ * the provided {@code IntSupplier}. This is suitable for generating
* constant streams, streams of random elements, etc.
*
* @param s the {@code IntSupplier} for generated elements
@@ -750,7 +808,7 @@
}
/**
- * Returns a sequential {@code IntStream} from {@code startInclusive}
+ * Returns a sequential ordered {@code IntStream} from {@code startInclusive}
* (inclusive) to {@code endExclusive} (exclusive) by an incremental step of
* {@code 1}.
*
@@ -776,7 +834,7 @@
}
/**
- * Returns a sequential {@code IntStream} from {@code startInclusive}
+ * Returns a sequential ordered {@code IntStream} from {@code startInclusive}
* (inclusive) to {@code endInclusive} (inclusive) by an incremental step of
* {@code 1}.
*
@@ -802,15 +860,16 @@
}
/**
- * Creates a lazy concatenated {@code IntStream} whose elements are all the
- * elements of a first {@code IntStream} succeeded by all the elements of the
- * second {@code IntStream}. The resulting stream is ordered if both
+ * Creates a lazily concatenated stream whose elements are all the
+ * elements of the first stream followed by all the elements of the
+ * second stream. The resulting stream is ordered if both
* of the input streams are ordered, and parallel if either of the input
- * streams is parallel.
+ * streams is parallel. When the resulting stream is closed, the close
+ * handlers for both input streams are invoked.
*
* @param a the first stream
- * @param b the second stream to concatenate on to end of the first stream
- * @return the concatenation of the two streams
+ * @param b the second stream
+ * @return the concatenation of the two input streams
*/
public static IntStream concat(IntStream a, IntStream b) {
Objects.requireNonNull(a);
@@ -818,15 +877,16 @@
Spliterator.OfInt split = new Streams.ConcatSpliterator.OfInt(
a.spliterator(), b.spliterator());
- return StreamSupport.intStream(split, a.isParallel() || b.isParallel());
+ IntStream stream = StreamSupport.intStream(split, a.isParallel() || b.isParallel());
+ return stream.onClose(Streams.composedClose(a, b));
}
/**
* A mutable builder for an {@code IntStream}.
*
- * <p>A stream builder has a lifecycle, where it starts in a building
- * phase, during which elements can be added, and then transitions to a
- * built phase, after which elements may not be added. The built phase
+ * <p>A stream builder has a lifecycle, which starts in a building
+ * phase, during which elements can be added, and then transitions to a built
+ * phase, after which elements may not be added. The built phase
* begins when the {@link #build()} method is called, which creates an
* ordered stream whose elements are the elements that were added to the
* stream builder, in the order they were added.
--- a/jdk/src/share/classes/java/util/stream/LongPipeline.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/LongPipeline.java Sat Sep 14 20:43:34 2013 +0100
@@ -283,10 +283,11 @@
@Override
public void accept(long t) {
- // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
- LongStream result = mapper.apply(t);
- if (result != null)
- result.sequential().forEach(i -> downstream.accept(i));
+ try (LongStream result = mapper.apply(t)) {
+ // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+ if (result != null)
+ result.sequential().forEach(i -> downstream.accept(i));
+ }
}
};
}
@@ -329,8 +330,8 @@
}
@Override
- public final LongStream peek(LongConsumer consumer) {
- Objects.requireNonNull(consumer);
+ public final LongStream peek(LongConsumer action) {
+ Objects.requireNonNull(action);
return new StatelessOp<Long>(this, StreamShape.LONG_VALUE,
0) {
@Override
@@ -338,7 +339,7 @@
return new Sink.ChainedLong<Long>(sink) {
@Override
public void accept(long t) {
- consumer.accept(t);
+ action.accept(t);
downstream.accept(t);
}
};
@@ -454,14 +455,14 @@
}
@Override
- public final <R> R collect(Supplier<R> resultFactory,
+ public final <R> R collect(Supplier<R> supplier,
ObjLongConsumer<R> accumulator,
BiConsumer<R, R> combiner) {
BinaryOperator<R> operator = (left, right) -> {
combiner.accept(left, right);
return left;
};
- return evaluate(ReduceOps.makeLong(resultFactory, accumulator, operator));
+ return evaluate(ReduceOps.makeLong(supplier, accumulator, operator));
}
@Override
--- a/jdk/src/share/classes/java/util/stream/LongStream.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/LongStream.java Sat Sep 14 20:43:34 2013 +0100
@@ -24,7 +24,11 @@
*/
package java.util.stream;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Arrays;
+import java.util.Collection;
import java.util.LongSummaryStatistics;
import java.util.Objects;
import java.util.OptionalDouble;
@@ -32,6 +36,7 @@
import java.util.PrimitiveIterator;
import java.util.Spliterator;
import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.LongBinaryOperator;
@@ -46,40 +51,87 @@
import java.util.function.Supplier;
/**
- * A sequence of primitive long elements supporting sequential and parallel
- * bulk operations. Streams support lazy intermediate operations (transforming
- * a stream to another stream) such as {@code filter} and {@code map}, and terminal
- * operations (consuming the contents of a stream to produce a result or
- * side-effect), such as {@code forEach}, {@code findFirst}, and {@code
- * iterator}. Once an operation has been performed on a stream, it
- * is considered <em>consumed</em> and no longer usable for other operations.
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations. The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link LongStream}:
+ *
+ * <pre>{@code
+ * long sum = widgets.stream()
+ * .filter(w -> w.getColor() == RED)
+ * .mapToLong(w -> w.getWeight())
+ * .sum();
+ * }</pre>
+ *
+ * In this example, {@code widgets} is a {@code Collection<Widget>}. We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code long} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
*
- * <p>For sequential stream pipelines, all operations are performed in the
- * <a href="package-summary.html#Ordering">encounter order</a> of the pipeline
- * source, if the pipeline source has a defined encounter order.
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>. A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an IO channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link LongStream#filter(LongPredicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link LongStream#sum()} or {@link LongStream#forEach(LongConsumer)}).
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
+ *
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals. Collections are primarily concerned with the efficient
+ * management of, and access to, their elements. By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
*
- * <p>For parallel stream pipelines, unless otherwise specified, intermediate
- * stream operations preserve the <a href="package-summary.html#Ordering">
- * encounter order</a> of their source, and terminal operations
- * respect the encounter order of their source, if the source
- * has an encounter order. Provided that and parameters to stream operations
- * satisfy the <a href="package-summary.html#NonInterference">non-interference
- * requirements</a>, and excepting differences arising from the absence of
- * a defined encounter order, the result of a stream pipeline should be the
- * stable across multiple executions of the same operations on the same source.
- * However, the timing and thread in which side-effects occur (for those
- * operations which are allowed to produce side-effects, such as
- * {@link #forEach(LongConsumer)}), are explicitly nondeterministic for parallel
- * execution of stream pipelines.
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source. Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
+ *
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToLong} in the example above. Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references. These parameters can never be null, should not modify the
+ * stream source, and should be
+ * <a href="package-summary.html#NonInterference">effectively stateless</a>
+ * (their result should not depend on any state that might change during
+ * execution of the stream pipeline.)
*
- * <p>Unless otherwise noted, passing a {@code null} argument to any stream
- * method may result in a {@link NullPointerException}.
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once. This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream. A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
*
- * @apiNote
- * Streams are not data structures; they do not manage the storage for their
- * elements, nor do they support access to individual elements. However,
- * you can use the {@link #iterator()} or {@link #spliterator()} operations to
- * perform a controlled traversal.
+ * <p>Streams have a {@link #close()} method and implement {@link AutoCloseable},
+ * but nearly all stream instances do not actually need to be closed after use.
+ * Generally, only streams whose source is an IO channel (such as those returned
+ * by {@link Files#lines(Path, Charset)}) will require closing. Most streams
+ * are backed by collections, arrays, or generating functions, which require no
+ * special resource management. (If a stream does require closing, it can be
+ * declared as a resource in a {@code try}-with-resources statement.)
+ *
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>. This
+ * execution mode is a property of the stream. Streams are created
+ * with an initial choice of sequential or parallel execution. (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.) This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
*
* @since 1.8
* @see <a href="package-summary.html">java.util.stream</a>
@@ -160,22 +212,13 @@
/**
* Returns a stream consisting of the results of replacing each element of
* this stream with the contents of the stream produced by applying the
- * provided mapping function to each element.
+ * provided mapping function to each element. (If the result of the mapping
+ * function is {@code null}, this is treated as if the result was an empty
+ * stream.)
*
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
- * @apiNote
- * The {@code flatMap()} operation has the effect of applying a one-to-many
- * tranformation to the elements of the stream, and then flattening the
- * resulting elements into a new stream. For example, if {@code orders}
- * is a stream of purchase orders, and each purchase order contains a
- * collection of line items, then the following produces a stream of line
- * items:
- * <pre>{@code
- * orderStream.flatMap(order -> order.getLineItems().stream())...
- * }</pre>
- *
* @param mapper a <a href="package-summary.html#NonInterference">
* non-interfering, stateless</a> function to apply to
* each element which produces an {@code LongStream} of new
@@ -224,18 +267,18 @@
* <pre>{@code
* list.stream()
* .filter(filteringFunction)
- * .peek(e -> {System.out.println("Filtered value: " + e); });
+ * .peek(e -> System.out.println("Filtered value: " + e));
* .map(mappingFunction)
- * .peek(e -> {System.out.println("Mapped value: " + e); });
+ * .peek(e -> System.out.println("Mapped value: " + e));
* .collect(Collectors.toLongSummaryStastistics());
* }</pre>
*
- * @param consumer a <a href="package-summary.html#NonInterference">
- * non-interfering</a> action to perform on the elements as
- * they are consumed from the stream
+ * @param action a <a href="package-summary.html#NonInterference">
+ * non-interfering</a> action to perform on the elements as
+ * they are consumed from the stream
* @return the new stream
*/
- LongStream peek(LongConsumer consumer);
+ LongStream peek(LongConsumer action);
/**
* Returns a stream consisting of the elements of this stream, truncated
@@ -252,8 +295,8 @@
/**
* Returns a stream consisting of the remaining elements of this stream
- * after indexing {@code startInclusive} elements into the stream. If the
- * {@code startInclusive} index lies past the end of this stream then an
+ * after discarding the first {@code startInclusive} elements of the stream.
+ * If this stream contains fewer than {@code startInclusive} elements then an
* empty stream will be returned.
*
* <p>This is a <a href="package-summary.html#StreamOps">stateful
@@ -267,10 +310,10 @@
/**
* Returns a stream consisting of the remaining elements of this stream
- * after indexing {@code startInclusive} elements into the stream and
- * truncated to contain no more than {@code endExclusive - startInclusive}
- * elements. If the {@code startInclusive} index lies past the end
- * of this stream then an empty stream will be returned.
+ * after discarding the first {@code startInclusive} elements and truncating
+ * the result to be no longer than {@code endExclusive - startInclusive}
+ * elements in length. If this stream contains fewer than
+ * {@code startInclusive} elements then an empty stream will be returned.
*
* <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
* stateful intermediate operation</a>.
@@ -419,12 +462,12 @@
/**
* Performs a <a href="package-summary.html#MutableReduction">mutable
* reduction</a> operation on the elements of this stream. A mutable
- * reduction is one in which the reduced value is a mutable value holder,
+ * reduction is one in which the reduced value is a mutable result container,
* such as an {@code ArrayList}, and elements are incorporated by updating
- * the state of the result, rather than by replacing the result. This
+ * the state of the result rather than by replacing the result. This
* produces a result equivalent to:
* <pre>{@code
- * R result = resultFactory.get();
+ * R result = supplier.get();
* for (long element : this stream)
* accumulator.accept(result, element);
* return result;
@@ -437,10 +480,9 @@
* operation</a>.
*
* @param <R> type of the result
- * @param resultFactory a function that creates a new result container.
- * For a parallel execution, this function may be
- * called multiple times and must return a fresh value
- * each time.
+ * @param supplier a function that creates a new result container. For a
+ * parallel execution, this function may be called
+ * multiple times and must return a fresh value each time.
* @param accumulator an <a href="package-summary.html#Associativity">associative</a>
* <a href="package-summary.html#NonInterference">non-interfering,
* stateless</a> function for incorporating an additional
@@ -452,18 +494,21 @@
* @return the result of the reduction
* @see Stream#collect(Supplier, BiConsumer, BiConsumer)
*/
- <R> R collect(Supplier<R> resultFactory,
+ <R> R collect(Supplier<R> supplier,
ObjLongConsumer<R> accumulator,
BiConsumer<R, R> combiner);
/**
* Returns the sum of elements in this stream. This is a special case
- * of a <a href="package-summary.html#MutableReduction">reduction</a>
+ * of a <a href="package-summary.html#Reduction">reduction</a>
* and is equivalent to:
* <pre>{@code
* return reduce(0, Long::sum);
* }</pre>
*
+ * <p>This is a <a href="package-summary.html#StreamOps">terminal
+ * operation</a>.
+ *
* @return the sum of elements in this stream
*/
long sum();
@@ -471,7 +516,7 @@
/**
* Returns an {@code OptionalLong} describing the minimum element of this
* stream, or an empty optional if this stream is empty. This is a special
- * case of a <a href="package-summary.html#MutableReduction">reduction</a>
+ * case of a <a href="package-summary.html#Reduction">reduction</a>
* and is equivalent to:
* <pre>{@code
* return reduce(Long::min);
@@ -479,7 +524,6 @@
*
* <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
*
-
* @return an {@code OptionalLong} containing the minimum element of this
* stream, or an empty {@code OptionalLong} if the stream is empty
*/
@@ -488,7 +532,7 @@
/**
* Returns an {@code OptionalLong} describing the maximum element of this
* stream, or an empty optional if this stream is empty. This is a special
- * case of a <a href="package-summary.html#MutableReduction">reduction</a>
+ * case of a <a href="package-summary.html#Reduction">reduction</a>
* and is equivalent to:
* <pre>{@code
* return reduce(Long::max);
@@ -504,7 +548,7 @@
/**
* Returns the count of elements in this stream. This is a special case of
- * a <a href="package-summary.html#MutableReduction">reduction</a> and is
+ * a <a href="package-summary.html#Reduction">reduction</a> and is
* equivalent to:
* <pre>{@code
* return map(e -> 1L).sum();
@@ -520,7 +564,10 @@
* Returns an {@code OptionalDouble} describing the arithmetic mean of elements of
* this stream, or an empty optional if this stream is empty. This is a
* special case of a
- * <a href="package-summary.html#MutableReduction">reduction</a>.
+ * <a href="package-summary.html#Reduction">reduction</a>.
+ *
+ * <p>This is a <a href="package-summary.html#StreamOps">terminal
+ * operation</a>.
*
* @return an {@code OptionalDouble} containing the average element of this
* stream, or an empty optional if the stream is empty
@@ -530,7 +577,10 @@
/**
* Returns a {@code LongSummaryStatistics} describing various summary data
* about the elements of this stream. This is a special case of a
- * <a href="package-summary.html#MutableReduction">reduction</a>.
+ * <a href="package-summary.html#Reduction">reduction</a>.
+ *
+ * <p>This is a <a href="package-summary.html#StreamOps">terminal
+ * operation</a>.
*
* @return a {@code LongSummaryStatistics} describing various summary data
* about the elements of this stream
@@ -587,9 +637,8 @@
/**
* Returns an {@link OptionalLong} describing the first element of this
- * stream (in the encounter order), or an empty {@code OptionalLong} if the
- * stream is empty. If the stream has no encounter order, then any element
- * may be returned.
+ * stream, or an empty {@code OptionalLong} if the stream is empty. If the
+ * stream has no encounter order, then any element may be returned.
*
* <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
* terminal operation</a>.
@@ -609,8 +658,8 @@
* <p>The behavior of this operation is explicitly nondeterministic; it is
* free to select any element in the stream. This is to allow for maximal
* performance in parallel operations; the cost is that multiple invocations
- * on the same source may not return the same result. (If the first element
- * in the encounter order is desired, use {@link #findFirst()} instead.)
+ * on the same source may not return the same result. (If a stable result
+ * is desired, use {@link #findFirst()} instead.)
*
* @return an {@code OptionalLong} describing some element of this stream,
* or an empty {@code OptionalLong} if the stream is empty
@@ -622,6 +671,9 @@
* Returns a {@code DoubleStream} consisting of the elements of this stream,
* converted to {@code double}.
*
+ * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+ * operation</a>.
+ *
* @return a {@code DoubleStream} consisting of the elements of this stream,
* converted to {@code double}
*/
@@ -631,6 +683,9 @@
* Returns a {@code Stream} consisting of the elements of this stream,
* each boxed to a {@code Long}.
*
+ * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+ * operation</a>.
+ *
* @return a {@code Stream} consistent of the elements of this stream,
* each boxed to {@code Long}
*/
@@ -679,7 +734,7 @@
}
/**
- * Returns a sequential stream whose elements are the specified values.
+ * Returns a sequential ordered stream whose elements are the specified values.
*
* @param values the elements of the new stream
* @return the new stream
@@ -689,7 +744,7 @@
}
/**
- * Returns an infinite sequential {@code LongStream} produced by iterative
+ * Returns an infinite sequential ordered {@code LongStream} produced by iterative
* application of a function {@code f} to an initial element {@code seed},
* producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
* {@code f(f(seed))}, etc.
@@ -727,9 +782,9 @@
}
/**
- * Returns a sequential {@code LongStream} where each element is generated
- * by a {@code LongSupplier}. This is suitable for generating constant
- * streams, streams of random elements, etc.
+ * Returns a sequential stream where each element is generated by
+ * the provided {@code LongSupplier}. This is suitable for generating
+ * constant streams, streams of random elements, etc.
*
* @param s the {@code LongSupplier} for generated elements
* @return a new sequential {@code LongStream}
@@ -741,7 +796,7 @@
}
/**
- * Returns a sequential {@code LongStream} from {@code startInclusive}
+ * Returns a sequential ordered {@code LongStream} from {@code startInclusive}
* (inclusive) to {@code endExclusive} (exclusive) by an incremental step of
* {@code 1}.
*
@@ -774,7 +829,7 @@
}
/**
- * Returns a sequential {@code LongStream} from {@code startInclusive}
+ * Returns a sequential ordered {@code LongStream} from {@code startInclusive}
* (inclusive) to {@code endInclusive} (inclusive) by an incremental step of
* {@code 1}.
*
@@ -808,15 +863,16 @@
}
/**
- * Creates a lazy concatenated {@code LongStream} whose elements are all the
- * elements of a first {@code LongStream} succeeded by all the elements of the
- * second {@code LongStream}. The resulting stream is ordered if both
+ * Creates a lazily concatenated stream whose elements are all the
+ * elements of the first stream followed by all the elements of the
+ * second stream. The resulting stream is ordered if both
* of the input streams are ordered, and parallel if either of the input
- * streams is parallel.
+ * streams is parallel. When the resulting stream is closed, the close
+ * handlers for both input streams are invoked.
*
* @param a the first stream
- * @param b the second stream to concatenate on to end of the first stream
- * @return the concatenation of the two streams
+ * @param b the second stream
+ * @return the concatenation of the two input streams
*/
public static LongStream concat(LongStream a, LongStream b) {
Objects.requireNonNull(a);
@@ -824,15 +880,16 @@
Spliterator.OfLong split = new Streams.ConcatSpliterator.OfLong(
a.spliterator(), b.spliterator());
- return StreamSupport.longStream(split, a.isParallel() || b.isParallel());
+ LongStream stream = StreamSupport.longStream(split, a.isParallel() || b.isParallel());
+ return stream.onClose(Streams.composedClose(a, b));
}
/**
* A mutable builder for a {@code LongStream}.
*
- * <p>A stream builder has a lifecycle, where it starts in a building
- * phase, during which elements can be added, and then transitions to a
- * built phase, after which elements may not be added. The built phase
+ * <p>A stream builder has a lifecycle, which starts in a building
+ * phase, during which elements can be added, and then transitions to a built
+ * phase, after which elements may not be added. The built phase begins
* begins when the {@link #build()} method is called, which creates an
* ordered stream whose elements are the elements that were added to the
* stream builder, in the order they were added.
--- a/jdk/src/share/classes/java/util/stream/PipelineHelper.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/PipelineHelper.java Sat Sep 14 20:43:34 2013 +0100
@@ -28,7 +28,7 @@
import java.util.function.IntFunction;
/**
- * Helper class for executing <a href="package-summary.html#StreamPipelines">
+ * Helper class for executing <a href="package-summary.html#StreamOps">
* stream pipelines</a>, capturing all of the information about a stream
* pipeline (output shape, intermediate operations, stream flags, parallelism,
* etc) in one place.
--- a/jdk/src/share/classes/java/util/stream/ReferencePipeline.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/ReferencePipeline.java Sat Sep 14 20:43:34 2013 +0100
@@ -264,10 +264,11 @@
@Override
public void accept(P_OUT u) {
- // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
- Stream<? extends R> result = mapper.apply(u);
- if (result != null)
- result.sequential().forEach(downstream);
+ try (Stream<? extends R> result = mapper.apply(u)) {
+ // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+ if (result != null)
+ result.sequential().forEach(downstream);
+ }
}
};
}
@@ -291,10 +292,11 @@
@Override
public void accept(P_OUT u) {
- // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
- IntStream result = mapper.apply(u);
- if (result != null)
- result.sequential().forEach(downstreamAsInt);
+ try (IntStream result = mapper.apply(u)) {
+ // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+ if (result != null)
+ result.sequential().forEach(downstreamAsInt);
+ }
}
};
}
@@ -318,10 +320,11 @@
@Override
public void accept(P_OUT u) {
- // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
- DoubleStream result = mapper.apply(u);
- if (result != null)
- result.sequential().forEach(downstreamAsDouble);
+ try (DoubleStream result = mapper.apply(u)) {
+ // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+ if (result != null)
+ result.sequential().forEach(downstreamAsDouble);
+ }
}
};
}
@@ -345,10 +348,11 @@
@Override
public void accept(P_OUT u) {
- // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
- LongStream result = mapper.apply(u);
- if (result != null)
- result.sequential().forEach(downstreamAsLong);
+ try (LongStream result = mapper.apply(u)) {
+ // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+ if (result != null)
+ result.sequential().forEach(downstreamAsLong);
+ }
}
};
}
@@ -356,8 +360,8 @@
}
@Override
- public final Stream<P_OUT> peek(Consumer<? super P_OUT> tee) {
- Objects.requireNonNull(tee);
+ public final Stream<P_OUT> peek(Consumer<? super P_OUT> action) {
+ Objects.requireNonNull(action);
return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
0) {
@Override
@@ -365,7 +369,7 @@
return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
@Override
public void accept(P_OUT u) {
- tee.accept(u);
+ action.accept(u);
downstream.accept(u);
}
};
@@ -493,7 +497,7 @@
@Override
@SuppressWarnings("unchecked")
- public final <R, A> R collect(Collector<? super P_OUT, A, ? extends R> collector) {
+ public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) {
A container;
if (isParallel()
&& (collector.characteristics().contains(Collector.Characteristics.CONCURRENT))
@@ -511,10 +515,10 @@
}
@Override
- public final <R> R collect(Supplier<R> resultFactory,
+ public final <R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super P_OUT> accumulator,
BiConsumer<R, R> combiner) {
- return evaluate(ReduceOps.makeRef(resultFactory, accumulator, combiner));
+ return evaluate(ReduceOps.makeRef(supplier, accumulator, combiner));
}
@Override
--- a/jdk/src/share/classes/java/util/stream/Stream.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/Stream.java Sat Sep 14 20:43:34 2013 +0100
@@ -24,13 +24,18 @@
*/
package java.util.stream;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Objects;
import java.util.Optional;
import java.util.Spliterator;
import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
@@ -44,51 +49,90 @@
import java.util.function.ToLongFunction;
import java.util.function.UnaryOperator;
-// @@@ Specification to-do list @@@
-// - Describe the difference between sequential and parallel streams
-// - More general information about reduce, better definitions for associativity, more description of
-// how reduce employs parallelism, more examples
-// - Role of stream flags in various operations, specifically ordering
-// - Whether each op preserves encounter order
-// @@@ Specification to-do list @@@
-
/**
- * A sequence of elements supporting sequential and parallel bulk operations.
- * Streams support lazy intermediate operations (transforming a stream to
- * another stream) such as {@code filter} and {@code map}, and terminal
- * operations (consuming the contents of a stream to produce a result or
- * side-effect), such as {@code forEach}, {@code findFirst}, and {@code
- * iterator}. Once an operation has been performed on a stream, it
- * is considered <em>consumed</em> and no longer usable for other operations.
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations. The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link IntStream}:
+ *
+ * <pre>{@code
+ * int sum = widgets.stream()
+ * .filter(w -> w.getColor() == RED)
+ * .mapToInt(w -> w.getWeight())
+ * .sum();
+ * }</pre>
+ *
+ * In this example, {@code widgets} is a {@code Collection<Widget>}. We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code int} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
*
- * <p>For sequential stream pipelines, all operations are performed in the
- * <a href="package-summary.html#Ordering">encounter order</a> of the pipeline
- * source, if the pipeline source has a defined encounter order.
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>. A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an I/O channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link Stream#filter(Predicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link Stream#count()} or {@link Stream#forEach(Consumer)}).
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
+ *
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals. Collections are primarily concerned with the efficient
+ * management of, and access to, their elements. By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
*
- * <p>For parallel stream pipelines, unless otherwise specified, intermediate
- * stream operations preserve the <a href="package-summary.html#Ordering">
- * encounter order</a> of their source, and terminal operations
- * respect the encounter order of their source, if the source
- * has an encounter order. Provided that and parameters to stream operations
- * satisfy the <a href="package-summary.html#NonInterference">non-interference
- * requirements</a>, and excepting differences arising from the absence of
- * a defined encounter order, the result of a stream pipeline should be the
- * stable across multiple executions of the same operations on the same source.
- * However, the timing and thread in which side-effects occur (for those
- * operations which are allowed to produce side-effects, such as
- * {@link #forEach(Consumer)}), are explicitly nondeterministic for parallel
- * execution of stream pipelines.
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source. Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
+ *
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToInt} in the example above. Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references. These parameters can never be null, should not modify the
+ * stream source, and should be
+ * <a href="package-summary.html#NonInterference">effectively stateless</a>
+ * (their result should not depend on any state that might change during
+ * execution of the stream pipeline.)
*
- * <p>Unless otherwise noted, passing a {@code null} argument to any stream
- * method may result in a {@link NullPointerException}.
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once. This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream. A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
*
- * @apiNote
- * Streams are not data structures; they do not manage the storage for their
- * elements, nor do they support access to individual elements. However,
- * you can use the {@link #iterator()} or {@link #spliterator()} operations to
- * perform a controlled traversal.
+ * <p>Streams have a {@link #close()} method and implement {@link AutoCloseable},
+ * but nearly all stream instances do not actually need to be closed after use.
+ * Generally, only streams whose source is an IO channel (such as those returned
+ * by {@link Files#lines(Path, Charset)}) will require closing. Most streams
+ * are backed by collections, arrays, or generating functions, which require no
+ * special resource management. (If a stream does require closing, it can be
+ * declared as a resource in a {@code try}-with-resources statement.)
*
- * @param <T> type of elements
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>. This
+ * execution mode is a property of the stream. Streams are created
+ * with an initial choice of sequential or parallel execution. (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.) This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
+ *
+ * @param <T> the type of the stream elements
* @since 1.8
* @see <a href="package-summary.html">java.util.stream</a>
*/
@@ -168,9 +212,9 @@
/**
* Returns a stream consisting of the results of replacing each element of
* this stream with the contents of the stream produced by applying the
- * provided mapping function to each element. If the result of the mapping
- * function is {@code null}, this is treated as if the result is an empty
- * stream.
+ * provided mapping function to each element. (If the result of the mapping
+ * function is {@code null}, this is treated as if the result was an empty
+ * stream.)
*
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
@@ -197,9 +241,9 @@
/**
* Returns an {@code IntStream} consisting of the results of replacing each
* element of this stream with the contents of the stream produced by
- * applying the provided mapping function to each element. If the result of
- * the mapping function is {@code null}, this is treated as if the result is
- * an empty stream.
+ * applying the provided mapping function to each element. (If the result
+ * of the mapping function is {@code null}, this is treated as if the result
+ * was an empty stream.)
*
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
@@ -214,9 +258,9 @@
/**
* Returns a {@code LongStream} consisting of the results of replacing each
* element of this stream with the contents of the stream produced
- * by applying the provided mapping function to each element. If the result
- * of the mapping function is {@code null}, this is treated as if the
- * result is an empty stream.
+ * by applying the provided mapping function to each element. (If the result
+ * of the mapping function is {@code null}, this is treated as if the result
+ * was an empty stream.)
*
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
@@ -231,9 +275,9 @@
/**
* Returns a {@code DoubleStream} consisting of the results of replacing each
* element of this stream with the contents of the stream produced
- * by applying the provided mapping function to each element. If the result
+ * by applying the provided mapping function to each element. (If the result
* of the mapping function is {@code null}, this is treated as if the result
- * is an empty stream.
+ * was an empty stream.)
*
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
@@ -260,7 +304,7 @@
* Returns a stream consisting of the elements of this stream, sorted
* according to natural order. If the elements of this stream are not
* {@code Comparable}, a {@code java.lang.ClassCastException} may be thrown
- * when the stream pipeline is executed.
+ * when the terminal operation is executed.
*
* <p>This is a <a href="package-summary.html#StreamOps">stateful
* intermediate operation</a>.
@@ -301,18 +345,18 @@
* <pre>{@code
* list.stream()
* .filter(filteringFunction)
- * .peek(e -> {System.out.println("Filtered value: " + e); });
+ * .peek(e -> System.out.println("Filtered value: " + e));
* .map(mappingFunction)
- * .peek(e -> {System.out.println("Mapped value: " + e); });
+ * .peek(e -> System.out.println("Mapped value: " + e));
* .collect(Collectors.intoList());
* }</pre>
*
- * @param consumer a <a href="package-summary.html#NonInterference">
+ * @param action a <a href="package-summary.html#NonInterference">
* non-interfering</a> action to perform on the elements as
* they are consumed from the stream
* @return the new stream
*/
- Stream<T> peek(Consumer<? super T> consumer);
+ Stream<T> peek(Consumer<? super T> action);
/**
* Returns a stream consisting of the elements of this stream, truncated
@@ -329,8 +373,8 @@
/**
* Returns a stream consisting of the remaining elements of this stream
- * after indexing {@code startInclusive} elements into the stream. If the
- * {@code startInclusive} index lies past the end of this stream then an
+ * after discarding the first {@code startInclusive} elements of the stream.
+ * If this stream contains fewer than {@code startInclusive} elements then an
* empty stream will be returned.
*
* <p>This is a <a href="package-summary.html#StreamOps">stateful
@@ -344,10 +388,10 @@
/**
* Returns a stream consisting of the remaining elements of this stream
- * after indexing {@code startInclusive} elements into the stream and
- * truncated to contain no more than {@code endExclusive - startInclusive}
- * elements. If the {@code startInclusive} index lies past the end
- * of this stream then an empty stream will be returned.
+ * after discarding the first {@code startInclusive} elements and truncating
+ * the result to be no longer than {@code endExclusive - startInclusive}
+ * elements in length. If this stream contains fewer than
+ * {@code startInclusive} elements then an empty stream will be returned.
*
* <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
* stateful intermediate operation</a>.
@@ -405,11 +449,23 @@
/**
* Returns an array containing the elements of this stream, using the
- * provided {@code generator} function to allocate the returned array.
+ * provided {@code generator} function to allocate the returned array, as
+ * well as any additional arrays that might be required for a partitioned
+ * execution or for resizing.
*
* <p>This is a <a href="package-summary.html#StreamOps">terminal
* operation</a>.
*
+ * @apiNote
+ * The generator function takes an integer, which is the size of the
+ * desired array, and produces an array of the desired size. This can be
+ * concisely expressed with an array constructor reference:
+ * <pre>{@code
+ * Person[] men = people.stream()
+ * .filter(p -> p.getGender() == MALE)
+ * .toArray(Person[]::new);
+ * }</pre>
+ *
* @param <A> the element type of the resulting array
* @param generator a function which produces a new array of the desired
* type and the provided length
@@ -451,7 +507,7 @@
* Integer sum = integers.reduce(0, (a, b) -> a+b);
* }</pre>
*
- * or more compactly:
+ * or:
*
* <pre>{@code
* Integer sum = integers.reduce(0, Integer::sum);
@@ -501,7 +557,8 @@
* @param accumulator an <a href="package-summary.html#Associativity">associative</a>
* <a href="package-summary.html#NonInterference">non-interfering,
* stateless</a> function for combining two values
- * @return the result of the reduction
+ * @return an {@link Optional} describing the result of the reduction
+ * @throws NullPointerException if the result of the reduction is null
* @see #reduce(Object, BinaryOperator)
* @see #min(java.util.Comparator)
* @see #max(java.util.Comparator)
@@ -510,8 +567,8 @@
/**
* Performs a <a href="package-summary.html#Reduction">reduction</a> on the
- * elements of this stream, using the provided identity, accumulation
- * function, and a combining functions. This is equivalent to:
+ * elements of this stream, using the provided identity, accumulation and
+ * combining functions. This is equivalent to:
* <pre>{@code
* U result = identity;
* for (T element : this stream)
@@ -537,8 +594,8 @@
* by an explicit combination of {@code map} and {@code reduce} operations.
* The {@code accumulator} function acts as a fused mapper and accumulator,
* which can sometimes be more efficient than separate mapping and reduction,
- * such as in the case where knowing the previously reduced value allows you
- * to avoid some computation.
+ * such as when knowing the previously reduced value allows you to avoid
+ * some computation.
*
* @param <U> The type of the result
* @param identity the identity value for the combiner function
@@ -561,12 +618,12 @@
/**
* Performs a <a href="package-summary.html#MutableReduction">mutable
* reduction</a> operation on the elements of this stream. A mutable
- * reduction is one in which the reduced value is a mutable value holder,
+ * reduction is one in which the reduced value is a mutable result container,
* such as an {@code ArrayList}, and elements are incorporated by updating
- * the state of the result, rather than by replacing the result. This
+ * the state of the result rather than by replacing the result. This
* produces a result equivalent to:
* <pre>{@code
- * R result = resultFactory.get();
+ * R result = supplier.get();
* for (T element : this stream)
* accumulator.accept(result, element);
* return result;
@@ -579,10 +636,11 @@
* operation</a>.
*
* @apiNote There are many existing classes in the JDK whose signatures are
- * a good match for use as arguments to {@code collect()}. For example,
- * the following will accumulate strings into an ArrayList:
+ * well-suited for use with method references as arguments to {@code collect()}.
+ * For example, the following will accumulate strings into an {@code ArrayList}:
* <pre>{@code
- * List<String> asList = stringStream.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
+ * List<String> asList = stringStream.collect(ArrayList::new, ArrayList::add,
+ * ArrayList::addAll);
* }</pre>
*
* <p>The following will take a stream of strings and concatenates them into a
@@ -594,10 +652,9 @@
* }</pre>
*
* @param <R> type of the result
- * @param resultFactory a function that creates a new result container.
- * For a parallel execution, this function may be
- * called multiple times and must return a fresh value
- * each time.
+ * @param supplier a function that creates a new result container. For a
+ * parallel execution, this function may be called
+ * multiple times and must return a fresh value each time.
* @param accumulator an <a href="package-summary.html#Associativity">associative</a>
* <a href="package-summary.html#NonInterference">non-interfering,
* stateless</a> function for incorporating an additional
@@ -608,24 +665,24 @@
* must be compatible with the accumulator function
* @return the result of the reduction
*/
- <R> R collect(Supplier<R> resultFactory,
+ <R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner);
/**
* Performs a <a href="package-summary.html#MutableReduction">mutable
* reduction</a> operation on the elements of this stream using a
- * {@code Collector} object to describe the reduction. A {@code Collector}
+ * {@code Collector}. A {@code Collector}
* encapsulates the functions used as arguments to
* {@link #collect(Supplier, BiConsumer, BiConsumer)}, allowing for reuse of
- * collection strategies, and composition of collect operations such as
+ * collection strategies and composition of collect operations such as
* multiple-level grouping or partitioning.
*
* <p>This is a <a href="package-summary.html#StreamOps">terminal
* operation</a>.
*
* <p>When executed in parallel, multiple intermediate results may be
- * instantiated, populated, and merged, so as to maintain isolation of
+ * instantiated, populated, and merged so as to maintain isolation of
* mutable data structures. Therefore, even when executed in parallel
* with non-thread-safe data structures (such as {@code ArrayList}), no
* additional synchronization is needed for a parallel reduction.
@@ -638,16 +695,16 @@
*
* <p>The following will classify {@code Person} objects by city:
* <pre>{@code
- * Map<String, Collection<Person>> peopleByCity
- * = personStream.collect(Collectors.groupBy(Person::getCity));
+ * Map<String, List<Person>> peopleByCity
+ * = personStream.collect(Collectors.groupingBy(Person::getCity));
* }</pre>
*
* <p>The following will classify {@code Person} objects by state and city,
* cascading two {@code Collector}s together:
* <pre>{@code
- * Map<String, Map<String, Collection<Person>>> peopleByStateAndCity
- * = personStream.collect(Collectors.groupBy(Person::getState,
- * Collectors.groupBy(Person::getCity)));
+ * Map<String, Map<String, List<Person>>> peopleByStateAndCity
+ * = personStream.collect(Collectors.groupingBy(Person::getState,
+ * Collectors.groupingBy(Person::getCity)));
* }</pre>
*
* @param <R> the type of the result
@@ -657,12 +714,12 @@
* @see #collect(Supplier, BiConsumer, BiConsumer)
* @see Collectors
*/
- <R, A> R collect(Collector<? super T, A, ? extends R> collector);
+ <R, A> R collect(Collector<? super T, A, R> collector);
/**
* Returns the minimum element of this stream according to the provided
* {@code Comparator}. This is a special case of a
- * <a href="package-summary.html#MutableReduction">reduction</a>.
+ * <a href="package-summary.html#Reduction">reduction</a>.
*
* <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
*
@@ -671,13 +728,14 @@
* elements of this stream
* @return an {@code Optional} describing the minimum element of this stream,
* or an empty {@code Optional} if the stream is empty
+ * @throws NullPointerException if the minimum element is null
*/
Optional<T> min(Comparator<? super T> comparator);
/**
* Returns the maximum element of this stream according to the provided
* {@code Comparator}. This is a special case of a
- * <a href="package-summary.html#MutableReduction">reduction</a>.
+ * <a href="package-summary.html#Reduction">reduction</a>.
*
* <p>This is a <a href="package-summary.html#StreamOps">terminal
* operation</a>.
@@ -687,12 +745,13 @@
* elements of this stream
* @return an {@code Optional} describing the maximum element of this stream,
* or an empty {@code Optional} if the stream is empty
+ * @throws NullPointerException if the maximum element is null
*/
Optional<T> max(Comparator<? super T> comparator);
/**
* Returns the count of elements in this stream. This is a special case of
- * a <a href="package-summary.html#MutableReduction">reduction</a> and is
+ * a <a href="package-summary.html#Reduction">reduction</a> and is
* equivalent to:
* <pre>{@code
* return mapToLong(e -> 1L).sum();
@@ -753,10 +812,9 @@
boolean noneMatch(Predicate<? super T> predicate);
/**
- * Returns an {@link Optional} describing the first element of this stream
- * (in the encounter order), or an empty {@code Optional} if the stream is
- * empty. If the stream has no encounter order, then any element may be
- * returned.
+ * Returns an {@link Optional} describing the first element of this stream,
+ * or an empty {@code Optional} if the stream is empty. If the stream has
+ * no encounter order, then any element may be returned.
*
* <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
* terminal operation</a>.
@@ -777,8 +835,8 @@
* <p>The behavior of this operation is explicitly nondeterministic; it is
* free to select any element in the stream. This is to allow for maximal
* performance in parallel operations; the cost is that multiple invocations
- * on the same source may not return the same result. (If the first element
- * in the encounter order is desired, use {@link #findFirst()} instead.)
+ * on the same source may not return the same result. (If a stable result
+ * is desired, use {@link #findFirst()} instead.)
*
* @return an {@code Optional} describing some element of this stream, or an
* empty {@code Optional} if the stream is empty
@@ -821,7 +879,7 @@
}
/**
- * Returns a sequential stream whose elements are the specified values.
+ * Returns a sequential ordered stream whose elements are the specified values.
*
* @param <T> the type of stream elements
* @param values the elements of the new stream
@@ -834,7 +892,7 @@
}
/**
- * Returns an infinite sequential {@code Stream} produced by iterative
+ * Returns an infinite sequential ordered {@code Stream} produced by iterative
* application of a function {@code f} to an initial element {@code seed},
* producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
* {@code f(f(seed))}, etc.
@@ -872,8 +930,8 @@
}
/**
- * Returns a sequential {@code Stream} where each element is
- * generated by a {@code Supplier}. This is suitable for generating
+ * Returns a sequential stream where each element is generated by
+ * the provided {@code Supplier}. This is suitable for generating
* constant streams, streams of random elements, etc.
*
* @param <T> the type of stream elements
@@ -887,16 +945,16 @@
}
/**
- * Creates a lazy concatenated {@code Stream} whose elements are all the
- * elements of a first {@code Stream} succeeded by all the elements of the
- * second {@code Stream}. The resulting stream is ordered if both
+ * Creates a lazily concatenated stream whose elements are all the
+ * elements of the first stream followed by all the elements of the
+ * second stream. The resulting stream is ordered if both
* of the input streams are ordered, and parallel if either of the input
- * streams is parallel.
+ * streams is parallel. When the resulting stream is closed, the close
+ * handlers for both input streams are invoked.
*
* @param <T> The type of stream elements
* @param a the first stream
- * @param b the second stream to concatenate on to end of the first
- * stream
+ * @param b the second stream
* @return the concatenation of the two input streams
*/
public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
@@ -906,7 +964,8 @@
@SuppressWarnings("unchecked")
Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
(Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
- return StreamSupport.stream(split, a.isParallel() || b.isParallel());
+ Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
+ return stream.onClose(Streams.composedClose(a, b));
}
/**
@@ -915,7 +974,7 @@
* {@code Builder} (without the copying overhead that comes from using
* an {@code ArrayList} as a temporary buffer.)
*
- * <p>A {@code Stream.Builder} has a lifecycle, where it starts in a building
+ * <p>A stream builder has a lifecycle, which starts in a building
* phase, during which elements can be added, and then transitions to a built
* phase, after which elements may not be added. The built phase begins
* when the {@link #build()} method is called, which creates an ordered
--- a/jdk/src/share/classes/java/util/stream/StreamSpliterators.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/StreamSpliterators.java Sat Sep 14 20:43:34 2013 +0100
@@ -1456,4 +1456,5 @@
}
}
}
-}
\ No newline at end of file
+}
+
--- a/jdk/src/share/classes/java/util/stream/StreamSupport.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/StreamSupport.java Sat Sep 14 20:43:34 2013 +0100
@@ -32,12 +32,8 @@
* Low-level utility methods for creating and manipulating streams.
*
* <p>This class is mostly for library writers presenting stream views
- * of their data structures; most static stream methods for end users are in
- * {@link Streams}.
- *
- * <p>Unless otherwise stated, streams are created as sequential
- * streams. A sequential stream can be transformed into a parallel stream by
- * calling the {@code parallel()} method on the created stream.
+ * of data structures; most static stream methods intended for end users are in
+ * the various {@code Stream} classes.
*
* @since 1.8
*/
@@ -80,7 +76,7 @@
* {@code Supplier} of {@code Spliterator}.
*
* <p>The {@link Supplier#get()} method will be invoked on the supplier no
- * more than once, and after the terminal operation of the stream pipeline
+ * more than once, and only after the terminal operation of the stream pipeline
* commences.
*
* <p>For spliterators that report a characteristic of {@code IMMUTABLE}
@@ -88,7 +84,7 @@
* <a href="../Spliterator.html#binding">late-binding</a>, it is likely
* more efficient to use {@link #stream(java.util.Spliterator, boolean)}
* instead.
- * The use of a {@code Supplier} in this form provides a level of
+ * <p>The use of a {@code Supplier} in this form provides a level of
* indirection that reduces the scope of potential interference with the
* source. Since the supplier is only invoked after the terminal operation
* commences, any modifications to the source up to the start of the
@@ -148,7 +144,7 @@
* {@code Supplier} of {@code Spliterator.OfInt}.
*
* <p>The {@link Supplier#get()} method will be invoked on the supplier no
- * more than once, and after the terminal operation of the stream pipeline
+ * more than once, and only after the terminal operation of the stream pipeline
* commences.
*
* <p>For spliterators that report a characteristic of {@code IMMUTABLE}
@@ -156,7 +152,7 @@
* <a href="../Spliterator.html#binding">late-binding</a>, it is likely
* more efficient to use {@link #intStream(java.util.Spliterator.OfInt, boolean)}
* instead.
- * The use of a {@code Supplier} in this form provides a level of
+ * <p>The use of a {@code Supplier} in this form provides a level of
* indirection that reduces the scope of potential interference with the
* source. Since the supplier is only invoked after the terminal operation
* commences, any modifications to the source up to the start of the
@@ -215,7 +211,7 @@
* {@code Supplier} of {@code Spliterator.OfLong}.
*
* <p>The {@link Supplier#get()} method will be invoked on the supplier no
- * more than once, and after the terminal operation of the stream pipeline
+ * more than once, and only after the terminal operation of the stream pipeline
* commences.
*
* <p>For spliterators that report a characteristic of {@code IMMUTABLE}
@@ -223,7 +219,7 @@
* <a href="../Spliterator.html#binding">late-binding</a>, it is likely
* more efficient to use {@link #longStream(java.util.Spliterator.OfLong, boolean)}
* instead.
- * The use of a {@code Supplier} in this form provides a level of
+ * <p>The use of a {@code Supplier} in this form provides a level of
* indirection that reduces the scope of potential interference with the
* source. Since the supplier is only invoked after the terminal operation
* commences, any modifications to the source up to the start of the
@@ -282,7 +278,7 @@
* {@code Supplier} of {@code Spliterator.OfDouble}.
*
* <p>The {@link Supplier#get()} method will be invoked on the supplier no
- * more than once, and after the terminal operation of the stream pipeline
+ * more than once, and only after the terminal operation of the stream pipeline
* commences.
*
* <p>For spliterators that report a characteristic of {@code IMMUTABLE}
@@ -290,7 +286,7 @@
* <a href="../Spliterator.html#binding">late-binding</a>, it is likely
* more efficient to use {@link #doubleStream(java.util.Spliterator.OfDouble, boolean)}
* instead.
- * The use of a {@code Supplier} in this form provides a level of
+ * <p>The use of a {@code Supplier} in this form provides a level of
* indirection that reduces the scope of potential interference with the
* source. Since the supplier is only invoked after the terminal operation
* commences, any modifications to the source up to the start of the
--- a/jdk/src/share/classes/java/util/stream/Streams.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/Streams.java Sat Sep 14 20:43:34 2013 +0100
@@ -833,4 +833,61 @@
}
}
}
+
+ /**
+ * Given two Runnables, return a Runnable that executes both in sequence,
+ * even if the first throws an exception, and if both throw exceptions, add
+ * any exceptions thrown by the second as suppressed exceptions of the first.
+ */
+ static Runnable composeWithExceptions(Runnable a, Runnable b) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ try {
+ a.run();
+ }
+ catch (Throwable e1) {
+ try {
+ b.run();
+ }
+ catch (Throwable e2) {
+ try {
+ e1.addSuppressed(e2);
+ } catch (Throwable ignore) {}
+ }
+ throw e1;
+ }
+ b.run();
+ }
+ };
+ }
+
+ /**
+ * Given two streams, return a Runnable that
+ * executes both of their {@link BaseStream#close} methods in sequence,
+ * even if the first throws an exception, and if both throw exceptions, add
+ * any exceptions thrown by the second as suppressed exceptions of the first.
+ */
+ static Runnable composedClose(BaseStream<?, ?> a, BaseStream<?, ?> b) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ try {
+ a.close();
+ }
+ catch (Throwable e1) {
+ try {
+ b.close();
+ }
+ catch (Throwable e2) {
+ try {
+ e1.addSuppressed(e2);
+ } catch (Throwable ignore) {}
+ }
+ throw e1;
+ }
+ b.close();
+ }
+ };
+ }
}
--- a/jdk/src/share/classes/java/util/stream/package-info.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/stream/package-info.java Sat Sep 14 20:43:34 2013 +0100
@@ -24,347 +24,485 @@
*/
/**
- * <h1>java.util.stream</h1>
- *
- * Classes to support functional-style operations on streams of values, as in the following:
+ * Classes to support functional-style operations on streams of elements, such
+ * as map-reduce transformations on collections. For example:
*
* <pre>{@code
- * int sumOfWeights = blocks.stream().filter(b -> b.getColor() == RED)
- * .mapToInt(b -> b.getWeight())
- * .sum();
+ * int sum = widgets.stream()
+ * .filter(b -> b.getColor() == RED)
+ * .mapToInt(b -> b.getWeight())
+ * .sum();
* }</pre>
*
- * <p>Here we use {@code blocks}, which might be a {@code Collection}, as a source for a stream,
- * and then perform a filter-map-reduce ({@code sum()} is an example of a <a href="package-summary.html#Reduction">reduction</a>
- * operation) on the stream to obtain the sum of the weights of the red blocks.
+ * <p>Here we use {@code widgets}, a {@code Collection<Widget>},
+ * as a source for a stream, and then perform a filter-map-reduce on the stream
+ * to obtain the sum of the weights of the red widgets. (Summation is an
+ * example of a <a href="package-summary.html#Reduction">reduction</a>
+ * operation.)
*
- * <p>The key abstraction used in this approach is {@link java.util.stream.Stream}, as well as its primitive
- * specializations {@link java.util.stream.IntStream}, {@link java.util.stream.LongStream},
- * and {@link java.util.stream.DoubleStream}. Streams differ from Collections in several ways:
+ * <p>The key abstraction introduced in this package is <em>stream</em>. The
+ * classes {@link java.util.stream.Stream}, {@link java.util.stream.IntStream},
+ * {@link java.util.stream.LongStream}, and {@link java.util.stream.DoubleStream}
+ * are streams over objects and the primitive {@code int}, {@code long} and
+ * {@code double} types. Streams differ from collections in several ways:
*
* <ul>
- * <li>No storage. A stream is not a data structure that stores elements; instead, they
- * carry values from a source (which could be a data structure, a generator, an IO channel, etc)
- * through a pipeline of computational operations.</li>
- * <li>Functional in nature. An operation on a stream produces a result, but does not modify
- * its underlying data source. For example, filtering a {@code Stream} produces a new {@code Stream},
- * rather than removing elements from the underlying source.</li>
- * <li>Laziness-seeking. Many stream operations, such as filtering, mapping, or duplicate removal,
- * can be implemented lazily, exposing opportunities for optimization. (For example, "find the first
- * {@code String} matching a pattern" need not examine all the input strings.) Stream operations
- * are divided into intermediate ({@code Stream}-producing) operations and terminal (value-producing)
- * operations; all intermediate operations are lazy.</li>
- * <li>Possibly unbounded. While collections have a finite size, streams need not. Operations
- * such as {@code limit(n)} or {@code findFirst()} can allow computations on infinite streams
- * to complete in finite time.</li>
+ * <li>No storage. A stream is not a data structure that stores elements;
+ * instead, it conveys elements from a source such as a data structure,
+ * an array, a generator function, or an I/O channel, through a pipeline of
+ * computational operations.</li>
+ * <li>Functional in nature. An operation on a stream produces a result,
+ * but does not modify its source. For example, filtering a {@code Stream}
+ * obtained from a collection produces a new {@code Stream} without the
+ * filtered elements, rather than removing elements from the source
+ * collection.</li>
+ * <li>Laziness-seeking. Many stream operations, such as filtering, mapping,
+ * or duplicate removal, can be implemented lazily, exposing opportunities
+ * for optimization. For example, "find the first {@code String} with
+ * three consecutive vowels" need not examine all the input strings.
+ * Stream operations are divided into intermediate ({@code Stream}-producing)
+ * operations and terminal (value- or side-effect-producing) operations.
+ * Intermediate operations are always lazy.</li>
+ * <li>Possibly unbounded. While collections have a finite size, streams
+ * need not. Short-circuiting operations such as {@code limit(n)} or
+ * {@code findFirst()} can allow computations on infinite streams to
+ * complete in finite time.</li>
+ * <li>Consumable. The elements of a stream are only visited once during
+ * the life of a stream. Like an {@link java.util.Iterator}, a new stream
+ * must be generated to revisit the same elements of the source.
+ * </li>
+ * </ul>
+ *
+ * Streams can be obtained in a number of ways. Some examples include:
+ * <ul>
+ * <li>From a {@link java.util.Collection} via the {@code stream()} and
+ * {@code parallelStream()} methods;</li>
+ * <li>From an array via {@link java.util.Arrays#stream(Object[])};</li>
+ * <li>From static factory methods on the stream classes, such as
+ * {@link java.util.stream.Stream#of(Object[])},
+ * {@link java.util.stream.IntStream#range(int, int)}
+ * or {@link java.util.stream.Stream#iterate(Object, UnaryOperator)};</li>
+ * <li>The lines of a file can be obtained from {@link java.io.BufferedReader#lines()};</li>
+ * <li>Streams of file paths can be obtained from methods in {@link java.nio.file.Files};</li>
+ * <li>Streams of random numbers can be obtained from {@link java.util.Random#ints()};</li>
+ * <li>Numerous other stream-bearing methods in the JDK, including
+ * {@link java.util.BitSet#stream()},
+ * {@link java.util.regex.Pattern#splitAsStream(java.lang.CharSequence)},
+ * and {@link java.util.jar.JarFile#stream()}.</li>
* </ul>
*
- * <h2><a name="StreamPipelines">Stream pipelines</a></h2>
+ * <p>Additional stream sources can be provided by third-party libraries using
+ * <a href="package-summary.html#StreamSources">these techniques</a>.
+ *
+ * <h2><a name="StreamOps">Stream operations and pipelines</a></h2>
*
- * <p>Streams are used to create <em>pipelines</em> of <a href="package-summary.html#StreamOps">operations</a>. A
- * complete stream pipeline has several components: a source (which may be a {@code Collection},
- * an array, a generator function, or an IO channel); zero or more <em>intermediate operations</em>
- * such as {@code Stream.filter} or {@code Stream.map}; and a <em>terminal operation</em> such
- * as {@code Stream.forEach} or {@code java.util.stream.Stream.reduce}. Stream operations may take as parameters
- * <em>function values</em> (which are often lambda expressions, but could be method references
- * or objects) which parameterize the behavior of the operation, such as a {@code Predicate}
- * passed to the {@code Stream#filter} method.
+ * <p>Stream operations are divided into <em>intermediate</em> and
+ * <em>terminal</em> operations, and are combined to form <em>stream
+ * pipelines</em>. A stream pipeline consists of a source (such as a
+ * {@code Collection}, an array, a generator function, or an I/O channel);
+ * followed by zero or more intermediate operations such as
+ * {@code Stream.filter} or {@code Stream.map}; and a terminal operation such
+ * as {@code Stream.forEach} or {@code Stream.reduce}.
*
- * <p>Intermediate operations return a new {@code Stream}. They are lazy; executing an
- * intermediate operation such as {@link java.util.stream.Stream#filter Stream.filter} does
- * not actually perform any filtering, instead creating a new {@code Stream} that, when
- * traversed, contains the elements of the initial {@code Stream} that match the
- * given {@code Predicate}. Consuming elements from the stream source does not
- * begin until the terminal operation is executed.
+ * <p>Intermediate operations return a new stream. They are always
+ * <em>lazy</em>; executing an intermediate operation such as
+ * {@code filter()} does not actually perform any filtering, but instead
+ * creates a new stream that, when traversed, contains the elements of
+ * the initial stream that match the given predicate. Traversal
+ * of the pipeline source does not begin until the terminal operation of the
+ * pipeline is executed.
*
- * <p>Terminal operations consume the {@code Stream} and produce a result or a side-effect.
- * After a terminal operation is performed, the stream can no longer be used and you must
- * return to the data source, or select a new data source, to get a new stream. For example,
- * obtaining the sum of weights of all red blocks, and then of all blue blocks, requires a
- * filter-map-reduce on two different streams:
- * <pre>{@code
- * int sumOfRedWeights = blocks.stream().filter(b -> b.getColor() == RED)
- * .mapToInt(b -> b.getWeight())
- * .sum();
- * int sumOfBlueWeights = blocks.stream().filter(b -> b.getColor() == BLUE)
- * .mapToInt(b -> b.getWeight())
- * .sum();
- * }</pre>
- *
- * <p>However, there are other techniques that allow you to obtain both results in a single
- * pass if multiple traversal is impractical or inefficient. TODO provide link
+ * <p>Terminal operations, such as {@code Stream.forEach} or
+ * {@code IntStream.sum}, may traverse the stream to produce a result or a
+ * side-effect. After the terminal operation is performed, the stream pipeline
+ * is considered consumed, and can no longer be used; if you need to traverse
+ * the same data source again, you must return to the data source to get a new
+ * stream. In almost all cases, terminal operations are <em>eager</em>,
+ * completing their traversal of the data source and processing of the pipeline
+ * before returning. Only the terminal operations {@code iterator()} and
+ * {@code spliterator()} are not; these are provided as an "escape hatch" to enable
+ * arbitrary client-controlled pipeline traversals in the event that the
+ * existing operations are not sufficient to the task.
*
- * <h3><a name="StreamOps">Stream operations</a></h3>
- *
- * <p>Intermediate stream operation (such as {@code filter} or {@code sorted}) always produce a
- * new {@code Stream}, and are always<em>lazy</em>. Executing a lazy operations does not
- * trigger processing of the stream contents; all processing is deferred until the terminal
- * operation commences. Processing streams lazily allows for significant efficiencies; in a
- * pipeline such as the filter-map-sum example above, filtering, mapping, and addition can be
- * fused into a single pass, with minimal intermediate state. Laziness also enables us to avoid
- * examining all the data when it is not necessary; for operations such as "find the first
- * string longer than 1000 characters", one need not examine all the input strings, just enough
- * to find one that has the desired characteristics. (This behavior becomes even more important
- * when the input stream is infinite and not merely large.)
+ * <p> Processing streams lazily allows for significant efficiencies; in a
+ * pipeline such as the filter-map-sum example above, filtering, mapping, and
+ * summing can be fused into a single pass on the data, with minimal
+ * intermediate state. Laziness also allows avoiding examining all the data
+ * when it is not necessary; for operations such as "find the first string
+ * longer than 1000 characters", it is only necessary to examine just enough
+ * strings to find one that has the desired characteristics without examining
+ * all of the strings available from the source. (This behavior becomes even
+ * more important when the input stream is infinite and not merely large.)
*
- * <p>Intermediate operations are further divided into <em>stateless</em> and <em>stateful</em>
- * operations. Stateless operations retain no state from previously seen values when processing
- * a new value; examples of stateless intermediate operations include {@code filter} and
- * {@code map}. Stateful operations may incorporate state from previously seen elements in
- * processing new values; examples of stateful intermediate operations include {@code distinct}
- * and {@code sorted}. Stateful operations may need to process the entire input before
- * producing a result; for example, one cannot produce any results from sorting a stream until
- * one has seen all elements of the stream. As a result, under parallel computation, some
- * pipelines containing stateful intermediate operations have to be executed in multiple passes.
- * Pipelines containing exclusively stateless intermediate operations can be processed in a
- * single pass, whether sequential or parallel.
+ * <p>Intermediate operations are further divided into <em>stateless</em>
+ * and <em>stateful</em> operations. Stateless operations, such as {@code filter}
+ * and {@code map}, retain no state from previously seen element when processing
+ * a new element -- each element can be processed
+ * independently of operations on other elements. Stateful operations, such as
+ * {@code distinct} and {@code sorted}, may incorporate state from previously
+ * seen elements when processing new elements.
*
- * <p>Further, some operations are deemed <em>short-circuiting</em> operations. An intermediate
- * operation is short-circuiting if, when presented with infinite input, it may produce a
- * finite stream as a result. A terminal operation is short-circuiting if, when presented with
- * infinite input, it may terminate in finite time. (Having a short-circuiting operation is a
- * necessary, but not sufficient, condition for the processing of an infinite stream to
- * terminate normally in finite time.)
+ * <p>Stateful operations may need to process the entire input
+ * before producing a result. For example, one cannot produce any results from
+ * sorting a stream until one has seen all elements of the stream. As a result,
+ * under parallel computation, some pipelines containing stateful intermediate
+ * operations may require multiple passes on the data or may need to buffer
+ * significant data. Pipelines containing exclusively stateless intermediate
+ * operations can be processed in a single pass, whether sequential or parallel,
+ * with minimal data buffering.
*
- * Terminal operations (such as {@code forEach} or {@code findFirst}) are always eager
- * (they execute completely before returning), and produce a non-{@code Stream} result, such
- * as a primitive value or a {@code Collection}, or have side-effects.
+ * <p>Further, some operations are deemed <em>short-circuiting</em> operations.
+ * An intermediate operation is short-circuiting if, when presented with
+ * infinite input, it may produce a finite stream as a result. A terminal
+ * operation is short-circuiting if, when presented with infinite input, it may
+ * terminate in finite time. Having a short-circuiting operation in the pipeline
+ * is a necessary, but not sufficient, condition for the processing of an infinite
+ * stream to terminate normally in finite time.
*
* <h3>Parallelism</h3>
*
- * <p>By recasting aggregate operations as a pipeline of operations on a stream of values, many
- * aggregate operations can be more easily parallelized. A {@code Stream} can execute either
- * in serial or in parallel. When streams are created, they are either created as sequential
- * or parallel streams; the parallel-ness of streams can also be switched by the
- * {@link java.util.stream Stream#sequential()} and {@link java.util.stream.Stream#parallel()}
- * operations. The {@code Stream} implementations in the JDK create serial streams unless
- * parallelism is explicitly requested. For example, {@code Collection} has methods
+ * <p>Processing elements with an explicit {@code for-}loop is inherently serial.
+ * Streams facilitate parallel execution by reframing the computation as a pipeline of
+ * aggregate operations, rather than as imperative operations on each individual
+ * element. All streams operations can execute either in serial or in parallel.
+ * The stream implementations in the JDK create serial streams unless parallelism is
+ * explicitly requested. For example, {@code Collection} has methods
* {@link java.util.Collection#stream} and {@link java.util.Collection#parallelStream},
- * which produce sequential and parallel streams respectively; other stream-bearing methods
- * such as {@link java.util.stream.IntStream#range(int, int)} produce sequential
- * streams but these can be efficiently parallelized by calling {@code parallel()} on the
- * result. The set of operations on serial and parallel streams is identical. To execute the
- * "sum of weights of blocks" query in parallel, we would do:
+ * which produce sequential and parallel streams respectively; other
+ * stream-bearing methods such as {@link java.util.stream.IntStream#range(int, int)}
+ * produce sequential streams but these streams can be efficiently parallelized by
+ * invoking their {@link java.util.stream.BaseStream#parallel()} method.
+ * To execute the prior "sum of weights of widgets" query in parallel, we would
+ * do:
*
* <pre>{@code
- * int sumOfWeights = blocks.parallelStream().filter(b -> b.getColor() == RED)
- * .mapToInt(b -> b.getWeight())
- * .sum();
+ * int sumOfWeights = widgets.}<code><b>parallelStream()</b></code>{@code
+ * .filter(b -> b.getColor() == RED)
+ * .mapToInt(b -> b.getWeight())
+ * .sum();
* }</pre>
*
- * <p>The only difference between the serial and parallel versions of this example code is
- * the creation of the initial {@code Stream}. Whether a {@code Stream} will execute in serial
- * or parallel can be determined by the {@code Stream#isParallel} method. When the terminal
- * operation is initiated, the entire stream pipeline is either executed sequentially or in
- * parallel, determined by the last operation that affected the stream's serial-parallel
- * orientation (which could be the stream source, or the {@code sequential()} or
- * {@code parallel()} methods.)
- *
- * <p>In order for the results of parallel operations to be deterministic and consistent with
- * their serial equivalent, the function values passed into the various stream operations should
- * be <a href="#NonInteference"><em>stateless</em></a>.
- *
- * <h3><a name="Ordering">Ordering</a></h3>
- *
- * <p>Streams may or may not have an <em>encounter order</em>. An encounter
- * order specifies the order in which elements are provided by the stream to the
- * operations pipeline. Whether or not there is an encounter order depends on
- * the source, the intermediate operations, and the terminal operation.
- * Certain stream sources (such as {@code List} or arrays) are intrinsically
- * ordered, whereas others (such as {@code HashSet}) are not. Some intermediate
- * operations may impose an encounter order on an otherwise unordered stream,
- * such as {@link java.util.stream.Stream#sorted()}, and others may render an
- * ordered stream unordered (such as {@link java.util.stream.Stream#unordered()}).
- * Some terminal operations may ignore encounter order, such as
- * {@link java.util.stream.Stream#forEach}.
+ * <p>The only difference between the serial and parallel versions of this
+ * example is the creation of the initial stream, using "{@code parallelStream()}"
+ * instead of "{@code stream()}". When the terminal operation is initiated,
+ * the stream pipeline is executed sequentially or in parallel depending on the
+ * orientation of the stream on which it is invoked. Whether a stream will execute in serial or
+ * parallel can be determined with the {@code isParallel()} method, and the
+ * orientation of a stream can be modified with the
+ * {@link java.util.stream.BaseStream#sequential()} and
+ * {@link java.util.stream.BaseStream#parallel()} operations. When the terminal
+ * operation is initiated, the stream pipeline is executed sequentially or in
+ * parallel depending on the mode of the stream on which it is invoked.
*
- * <p>If a Stream is ordered, most operations are constrained to operate on the
- * elements in their encounter order; if the source of a stream is a {@code List}
- * containing {@code [1, 2, 3]}, then the result of executing {@code map(x -> x*2)}
- * must be {@code [2, 4, 6]}. However, if the source has no defined encounter
- * order, than any of the six permutations of the values {@code [2, 4, 6]} would
- * be a valid result. Many operations can still be efficiently parallelized even
- * under ordering constraints.
- *
- * <p>For sequential streams, ordering is only relevant to the determinism
- * of operations performed repeatedly on the same source. (An {@code ArrayList}
- * is constrained to iterate elements in order; a {@code HashSet} is not, and
- * repeated iteration might produce a different order.)
+ * <p>Except for operations identified as explicitly nondeterministic, such
+ * as {@code findAny()}, whether a stream executes sequentially or in parallel
+ * should not change the result of the computation.
*
- * <p>For parallel streams, relaxing the ordering constraint can enable
- * optimized implementation for some operations. For example, duplicate
- * filtration on an ordered stream must completely process the first partition
- * before it can return any elements from a subsequent partition, even if those
- * elements are available earlier. On the other hand, without the constraint of
- * ordering, duplicate filtration can be done more efficiently by using
- * a shared {@code ConcurrentHashSet}. There will be cases where the stream
- * is structurally ordered (the source is ordered and the intermediate
- * operations are order-preserving), but the user does not particularly care
- * about the encounter order. In some cases, explicitly de-ordering the stream
- * with the {@link java.util.stream.Stream#unordered()} method may result in
- * improved parallel performance for some stateful or terminal operations.
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, which are often lambda expressions. To preserve correct behavior,
+ * these <em>behavioral parameters</em> must be <em>non-interfering</em>, and in
+ * most cases must be <em>stateless</em>. Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.
*
* <h3><a name="Non-Interference">Non-interference</a></h3>
*
- * The {@code java.util.stream} package enables you to execute possibly-parallel
- * bulk-data operations over a variety of data sources, including even non-thread-safe
- * collections such as {@code ArrayList}. This is possible only if we can
- * prevent <em>interference</em> with the data source during the execution of a
- * stream pipeline. (Execution begins when the terminal operation is invoked, and ends
- * when the terminal operation completes.) For most data sources, preventing interference
- * means ensuring that the data source is <em>not modified at all</em> during the execution
- * of the stream pipeline. (Some data sources, such as concurrent collections, are
- * specifically designed to handle concurrent modification.)
+ * Streams enable you to execute possibly-parallel aggregate operations over a
+ * variety of data sources, including even non-thread-safe collections such as
+ * {@code ArrayList}. This is possible only if we can prevent
+ * <em>interference</em> with the data source during the execution of a stream
+ * pipeline. Except for the escape-hatch operations {@code iterator()} and
+ * {@code spliterator()}, execution begins when the terminal operation is
+ * invoked, and ends when the terminal operation completes. For most data
+ * sources, preventing interference means ensuring that the data source is
+ * <em>not modified at all</em> during the execution of the stream pipeline.
+ * The notable exception to this are streams whose sources are concurrent
+ * collections, which are specifically designed to handle concurrent modification.
*
- * <p>Accordingly, lambda expressions (or other objects implementing the appropriate functional
- * interface) passed to stream methods should never modify the stream's data source. An
- * implementation is said to <em>interfere</em> with the data source if it modifies, or causes
- * to be modified, the stream's data source. The need for non-interference applies to all
- * pipelines, not just parallel ones. Unless the stream source is concurrent, modifying a
- * stream's data source during execution of a stream pipeline can cause exceptions, incorrect
- * answers, or nonconformant results.
+ * <p>Accordingly, behavioral parameters passed to stream methods should never
+ * modify the stream's data source. An implementation is said to
+ * <em>interfere</em> with the data source if it modifies, or causes to be
+ * modified, the stream's data source. The need for non-interference applies
+ * to all pipelines, not just parallel ones. Unless the stream source is
+ * concurrent, modifying a stream's data source during execution of a stream
+ * pipeline can cause exceptions, incorrect answers, or nonconformant behavior.
*
- * <p>Further, results may be nondeterministic or incorrect if the lambda expressions passed to
- * stream operations are <em>stateful</em>. A stateful lambda (or other object implementing the
- * appropriate functional interface) is one whose result depends on any state which might change
- * during the execution of the stream pipeline. An example of a stateful lambda is:
+ * <p>Results may be nondeterministic or incorrect if the behavioral
+ * parameters of stream operations are <em>stateful</em>. A stateful lambda
+ * (or other object implementing the appropriate functional interface) is one
+ * whose result depends on any state which might change during the execution
+ * of the stream pipeline. An example of a stateful lambda is:
+ *
* <pre>{@code
* Set<Integer> seen = Collections.synchronizedSet(new HashSet<>());
* stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })...
* }</pre>
- * Here, if the mapping operation is performed in parallel, the results for the same input
- * could vary from run to run, due to thread scheduling differences, whereas, with a stateless
- * lambda expression the results would always be the same.
+ *
+ * Here, if the mapping operation is performed in parallel, the results for the
+ * same input could vary from run to run, due to thread scheduling differences,
+ * whereas, with a stateless lambda expression the results would always be the
+ * same.
+ *
+ * For well-behaved stream sources, the source can be modified before the
+ * terminal operation commences and those modifications will be reflected in
+ * the covered elements. For example, consider the following code:
+ *
+ * <pre>{@code
+ * List<String> l = new ArrayList(Arrays.asList("one", "two"));
+ * Stream<String> sl = l.stream();
+ * l.add("three");
+ * String s = sl.collect(joining(" "));
+ * }</pre>
+ *
+ * First a list is created consisting of two strings: "one"; and "two". Then a
+ * stream is created from that list. Next the list is modified by adding a third
+ * string: "three". Finally the elements of the stream are collected and joined
+ * together. Since the list was modified before the terminal {@code collect}
+ * operation commenced the result will be a string of "one two three". All the
+ * streams returned from JDK collections, and most other JDK classes,
+ * are well-behaved in this manner; for streams generated by other libraries, see
+ * <a href="package-summary.html#StreamSources">Low-level stream
+ * construction</a> for requirements for building well-behaved streams.
+ *
+ * <p>Some streams, particularly those whose stream sources are concurrent, can
+ * tolerate concurrent modification during execution of a stream pipeline.
+ * However, in no case -- even if the stream source is concurrent -- should
+ * behavioral parameters to stream operations modify the stream source. Modifying
+ * the stream source from within the stream source may cause pipeline execution
+ * to fail to terminate, produce inaccurate results, or throw exceptions.
+ * The following example shows inappropriate interference with the source:
+ * <pre>{@code
+ * // Don't do this!
+ * List<String> l = new ArrayList(Arrays.asList("one", "two"));
+ * Stream<String> sl = l.stream();
+ * String s = sl.peek(s -> l.add("BAD LAMBDA")).collect(joining(" "));
+ * }</pre>
*
* <h3>Side-effects</h3>
*
+ * Side-effects in behavioral parameters to stream operations are, in general,
+ * discouraged, as they can often lead to unwitting violations of the
+ * statelessness requirement, as well as other thread-safety hazards. Many
+ * computations where one might be tempted to use side effects can be more
+ * safely and efficiently expressed without side-effects, such as using
+ * <a href="package-summary.html#Reduction">reduction</a> instead of mutable
+ * accumulators. However, side-effects such as using {@code println()} for debugging
+ * purposes are usually harmless. A small number of stream operations, such as
+ * {@code forEach()} and {@code peek()}, can operate only via side-effects;
+ * these should be used with care.
+ *
+ * <p>As an example of how to transform a stream pipeline that inappropriately
+ * uses side-effects to one that does not, the following code searches a stream
+ * of strings for those matching a given regular expression, and puts the
+ * matches in a list.
+ *
+ * <pre>{@code
+ * ArrayList<String> results = new ArrayList<>();
+ * stream.filter(s -> pattern.matcher(s).matches())
+ * .forEach(s -> results.add(s)); // Unnecessary use of side-effects!
+ * }</pre>
+ *
+ * This code unnecessarily uses side-effects. If executed in parallel, the
+ * non-thread-safety of {@code ArrayList} would cause incorrect results, and
+ * adding needed synchronization would cause contention, undermining the
+ * benefit of parallelism. Furthermore, using side-effects here is completely
+ * unnecessary; the {@code forEach()} can simply be replaced with a reduction
+ * operation that is safer, more efficient, and more amenable to
+ * parallelization:
+ *
+ * <pre>{@code
+ * List<String>results =
+ * stream.filter(s -> pattern.matcher(s).matches())
+ * .collect(Collectors.toList()); // No side-effects!
+ * }</pre>
+ *
+ * <h3><a name="Ordering">Ordering</a></h3>
+ *
+ * <p>Streams may or may not have a defined <em>encounter order</em>. Whether
+ * or not a stream has an encounter order depends on the source and the
+ * intermediate operations. Certain stream sources (such as {@code List} or
+ * arrays) are intrinsically ordered, whereas others (such as {@code HashSet})
+ * are not. Some intermediate operations, such as {@code sorted()}, may impose
+ * an encounter order on an otherwise unordered stream, and others may render an
+ * ordered stream unordered, such as {@link java.util.stream.BaseStream#unordered()}.
+ * Further, some terminal operations may ignore encounter order, such as
+ * {@code forEach()}.
+ *
+ * <p>If a stream is ordered, most operations are constrained to operate on the
+ * elements in their encounter order; if the source of a stream is a {@code List}
+ * containing {@code [1, 2, 3]}, then the result of executing {@code map(x -> x*2)}
+ * must be {@code [2, 4, 6]}. However, if the source has no defined encounter
+ * order, then any permutation of the values {@code [2, 4, 6]} would be a valid
+ * result.
+ *
+ * <p>For sequential streams, the presence or absence of an encounter order does
+ * not affect performance, only determinism. If a stream is ordered, repeated
+ * execution of identical stream pipelines on an identical source will produce
+ * an identical result; if it is not ordered, repeated execution might produce
+ * different results.
+ *
+ * <p>For parallel streams, relaxing the ordering constraint can sometimes enable
+ * more efficient execution. Certain aggregate operations,
+ * such as filtering duplicates ({@code distinct()}) or grouped reductions
+ * ({@code Collectors.groupingBy()}) can be implemented more efficiently if ordering of elements
+ * is not relevant. Similarly, operations that are intrinsically tied to encounter order,
+ * such as {@code limit()}, may require
+ * buffering to ensure proper ordering, undermining the benefit of parallelism.
+ * In cases where the stream has an encounter order, but the user does not
+ * particularly <em>care</em> about that encounter order, explicitly de-ordering
+ * the stream with {@link java.util.stream.BaseStream#unordered() unordered()} may
+ * improve parallel performance for some stateful or terminal operations.
+ * However, most stream pipelines, such as the "sum of weight of blocks" example
+ * above, still parallelize efficiently even under ordering constraints.
+ *
* <h2><a name="Reduction">Reduction operations</a></h2>
*
- * A <em>reduction</em> operation takes a stream of elements and processes them in a way
- * that reduces to a single value or summary description, such as finding the sum or maximum
- * of a set of numbers. (In more complex scenarios, the reduction operation might need to
- * extract data from the elements before reducing that data to a single value, such as
- * finding the sum of weights of a set of blocks. This would require extracting the weight
- * from each block before summing up the weights.)
+ * A <em>reduction</em> operation (also called a <em>fold</em>) takes a sequence
+ * of input elements and combines them into a single summary result by repeated
+ * application of a combining operation, such as finding the sum or maximum of
+ * a set of numbers, or accumulating elements into a list. The streams classes have
+ * multiple forms of general reduction operations, called
+ * {@link java.util.stream.Stream#reduce(java.util.function.BinaryOperator) reduce()}
+ * and {@link java.util.stream.Stream#collect(java.util.stream.Collector) collect()},
+ * as well as multiple specialized reduction forms such as
+ * {@link java.util.stream.IntStream#sum() sum()}, {@link java.util.stream.IntStream#max() max()},
+ * or {@link java.util.stream.IntStream#count() count()}.
*
- * <p>Of course, such operations can be readily implemented as simple sequential loops, as in:
+ * <p>Of course, such operations can be readily implemented as simple sequential
+ * loops, as in:
* <pre>{@code
* int sum = 0;
* for (int x : numbers) {
* sum += x;
* }
* }</pre>
- * However, there may be a significant advantage to preferring a {@link java.util.stream.Stream#reduce reduce operation}
- * over a mutative accumulation such as the above -- a properly constructed reduce operation is
- * inherently parallelizable so long as the
- * {@link java.util.function.BinaryOperator reduction operaterator}
- * has the right characteristics. Specifically the operator must be
- * <a href="#Associativity">associative</a>. For example, given a
- * stream of numbers for which we want to find the sum, we can write:
+ * However, there are good reasons to prefer a reduce operation
+ * over a mutative accumulation such as the above. Not only is a reduction
+ * "more abstract" -- it operates on the stream as a whole rather than individual
+ * elements -- but a properly constructed reduce operation is inherently
+ * parallelizable, so long as the function(s) used to process the elements
+ * are <a href="package-summary.html#Associativity">associative</a> and
+ * <a href="package-summary.html#NonInterfering">stateless</a>.
+ * For example, given a stream of numbers for which we want to find the sum, we
+ * can write:
* <pre>{@code
- * int sum = numbers.reduce(0, (x,y) -> x+y);
+ * int sum = numbers.stream().reduce(0, (x,y) -> x+y);
* }</pre>
- * or more succinctly:
+ * or:
* <pre>{@code
- * int sum = numbers.reduce(0, Integer::sum);
+ * int sum = numbers.stream().reduce(0, Integer::sum);
* }</pre>
*
- * <p>(The primitive specializations of {@link java.util.stream.Stream}, such as
- * {@link java.util.stream.IntStream}, even have convenience methods for common reductions,
- * such as {@link java.util.stream.IntStream#sum() sum} and {@link java.util.stream.IntStream#max() max},
- * which are implemented as simple wrappers around reduce.)
+ * <p>These reduction operations can run safely in parallel with almost no
+ * modification:
+ * <pre>{@code
+ * int sum = numbers.parallelStream().reduce(0, Integer::sum);
+ * }</pre>
*
- * <p>Reduction parallellizes well since the implementation of {@code reduce} can operate on
- * subsets of the stream in parallel, and then combine the intermediate results to get the final
- * correct answer. Even if you were to use a parallelizable form of the
- * {@link java.util.stream.Stream#forEach(Consumer) forEach()} method
- * in place of the original for-each loop above, you would still have to provide thread-safe
- * updates to the shared accumulating variable {@code sum}, and the required synchronization
- * would likely eliminate any performance gain from parallelism. Using a {@code reduce} method
- * instead removes all of the burden of parallelizing the reduction operation, and the library
- * can provide an efficient parallel implementation with no additional synchronization needed.
+ * <p>Reduction parallellizes well because the implementation
+ * can operate on subsets of the data in parallel, and then combine the
+ * intermediate results to get the final correct answer. (Even if the language
+ * had a "parallel for-each" construct, the mutative accumulation approach would
+ * still required the developer to provide
+ * thread-safe updates to the shared accumulating variable {@code sum}, and
+ * the required synchronization would then likely eliminate any performance gain from
+ * parallelism.) Using {@code reduce()} instead removes all of the
+ * burden of parallelizing the reduction operation, and the library can provide
+ * an efficient parallel implementation with no additional synchronization
+ * required.
*
- * <p>The "blocks" examples shown earlier shows how reduction combines with other operations
- * to replace for loops with bulk operations. If {@code blocks} is a collection of {@code Block}
- * objects, which have a {@code getWeight} method, we can find the heaviest block with:
+ * <p>The "widgets" examples shown earlier shows how reduction combines with
+ * other operations to replace for loops with bulk operations. If {@code widgets}
+ * is a collection of {@code Widget} objects, which have a {@code getWeight} method,
+ * we can find the heaviest widget with:
* <pre>{@code
- * OptionalInt heaviest = blocks.stream()
- * .mapToInt(Block::getWeight)
- * .reduce(Integer::max);
+ * OptionalInt heaviest = widgets.parallelStream()
+ * .mapToInt(Widget::getWeight)
+ * .max();
* }</pre>
*
- * <p>In its more general form, a {@code reduce} operation on elements of type {@code <T>}
- * yielding a result of type {@code <U>} requires three parameters:
+ * <p>In its more general form, a {@code reduce} operation on elements of type
+ * {@code <T>} yielding a result of type {@code <U>} requires three parameters:
* <pre>{@code
* <U> U reduce(U identity,
- * BiFunction<U, ? super T, U> accumlator,
+ * BiFunction<U, ? super T, U> accumulator,
* BinaryOperator<U> combiner);
* }</pre>
- * Here, the <em>identity</em> element is both an initial seed for the reduction, and a default
- * result if there are no elements. The <em>accumulator</em> function takes a partial result and
- * the next element, and produce a new partial result. The <em>combiner</em> function combines
- * the partial results of two accumulators to produce a new partial result, and eventually the
- * final result.
+ * Here, the <em>identity</em> element is both an initial seed value for the reduction
+ * and a default result if there are no input elements. The <em>accumulator</em>
+ * function takes a partial result and the next element, and produces a new
+ * partial result. The <em>combiner</em> function combines two partial results
+ * to produce a new partial result. (The combiner is necessary in parallel
+ * reductions, where the input is partitioned, a partial accumulation computed
+ * for each partition, and then the partial results are combined to produce a
+ * final result.)
*
- * <p>This form is a generalization of the two-argument form, and is also a generalization of
- * the map-reduce construct illustrated above. If we wanted to re-cast the simple {@code sum}
- * example using the more general form, {@code 0} would be the identity element, while
- * {@code Integer::sum} would be both the accumulator and combiner. For the sum-of-weights
- * example, this could be re-cast as:
+ * <p>More formally, the {@code identity} value must be an <em>identity</em> for
+ * the combiner function. This means that for all {@code u},
+ * {@code combiner.apply(identity, u)} is equal to {@code u}. Additionally, the
+ * {@code combiner} function must be <a href="package-summary.html#Associativity">associative</a> and
+ * must be compatible with the {@code accumulator} function: for all {@code u}
+ * and {@code t}, {@code combiner.apply(u, accumulator.apply(identity, t))} must
+ * be {@code equals()} to {@code accumulator.apply(u, t)}.
+ *
+ * <p>The three-argument form is a generalization of the two-argument form,
+ * incorporating a mapping step into the accumulation step. We could
+ * re-cast the simple sum-of-weights example using the more general form as
+ * follows:
* <pre>{@code
- * int sumOfWeights = blocks.stream().reduce(0,
- * (sum, b) -> sum + b.getWeight())
- * Integer::sum);
+ * int sumOfWeights = widgets.stream()
+ * .reduce(0,
+ * (sum, b) -> sum + b.getWeight())
+ * Integer::sum);
* }</pre>
- * though the map-reduce form is more readable and generally preferable. The generalized form
- * is provided for cases where significant work can be optimized away by combining mapping and
- * reducing into a single function.
+ * though the explicit map-reduce form is more readable and therefore should
+ * usually be preferred. The generalized form is provided for cases where
+ * significant work can be optimized away by combining mapping and reducing
+ * into a single function.
*
- * <p>More formally, the {@code identity} value must be an <em>identity</em> for the combiner
- * function. This means that for all {@code u}, {@code combiner.apply(identity, u)} is equal
- * to {@code u}. Additionally, the {@code combiner} function must be
- * <a href="#Associativity">associative</a> and must be compatible with the {@code accumulator}
- * function; for all {@code u} and {@code t}, the following must hold:
- * <pre>{@code
- * combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)
- * }</pre>
+ * <h3><a name="MutableReduction">Mutable reduction</a></h3>
*
- * <h3><a name="MutableReduction">Mutable Reduction</a></h3>
- *
- * A <em>mutable</em> reduction operation is similar to an ordinary reduction, in that it reduces
- * a stream of values to a single value, but instead of producing a distinct single-valued result, it
- * mutates a general <em>result container</em>, such as a {@code Collection} or {@code StringBuilder},
+ * A <em>mutable reduction operation</em> accumulates input elements into a
+ * mutable result container, such as a {@code Collection} or {@code StringBuilder},
* as it processes the elements in the stream.
*
- * <p>For example, if we wanted to take a stream of strings and concatenate them into a single
- * long string, we <em>could</em> achieve this with ordinary reduction:
+ * <p>If we wanted to take a stream of strings and concatenate them into a
+ * single long string, we <em>could</em> achieve this with ordinary reduction:
* <pre>{@code
* String concatenated = strings.reduce("", String::concat)
* }</pre>
*
- * We would get the desired result, and it would even work in parallel. However, we might not
- * be happy about the performance! Such an implementation would do a great deal of string
- * copying, and the run time would be <em>O(n^2)</em> in the number of elements. A more
- * performant approach would be to accumulate the results into a {@link java.lang.StringBuilder}, which
- * is a mutable container for accumulating strings. We can use the same technique to
+ * <p>We would get the desired result, and it would even work in parallel. However,
+ * we might not be happy about the performance! Such an implementation would do
+ * a great deal of string copying, and the run time would be <em>O(n^2)</em> in
+ * the number of characters. A more performant approach would be to accumulate
+ * the results into a {@link java.lang.StringBuilder}, which is a mutable
+ * container for accumulating strings. We can use the same technique to
* parallelize mutable reduction as we do with ordinary reduction.
*
- * <p>The mutable reduction operation is called {@link java.util.stream.Stream#collect(Collector) collect()}, as it
- * collects together the desired results into a result container such as {@code StringBuilder}.
- * A {@code collect} operation requires three things: a factory function which will construct
- * new instances of the result container, an accumulating function that will update a result
- * container by incorporating a new element, and a combining function that can take two
- * result containers and merge their contents. The form of this is very similar to the general
+ * <p>The mutable reduction operation is called
+ * {@link java.util.stream.Stream#collect(Collector) collect()},
+ * as it collects together the desired results into a result container such
+ * as a {@code Collection}.
+ * A {@code collect} operation requires three functions:
+ * a supplier function to construct new instances of the result container, an
+ * accumulator function to incorporate an input element into a result
+ * container, and a combining function to merge the contents of one result
+ * container into another. The form of this is very similar to the general
* form of ordinary reduction:
* <pre>{@code
- * <R> R collect(Supplier<R> resultFactory,
+ * <R> R collect(Supplier<R> supplier,
* BiConsumer<R, ? super T> accumulator,
* BiConsumer<R, R> combiner);
* }</pre>
- * As with {@code reduce()}, the benefit of expressing {@code collect} in this abstract way is
- * that it is directly amenable to parallelization: we can accumulate partial results in parallel
- * and then combine them. For example, to collect the String representations of the elements
- * in a stream into an {@code ArrayList}, we could write the obvious sequential for-each form:
+ * <p>As with {@code reduce()}, a benefit of expressing {@code collect} in this
+ * abstract way is that it is directly amenable to parallelization: we can
+ * accumulate partial results in parallel and then combine them, so long as the
+ * accumulation and combining functions satisfy the appropriate requirements.
+ * For example, to collect the String representations of the elements in a
+ * stream into an {@code ArrayList}, we could write the obvious sequential
+ * for-each form:
* <pre>{@code
* ArrayList<String> strings = new ArrayList<>();
* for (T element : stream) {
@@ -377,92 +515,108 @@
* (c, e) -> c.add(e.toString()),
* (c1, c2) -> c1.addAll(c2));
* }</pre>
- * or, noting that we have buried a mapping operation inside the accumulator function, more
- * succinctly as:
- * <pre>{@code
- * ArrayList<String> strings = stream.map(Object::toString)
- * .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
- * }</pre>
- * Here, our supplier is just the {@link java.util.ArrayList#ArrayList() ArrayList constructor}, the
- * accumulator adds the stringified element to an {@code ArrayList}, and the combiner simply
- * uses {@link java.util.ArrayList#addAll addAll} to copy the strings from one container into the other.
- *
- * <p>As with the regular reduction operation, the ability to parallelize only comes if an
- * <a href="package-summary.html#Associativity">associativity</a> condition is met. The {@code combiner} is associative
- * if for result containers {@code r1}, {@code r2}, and {@code r3}:
- * <pre>{@code
- * combiner.accept(r1, r2);
- * combiner.accept(r1, r3);
- * }</pre>
- * is equivalent to
- * <pre>{@code
- * combiner.accept(r2, r3);
- * combiner.accept(r1, r2);
- * }</pre>
- * where equivalence means that {@code r1} is left in the same state (according to the meaning
- * of {@link java.lang.Object#equals equals} for the element types). Similarly, the {@code resultFactory}
- * must act as an <em>identity</em> with respect to the {@code combiner} so that for any result
- * container {@code r}:
+ * or, pulling the mapping operation out of the accumulator function, we could
+ * express it more succinctly as:
* <pre>{@code
- * combiner.accept(r, resultFactory.get());
+ * List<String> strings = stream.map(Object::toString)
+ * .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
* }</pre>
- * does not modify the state of {@code r} (again according to the meaning of
- * {@link java.lang.Object#equals equals}). Finally, the {@code accumulator} and {@code combiner} must be
- * compatible such that for a result container {@code r} and element {@code t}:
- * <pre>{@code
- * r2 = resultFactory.get();
- * accumulator.accept(r2, t);
- * combiner.accept(r, r2);
- * }</pre>
- * is equivalent to:
+ * Here, our supplier is just the {@link java.util.ArrayList#ArrayList()
+ * ArrayList constructor}, the accumulator adds the stringified element to an
+ * {@code ArrayList}, and the combiner simply uses {@link java.util.ArrayList#addAll addAll}
+ * to copy the strings from one container into the other.
+ *
+ * <p>The three aspects of {@code collect} -- supplier, accumulator, and
+ * combiner -- are tightly coupled. We can use the abstraction of a
+ * {@link java.util.stream.Collector} to capture all three aspects. The
+ * above example for collecting strings into a {@code List} can be rewritten
+ * using a standard {@code Collector} as:
* <pre>{@code
- * accumulator.accept(r,t);
+ * List<String> strings = stream.map(Object::toString)
+ * .collect(Collectors.toList());
* }</pre>
- * where equivalence means that {@code r} is left in the same state (again according to the
- * meaning of {@link java.lang.Object#equals equals}).
*
- * <p> The three aspects of {@code collect}: supplier, accumulator, and combiner, are often very
- * tightly coupled, and it is convenient to introduce the notion of a {@link java.util.stream.Collector} as
- * being an object that embodies all three aspects. There is a {@link java.util.stream.Stream#collect(Collector) collect}
- * method that simply takes a {@code Collector} and returns the resulting container.
- * The above example for collecting strings into a {@code List} can be rewritten using a
- * standard {@code Collector} as:
+ * <p>Packaging mutable reductions into a Collector has another advantage:
+ * composability. The class {@link java.util.stream.Collectors} contains a
+ * number of predefined factories for collectors, including combinators
+ * that transform one collector into another. For example, suppose we have a
+ * collector that computes the sum of the salaries of a stream of
+ * employees, as follows:
+ *
* <pre>{@code
- * ArrayList<String> strings = stream.map(Object::toString)
- * .collect(Collectors.toList());
+ * Collector<Employee, ?, Integer> summingSalaries
+ * = Collectors.summingInt(Employee::getSalary);
* }</pre>
*
- * <h3><a name="ConcurrentReduction">Reduction, Concurrency, and Ordering</a></h3>
+ * (The {@code ?} for the second type parameter merely indicates that we don't
+ * care about the intermediate representation used by this collector.)
+ * If we wanted to create a collector to tabulate the sum of salaries by
+ * department, we could reuse {@code summingSalaries} using
+ * {@link java.util.stream.Collectors#groupingBy(java.util.function.Function, java.util.stream.Collector) groupingBy}:
+ *
+ * <pre>{@code
+ * Map<Department, Integer> salariesByDept
+ * = employees.stream().collect(Collectors.groupingBy(Employee::getDepartment,
+ * summingSalaries));
+ * }</pre>
+ *
+ * <p>As with the regular reduction operation, {@code collect()} operations can
+ * only be parallelized if appropriate conditions are met. For any partially
+ * accumulated result, combining it with an empty result container must
+ * produce an equivalent result. That is, for a partially accumulated result
+ * {@code p} that is the result of any series of accumulator and combiner
+ * invocations, {@code p} must be equivalent to
+ * {@code combiner.apply(p, supplier.get())}.
*
- * With some complex reduction operations, for example a collect that produces a
- * {@code Map}, such as:
+ * <p>Further, however the computation is split, it must produce an equivalent
+ * result. For any input elements {@code t1} and {@code t2}, the results
+ * {@code r1} and {@code r2} in the computation below must be equivalent:
+ * <pre>{@code
+ * A a1 = supplier.get();
+ * accumulator.accept(a1, t1);
+ * accumulator.accept(a1, t2);
+ * R r1 = finisher.apply(a1); // result without splitting
+ *
+ * A a2 = supplier.get();
+ * accumulator.accept(a2, t1);
+ * A a3 = supplier.get();
+ * accumulator.accept(a3, t2);
+ * R r2 = finisher.apply(combiner.apply(a2, a3)); // result with splitting
+ * }</pre>
+ *
+ * <p>Here, equivalence generally means according to {@link java.lang.Object#equals(Object)}.
+ * but in some cases equivalence may be relaxed to account for differences in
+ * order.
+ *
+ * <h3><a name="ConcurrentReduction">Reduction, concurrency, and ordering</a></h3>
+ *
+ * With some complex reduction operations, for example a {@code collect()} that
+ * produces a {@code Map}, such as:
* <pre>{@code
* Map<Buyer, List<Transaction>> salesByBuyer
* = txns.parallelStream()
* .collect(Collectors.groupingBy(Transaction::getBuyer));
* }</pre>
- * (where {@link java.util.stream.Collectors#groupingBy} is a utility function
- * that returns a {@link java.util.stream.Collector} for grouping sets of elements based on some key)
* it may actually be counterproductive to perform the operation in parallel.
- * This is because the combining step (merging one {@code Map} into another by key)
- * can be expensive for some {@code Map} implementations.
+ * This is because the combining step (merging one {@code Map} into another by
+ * key) can be expensive for some {@code Map} implementations.
*
* <p>Suppose, however, that the result container used in this reduction
* was a concurrently modifiable collection -- such as a
- * {@link java.util.concurrent.ConcurrentHashMap ConcurrentHashMap}. In that case,
- * the parallel invocations of the accumulator could actually deposit their results
- * concurrently into the same shared result container, eliminating the need for the combiner to
- * merge distinct result containers. This potentially provides a boost
- * to the parallel execution performance. We call this a <em>concurrent</em> reduction.
+ * {@link java.util.concurrent.ConcurrentHashMap}. In that case, the parallel
+ * invocations of the accumulator could actually deposit their results
+ * concurrently into the same shared result container, eliminating the need for
+ * the combiner to merge distinct result containers. This potentially provides
+ * a boost to the parallel execution performance. We call this a
+ * <em>concurrent</em> reduction.
*
- * <p>A {@link java.util.stream.Collector} that supports concurrent reduction is marked with the
- * {@link java.util.stream.Collector.Characteristics#CONCURRENT} characteristic.
- * Having a concurrent collector is a necessary condition for performing a
- * concurrent reduction, but that alone is not sufficient. If you imagine multiple
- * accumulators depositing results into a shared container, the order in which
- * results are deposited is non-deterministic. Consequently, a concurrent reduction
- * is only possible if ordering is not important for the stream being processed.
- * The {@link java.util.stream.Stream#collect(Collector)}
+ * <p>A {@link java.util.stream.Collector} that supports concurrent reduction is
+ * marked with the {@link java.util.stream.Collector.Characteristics#CONCURRENT}
+ * characteristic. However, a concurrent collection also has a downside. If
+ * multiple threads are depositing results concurrently into a shared container,
+ * the order in which results are deposited is non-deterministic. Consequently,
+ * a concurrent reduction is only possible if ordering is not important for the
+ * stream being processed. The {@link java.util.stream.Stream#collect(Collector)}
* implementation will only perform a concurrent reduction if
* <ul>
* <li>The stream is parallel;</li>
@@ -472,95 +626,100 @@
* <li>Either the stream is unordered, or the collector has the
* {@link java.util.stream.Collector.Characteristics#UNORDERED} characteristic.
* </ul>
- * For example:
+ * You can ensure the stream is unordered by using the
+ * {@link java.util.stream.BaseStream#unordered()} method. For example:
* <pre>{@code
* Map<Buyer, List<Transaction>> salesByBuyer
* = txns.parallelStream()
* .unordered()
* .collect(groupingByConcurrent(Transaction::getBuyer));
* }</pre>
- * (where {@link java.util.stream.Collectors#groupingByConcurrent} is the concurrent companion
- * to {@code groupingBy}).
+ * (where {@link java.util.stream.Collectors#groupingByConcurrent} is the
+ * concurrent equivalent of {@code groupingBy}).
*
- * <p>Note that if it is important that the elements for a given key appear in the
- * order they appear in the source, then we cannot use a concurrent reduction,
- * as ordering is one of the casualties of concurrent insertion. We would then
- * be constrained to implement either a sequential reduction or a merge-based
- * parallel reduction.
+ * <p>Note that if it is important that the elements for a given key appear in
+ * the order they appear in the source, then we cannot use a concurrent
+ * reduction, as ordering is one of the casualties of concurrent insertion.
+ * We would then be constrained to implement either a sequential reduction or
+ * a merge-based parallel reduction.
*
- * <h2><a name="Associativity">Associativity</a></h2>
+ * <h3><a name="Associativity">Associativity</a></h3>
*
- * An operator or function {@code op} is <em>associative</em> if the following holds:
+ * An operator or function {@code op} is <em>associative</em> if the following
+ * holds:
* <pre>{@code
* (a op b) op c == a op (b op c)
* }</pre>
- * The importance of this to parallel evaluation can be seen if we expand this to four terms:
+ * The importance of this to parallel evaluation can be seen if we expand this
+ * to four terms:
* <pre>{@code
* a op b op c op d == (a op b) op (c op d)
* }</pre>
- * So we can evaluate {@code (a op b)} in parallel with {@code (c op d)} and then invoke {@code op} on
- * the results.
- * TODO what does associative mean for mutative combining functions?
- * FIXME: we described mutative associativity above.
+ * So we can evaluate {@code (a op b)} in parallel with {@code (c op d)}, and
+ * then invoke {@code op} on the results.
*
- * <h2><a name="StreamSources">Stream sources</a></h2>
- * TODO where does this section go?
+ * <p>Examples of associative operations include numeric addition, min, and
+ * max, and string concatenation.
+ *
+ * <h2><a name="StreamSources">Low-level stream construction</a></h2>
*
- * XXX - change to section to stream construction gradually introducing more
- * complex ways to construct
- * - construction from Collection
- * - construction from Iterator
- * - construction from array
- * - construction from generators
- * - construction from spliterator
+ * So far, all the stream examples have used methods like
+ * {@link java.util.Collection#stream()} or {@link java.util.Arrays#stream(Object[])}
+ * to obtain a stream. How are those stream-bearing methods implemented?
+ *
+ * <p>The class {@link java.util.stream.StreamSupport} has a number of
+ * low-level methods for creating a stream, all using some form of a
+ * {@link java.util.Spliterator}. A spliterator is the parallel analogue of an
+ * {@link java.util.Iterator}; it describes a (possibly infinite) collection of
+ * elements, with support for sequentially advancing, bulk traversal, and
+ * splitting off some portion of the input into another spliterator which can
+ * be processed in parallel. At the lowest level, all streams are driven by a
+ * spliterator.
*
- * XXX - the following is quite low-level but important aspect of stream constriction
- *
- * <p>A pipeline is initially constructed from a spliterator (see {@link java.util.Spliterator}) supplied by a stream source.
- * The spliterator covers elements of the source and provides element traversal operations
- * for a possibly-parallel computation. See methods on {@link java.util.stream.Streams} for construction
- * of pipelines using spliterators.
+ * <p>There are a number of implementation choices in implementing a
+ * spliterator, nearly all of which are tradeoffs between simplicity of
+ * implementation and runtime performance of streams using that spliterator.
+ * The simplest, but least performant, way to create a spliterator is to
+ * create one from an iterator using
+ * {@link java.util.Spliterators#spliteratorUnknownSize(java.util.Iterator, int)}.
+ * While such a spliterator will work, it will likely offer poor parallel
+ * performance, since we have lost sizing information (how big is the
+ * underlying data set), as well as being constrained to a simplistic
+ * splitting algorithm.
*
- * <p>A source may directly supply a spliterator. If so, the spliterator is traversed, split, or queried
- * for estimated size after, and never before, the terminal operation commences. It is strongly recommended
- * that the spliterator report a characteristic of {@code IMMUTABLE} or {@code CONCURRENT}, or be
- * <em>late-binding</em> and not bind to the elements it covers until traversed, split or queried for
- * estimated size.
+ * <p>A higher-quality spliterator will provide balanced and known-size
+ * splits, accurate sizing information, and a number of other
+ * {@link java.util.Spliterator#characteristics() characteristics} of the
+ * spliterator or data that can be used by implementations to optimize
+ * execution.
*
- * <p>If a source cannot directly supply a recommended spliterator then it may indirectly supply a spliterator
- * using a {@code Supplier}. The spliterator is obtained from the supplier after, and never before, the terminal
+ * <p>Spliterators for mutable data sources have an additional challenge;
+ * timing of binding to the data, since the data could change between the time
+ * the spliterator is created and the time the stream pipeline is executed.
+ * Ideally, a spliterator for a stream would report a characteristic of
+
+ * {@code IMMUTABLE} or {@code CONCURRENT}; if not it should be
+ * <a href="../Spliterator.html#binding"><em>late-binding</em></a>. If a source
+ * cannot directly supply a recommended spliterator, it may indirectly supply
+ * a spliterator using a {@code Supplier}, and construct a stream via the
+ * {@code Supplier}-accepting versions of
+ * {@link java.util.stream.StreamSupport#stream(Supplier, int, boolean) stream()}.
+ * The spliterator is obtained from the supplier only after the terminal
* operation of the stream pipeline commences.
*
- * <p>Such requirements significantly reduce the scope of potential interference to the interval starting
- * with the commencing of the terminal operation and ending with the producing a result or side-effect. See
- * <a href="package-summary.html#Non-Interference">Non-Interference</a> for
- * more details.
- *
- * XXX - move the following to the non-interference section
- *
- * <p>A source can be modified before the terminal operation commences and those modifications will be reflected in
- * the covered elements. Afterwards, and depending on the properties of the source, further modifications
- * might not be reflected and the throwing of a {@code ConcurrentModificationException} may occur.
+ * <p>These requirements significantly reduce the scope of potential
+ * interference between mutations of the stream source and execution of stream
+ * pipelines. Streams based on spliterators with the desired characteristics,
+ * or those using the Supplier-based factory forms, are immune to
+ * modifications of the data source prior to commencement of the terminal
+ * operation (provided the behavioral parameters to the stream operations meet
+ * the required criteria for non-interference and statelessness). See
+ * <a href="package-summary.html#Non-Interference">Non-Interference</a>
+ * for more details.
*
- * <p>For example, consider the following code:
- * <pre>{@code
- * List<String> l = new ArrayList(Arrays.asList("one", "two"));
- * Stream<String> sl = l.stream();
- * l.add("three");
- * String s = sl.collect(joining(" "));
- * }</pre>
- * First a list is created consisting of two strings: "one"; and "two". Then a stream is created from that list.
- * Next the list is modified by adding a third string: "three". Finally the elements of the stream are collected
- * and joined together. Since the list was modified before the terminal {@code collect} operation commenced
- * the result will be a string of "one two three". However, if the list is modified after the terminal operation
- * commences, as in:
- * <pre>{@code
- * List<String> l = new ArrayList(Arrays.asList("one", "two"));
- * Stream<String> sl = l.stream();
- * String s = sl.peek(s -> l.add("BAD LAMBDA")).collect(joining(" "));
- * }</pre>
- * then a {@code ConcurrentModificationException} will be thrown since the {@code peek} operation will attempt
- * to add the string "BAD LAMBDA" to the list after the terminal operation has commenced.
+ * @since 1.8
*/
+package java.util.stream;
-package java.util.stream;
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
--- a/jdk/src/share/classes/java/util/zip/Deflater.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/zip/Deflater.java Sat Sep 14 20:43:34 2013 +0100
@@ -261,6 +261,12 @@
/**
* Sets the compression strategy to the specified value.
+ *
+ * <p> If the compression strategy is changed, the next invocation
+ * of {@code deflate} will compress the input available so far with
+ * the old strategy (and may be flushed); the new strategy will take
+ * effect only after that invocation.
+ *
* @param strategy the new compression strategy
* @exception IllegalArgumentException if the compression strategy is
* invalid
@@ -283,7 +289,13 @@
}
/**
- * Sets the current compression level to the specified value.
+ * Sets the compression level to the specified value.
+ *
+ * <p> If the compression level is changed, the next invocation
+ * of {@code deflate} will compress the input available so far
+ * with the old level (and may be flushed); the new level will
+ * take effect only after that invocation.
+ *
* @param level the new compression level (0-9)
* @exception IllegalArgumentException if the compression level is invalid
*/
--- a/jdk/src/share/classes/java/util/zip/ZipConstants.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/zip/ZipConstants.java Sat Sep 14 20:43:34 2013 +0100
@@ -69,21 +69,6 @@
static final int EXTLEN = 12; // uncompressed size
/*
- * Extra field header ID
- */
- static final int EXTID_ZIP64 = 0x0001; // Zip64
- static final int EXTID_NTFS = 0x000a; // NTFS
- static final int EXTID_UNIX = 0x000d; // UNIX
- static final int EXTID_EXTT = 0x5455; // Info-ZIP Extended Timestamp
-
- /*
- * EXTT timestamp flags
- */
- static final int EXTT_FLAG_LMT = 0x1; // LastModifiedTime
- static final int EXTT_FLAG_LAT = 0x2; // LastAccessTime
- static final int EXTT_FLAT_CT = 0x4; // CreationTime
-
- /*
* Central directory (CEN) header field offsets
*/
static final int CENVEM = 4; // version made by
--- a/jdk/src/share/classes/java/util/zip/ZipConstants64.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/zip/ZipConstants64.java Sat Sep 14 20:43:34 2013 +0100
@@ -80,5 +80,26 @@
// comment fields for this file must be
// encoded using UTF-8.
+ /*
+ * Constants below are defined here (instead of in ZipConstants)
+ * to avoid being exposed as public fields of ZipFile, ZipEntry,
+ * ZipInputStream and ZipOutputstream.
+ */
+
+ /*
+ * Extra field header ID
+ */
+ static final int EXTID_ZIP64 = 0x0001; // Zip64
+ static final int EXTID_NTFS = 0x000a; // NTFS
+ static final int EXTID_UNIX = 0x000d; // UNIX
+ static final int EXTID_EXTT = 0x5455; // Info-ZIP Extended Timestamp
+
+ /*
+ * EXTT timestamp flags
+ */
+ static final int EXTT_FLAG_LMT = 0x1; // LastModifiedTime
+ static final int EXTT_FLAG_LAT = 0x2; // LastAccessTime
+ static final int EXTT_FLAT_CT = 0x4; // CreationTime
+
private ZipConstants64() {}
}
--- a/jdk/src/share/classes/java/util/zip/ZipEntry.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/java/util/zip/ZipEntry.java Sat Sep 14 20:43:34 2013 +0100
@@ -30,6 +30,8 @@
import java.util.Objects;
import java.util.concurrent.TimeUnit;
+import static java.util.zip.ZipConstants64.*;
+
/**
* This class is used to represent a ZIP file entry.
*
--- a/jdk/src/share/classes/javax/management/MBeanAttributeInfo.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/javax/management/MBeanAttributeInfo.java Sat Sep 14 20:43:34 2013 +0100
@@ -30,6 +30,7 @@
import com.sun.jmx.mbeanserver.GetPropertyAction;
import com.sun.jmx.mbeanserver.Introspector;
+import java.util.Objects;
/**
@@ -301,7 +302,7 @@
right and we needlessly hashed in the description and parameter
array. */
public int hashCode() {
- return getName().hashCode() ^ getType().hashCode();
+ return Objects.hash(getName(), getType());
}
private static boolean isIs(Method getter) {
--- a/jdk/src/share/classes/javax/management/MBeanConstructorInfo.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/javax/management/MBeanConstructorInfo.java Sat Sep 14 20:43:34 2013 +0100
@@ -29,6 +29,7 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.Arrays;
+import java.util.Objects;
/**
* Describes a constructor exposed by an MBean. Instances of this
@@ -203,11 +204,7 @@
quite long and yet the same between constructors. Likewise for
the descriptor. */
public int hashCode() {
- int hash = getName().hashCode();
- MBeanParameterInfo[] sig = fastGetSignature();
- for (int i = 0; i < sig.length; i++)
- hash ^= sig[i].hashCode();
- return hash;
+ return Objects.hash(getName()) ^ Arrays.hashCode(fastGetSignature());
}
private static MBeanParameterInfo[] constructorSignature(Constructor<?> cn) {
--- a/jdk/src/share/classes/javax/management/MBeanInfo.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/javax/management/MBeanInfo.java Sat Sep 14 20:43:34 2013 +0100
@@ -36,6 +36,7 @@
import java.util.WeakHashMap;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.Objects;
import static javax.management.ImmutableDescriptor.nonNullDescriptor;
@@ -515,24 +516,15 @@
if (hashCode != 0)
return hashCode;
- hashCode =
- getClassName().hashCode() ^
- getDescriptor().hashCode() ^
- arrayHashCode(fastGetAttributes()) ^
- arrayHashCode(fastGetOperations()) ^
- arrayHashCode(fastGetConstructors()) ^
- arrayHashCode(fastGetNotifications());
+ hashCode = Objects.hash(getClassName(), getDescriptor())
+ ^ Arrays.hashCode(fastGetAttributes())
+ ^ Arrays.hashCode(fastGetOperations())
+ ^ Arrays.hashCode(fastGetConstructors())
+ ^ Arrays.hashCode(fastGetNotifications());
return hashCode;
}
- private static int arrayHashCode(Object[] array) {
- int hash = 0;
- for (int i = 0; i < array.length; i++)
- hash ^= array[i].hashCode();
- return hash;
- }
-
/**
* Cached results of previous calls to arrayGettersSafe. This is
* a WeakHashMap so that we don't prevent a class from being
--- a/jdk/src/share/classes/javax/management/MBeanOperationInfo.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/javax/management/MBeanOperationInfo.java Sat Sep 14 20:43:34 2013 +0100
@@ -29,6 +29,7 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
+import java.util.Objects;
/**
* Describes a management operation exposed by an MBean. Instances of
@@ -309,7 +310,7 @@
parameter array. */
@Override
public int hashCode() {
- return getName().hashCode() ^ getReturnType().hashCode();
+ return Objects.hash(getName(), getReturnType());
}
private static MBeanParameterInfo[] methodSignature(Method method) {
--- a/jdk/src/share/classes/javax/management/MBeanParameterInfo.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/javax/management/MBeanParameterInfo.java Sat Sep 14 20:43:34 2013 +0100
@@ -25,6 +25,7 @@
package javax.management;
+import java.util.Objects;
/**
* Describes an argument of an operation exposed by an MBean.
@@ -143,6 +144,6 @@
}
public int hashCode() {
- return getName().hashCode() ^ getType().hashCode();
+ return Objects.hash(getName(), getType());
}
}
--- a/jdk/src/share/classes/javax/management/openmbean/OpenMBeanInfoSupport.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/javax/management/openmbean/OpenMBeanInfoSupport.java Sat Sep 14 20:43:34 2013 +0100
@@ -31,6 +31,7 @@
//
import java.util.Arrays;
import java.util.HashSet;
+import java.util.Objects;
import javax.management.Descriptor;
import javax.management.MBeanAttributeInfo;
@@ -269,8 +270,9 @@
//
// their MBean className should be equal
- if ( ! this.getClassName().equals(other.getClassName()) )
+ if (!Objects.equals(this.getClassName(), other.getClassName())) {
return false;
+ }
// their infos on attributes should be equal (order not
// significant => equality between sets, not arrays or lists)
@@ -342,7 +344,9 @@
//
if (myHashCode == null) {
int value = 0;
- value += this.getClassName().hashCode();
+ if (this.getClassName() != null) {
+ value += this.getClassName().hashCode();
+ }
value += arraySetHash(this.getAttributes());
value += arraySetHash(this.getConstructors());
value += arraySetHash(this.getOperations());
--- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java Sat Sep 14 20:43:34 2013 +0100
@@ -405,14 +405,7 @@
throw new IOException("Not connected");
}
- MBeanServerConnection rmbsc = rmbscMap.get(delegationSubject);
- if (rmbsc != null) {
- return rmbsc;
- }
-
- rmbsc = new RemoteMBeanServerConnection(delegationSubject);
- rmbscMap.put(delegationSubject, rmbsc);
- return rmbsc;
+ return getConnectionWithSubject(delegationSubject);
}
public void
@@ -1831,7 +1824,7 @@
// Initialization of transient variables.
private void initTransients() {
- rmbscMap = new WeakHashMap<Subject, MBeanServerConnection>();
+ rmbscMap = new WeakHashMap<Subject, WeakReference<MBeanServerConnection>>();
connected = false;
terminated = false;
@@ -2011,6 +2004,25 @@
private final ClassLoader loader;
}
+ private MBeanServerConnection getConnectionWithSubject(Subject delegationSubject) {
+ MBeanServerConnection conn = null;
+
+ if (delegationSubject == null) {
+ if (nullSubjectConnRef == null
+ || (conn = nullSubjectConnRef.get()) == null) {
+ conn = new RemoteMBeanServerConnection(null);
+ nullSubjectConnRef = new WeakReference(conn);
+ }
+ } else {
+ WeakReference<MBeanServerConnection> wr = rmbscMap.get(delegationSubject);
+ if (wr == null || (conn = wr.get()) == null) {
+ conn = new RemoteMBeanServerConnection(delegationSubject);
+ rmbscMap.put(delegationSubject, new WeakReference(conn));
+ }
+ }
+ return conn;
+ }
+
/*
The following section of code avoids a class loading problem
with RMI. The problem is that an RMI stub, when deserializing
@@ -2551,7 +2563,8 @@
private transient long clientNotifSeqNo = 0;
- private transient WeakHashMap<Subject, MBeanServerConnection> rmbscMap;
+ private transient WeakHashMap<Subject, WeakReference<MBeanServerConnection>> rmbscMap;
+ private transient WeakReference<MBeanServerConnection> nullSubjectConnRef = null;
private transient RMINotifClient rmiNotifClient;
// = new RMINotifClient(new Integer(0));
--- a/jdk/src/share/classes/javax/net/ssl/SSLParameters.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/javax/net/ssl/SSLParameters.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -40,7 +40,7 @@
* the list of protocols to be allowed, the endpoint identification
* algorithm during SSL/TLS handshaking, the Server Name Indication (SNI),
* the algorithm constraints and whether SSL/TLS servers should request
- * or require client authentication.
+ * or require client authentication, etc.
* <p>
* SSLParameters can be created via the constructors in this class.
* Objects can also be obtained using the <code>getSSLParameters()</code>
@@ -73,13 +73,14 @@
private AlgorithmConstraints algorithmConstraints;
private Map<Integer, SNIServerName> sniNames = null;
private Map<Integer, SNIMatcher> sniMatchers = null;
+ private boolean preferLocalCipherSuites;
/**
* Constructs SSLParameters.
* <p>
* The values of cipherSuites, protocols, cryptographic algorithm
* constraints, endpoint identification algorithm, server names and
- * server name matchers are set to <code>null</code>,
+ * server name matchers are set to <code>null</code>, useCipherSuitesOrder,
* wantClientAuth and needClientAuth are set to <code>false</code>.
*/
public SSLParameters() {
@@ -434,5 +435,34 @@
return null;
}
+
+ /**
+ * Sets whether the local cipher suites preference should be honored.
+ *
+ * @param honorOrder whether local cipher suites order in
+ * {@code #getCipherSuites} should be honored during
+ * SSL/TLS handshaking.
+ *
+ * @see #getUseCipherSuitesOrder()
+ *
+ * @since 1.8
+ */
+ public final void setUseCipherSuitesOrder(boolean honorOrder) {
+ this.preferLocalCipherSuites = honorOrder;
+ }
+
+ /**
+ * Returns whether the local cipher suites preference should be honored.
+ *
+ * @return whether local cipher suites order in {@code #getCipherSuites}
+ * should be honored during SSL/TLS handshaking.
+ *
+ * @see #setUseCipherSuitesOrder(boolean)
+ *
+ * @since 1.8
+ */
+ public final boolean getUseCipherSuitesOrder() {
+ return preferLocalCipherSuites;
+ }
}
--- a/jdk/src/share/classes/javax/security/auth/Subject.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/javax/security/auth/Subject.java Sat Sep 14 20:43:34 2013 +0100
@@ -1186,7 +1186,7 @@
}
public boolean removeAll(Collection<?> c) {
-
+ Objects.requireNonNull(c);
boolean modified = false;
final Iterator<E> e = iterator();
while (e.hasNext()) {
@@ -1222,7 +1222,7 @@
}
public boolean retainAll(Collection<?> c) {
-
+ Objects.requireNonNull(c);
boolean modified = false;
boolean retain = false;
final Iterator<E> e = iterator();
--- a/jdk/src/share/classes/javax/sql/rowset/Predicate.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/javax/sql/rowset/Predicate.java Sat Sep 14 20:43:34 2013 +0100
@@ -56,44 +56,43 @@
* <pre>{@code
* public class Range implements Predicate {
*
- * private Object lo[];
- * private Object hi[];
- * private int idx[];
+ * private int[] lo;
+ * private int[] hi;
+ * private int[] idx;
*
- * public Range(Object[] lo, Object[] hi, int[] idx) {
+ * public Range(int[] lo, int[] hi, int[] idx) {
* this.lo = lo;
* this.hi = hi;
* this.idx = idx;
* }
*
* public boolean evaluate(RowSet rs) {
- * CachedRowSet crs = (CachedRowSet)rs;
- * boolean bool1,bool2;
*
* // Check the present row determine if it lies
* // within the filtering criteria.
*
* for (int i = 0; i < idx.length; i++) {
+ * int value;
+ * try {
+ * value = (Integer) rs.getObject(idx[i]);
+ * } catch (SQLException ex) {
+ * Logger.getLogger(Range.class.getName()).log(Level.SEVERE, null, ex);
+ * return false;
+ * }
*
- * if ((rs.getObject(idx[i]) >= lo[i]) &&
- * (rs.getObject(idx[i]) >= hi[i]) {
- * bool1 = true; // within filter constraints
- * } else {
- * bool2 = true; // outside of filter constraints
- * }
- * }
- *
- * if (bool2) {
- * return false;
- * } else {
- * return true;
- * }
+ * if (value < lo[i] && value > hi[i]) {
+ * // outside of filter constraints
+ * return false;
+ * }
+ * }
+ * // Within filter constraints
+ * return true;
* }
- * }
+ * }
* }</pre>
* <P>
* The example above implements a simple range predicate. Note, that
- * implementations should but are not required to provider <code>String</code>
+ * implementations should but are not required to provide <code>String</code>
* and integer index based constructors to provide for JDBC RowSet Implementation
* applications that use both column identification conventions.
*
--- a/jdk/src/share/classes/sun/applet/AppletSecurity.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/applet/AppletSecurity.java Sat Sep 14 20:43:34 2013 +0100
@@ -314,7 +314,7 @@
// If we're about to allow access to the main EventQueue,
// and anything untrusted is on the class context stack,
// disallow access.
- super.checkAwtEventQueueAccess();
+ super.checkPermission(SecurityConstants.AWT.CHECK_AWT_EVENTQUEUE_PERMISSION);
}
} // checkAwtEventQueueAccess()
--- a/jdk/src/share/classes/sun/awt/AppContext.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/awt/AppContext.java Sat Sep 14 20:43:34 2013 +0100
@@ -838,21 +838,59 @@
public boolean isMainAppContext() {
return (numAppContexts.get() == 1 && mainAppContext != null);
}
- public Object getContext() {
- return getAppContext();
- }
- public Object getExecutionContext() {
- return getExecutionAppContext();
+
+ /**
+ * Returns the AppContext used for applet logging isolation, or null if
+ * the default global context can be used.
+ * If there's no applet, or if the caller is a stand alone application,
+ * or running in the main app context, returns null.
+ * Otherwise, returns the AppContext of the calling applet.
+ * @return null if the global default context can be used,
+ * an AppContext otherwise.
+ **/
+ public Object getAppletContext() {
+ // There's no AppContext: return null.
+ // No need to call getAppContext() if numAppContext == 0:
+ // it means that no AppContext has been created yet, and
+ // we don't want to trigger the creation of a main app
+ // context since we don't need it.
+ if (numAppContexts.get() == 0) return null;
+
+ // Get the context from the security manager
+ AppContext ecx = getExecutionAppContext();
+
+ // Not sure we really need to re-check numAppContexts here.
+ // If all applets have gone away then we could have a
+ // numAppContexts coming back to 0. So we recheck
+ // it here because we don't want to trigger the
+ // creation of a main AppContext in that case.
+ // This is probably not 100% MT-safe but should reduce
+ // the window of opportunity in which that issue could
+ // happen.
+ if (numAppContexts.get() > 0) {
+ // Defaults to thread group caching.
+ // This is probably not required as we only really need
+ // isolation in a deployed applet environment, in which
+ // case ecx will not be null when we reach here
+ // However it helps emulate the deployed environment,
+ // in tests for instance.
+ ecx = ecx != null ? ecx : getAppContext();
+ }
+
+ // getAppletContext() may be called when initializing the main
+ // app context - in which case mainAppContext will still be
+ // null. To work around this issue we simply use
+ // AppContext.threadGroup.getParent() == null instead, since
+ // mainAppContext is the only AppContext which should have
+ // the root TG as its thread group.
+ // See: JDK-8023258
+ final boolean isMainAppContext = ecx == null
+ || mainAppContext == ecx
+ || mainAppContext == null && ecx.threadGroup.getParent() == null;
+
+ return isMainAppContext ? null : ecx;
}
- public Object get(Object context, Object key) {
- return ((AppContext)context).get(key);
- }
- public void put(Object context, Object key, Object value) {
- ((AppContext)context).put(key, value);
- }
- public void remove(Object context, Object key) {
- ((AppContext)context).remove(key);
- }
+
});
}
}
--- a/jdk/src/share/classes/sun/awt/dnd/SunDropTargetContextPeer.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/awt/dnd/SunDropTargetContextPeer.java Sat Sep 14 20:43:34 2013 +0100
@@ -57,6 +57,7 @@
import sun.awt.SunToolkit;
import sun.awt.datatransfer.DataTransferer;
import sun.awt.datatransfer.ToolkitThreadBlockedHandler;
+import sun.security.util.SecurityConstants;
/**
* <p>
@@ -225,7 +226,7 @@
SecurityManager sm = System.getSecurityManager();
try {
if (!dropInProcess && sm != null) {
- sm.checkSystemClipboardAccess();
+ sm.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
}
} catch (Exception e) {
Thread currentThread = Thread.currentThread();
--- a/jdk/src/share/classes/sun/java2d/cmm/CMSManager.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/java2d/cmm/CMSManager.java Sat Sep 14 20:43:34 2013 +0100
@@ -104,53 +104,53 @@
cName = tcmm.getClass().getName();
}
- public long loadProfile(byte[] data) {
+ public Profile loadProfile(byte[] data) {
System.err.print(cName + ".loadProfile");
- long profileID = tcmm.loadProfile(data);
- System.err.printf("(ID=%x)\n", profileID);
- return profileID;
+ Profile p = tcmm.loadProfile(data);
+ System.err.printf("(ID=%s)\n", p.toString());
+ return p;
}
- public void freeProfile(long profileID) {
- System.err.printf(cName + ".freeProfile(ID=%x)\n", profileID);
- tcmm.freeProfile(profileID);
+ public void freeProfile(Profile p) {
+ System.err.printf(cName + ".freeProfile(ID=%s)\n", p.toString());
+ tcmm.freeProfile(p);
}
- public int getProfileSize(long profileID) {
- System.err.print(cName + ".getProfileSize(ID=" + profileID + ")");
- int size = tcmm.getProfileSize(profileID);
+ public int getProfileSize(Profile p) {
+ System.err.print(cName + ".getProfileSize(ID=" + p + ")");
+ int size = tcmm.getProfileSize(p);
System.err.println("=" + size);
return size;
}
- public void getProfileData(long profileID, byte[] data) {
- System.err.print(cName + ".getProfileData(ID=" + profileID + ") ");
+ public void getProfileData(Profile p, byte[] data) {
+ System.err.print(cName + ".getProfileData(ID=" + p + ") ");
System.err.println("requested " + data.length + " byte(s)");
- tcmm.getProfileData(profileID, data);
+ tcmm.getProfileData(p, data);
}
- public int getTagSize(long profileID, int tagSignature) {
+ public int getTagSize(Profile p, int tagSignature) {
System.err.printf(cName + ".getTagSize(ID=%x, TagSig=%s)",
- profileID, signatureToString(tagSignature));
- int size = tcmm.getTagSize(profileID, tagSignature);
+ p, signatureToString(tagSignature));
+ int size = tcmm.getTagSize(p, tagSignature);
System.err.println("=" + size);
return size;
}
- public void getTagData(long profileID, int tagSignature,
+ public void getTagData(Profile p, int tagSignature,
byte[] data) {
System.err.printf(cName + ".getTagData(ID=%x, TagSig=%s)",
- profileID, signatureToString(tagSignature));
+ p, signatureToString(tagSignature));
System.err.println(" requested " + data.length + " byte(s)");
- tcmm.getTagData(profileID, tagSignature, data);
+ tcmm.getTagData(p, tagSignature, data);
}
- public void setTagData(long profileID, int tagSignature,
+ public void setTagData(Profile p, int tagSignature,
byte[] data) {
- System.err.print(cName + ".setTagData(ID=" + profileID +
+ System.err.print(cName + ".setTagData(ID=" + p +
", TagSig=" + tagSignature + ")");
System.err.println(" sending " + data.length + " byte(s)");
- tcmm.setTagData(profileID, tagSignature, data);
+ tcmm.setTagData(p, tagSignature, data);
}
/* methods for creating ColorTransforms */
--- a/jdk/src/share/classes/sun/java2d/cmm/PCMM.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/java2d/cmm/PCMM.java Sat Sep 14 20:43:34 2013 +0100
@@ -32,13 +32,13 @@
public interface PCMM {
/* methods invoked from ICC_Profile */
- public long loadProfile(byte[] data);
- public void freeProfile(long profileID);
- public int getProfileSize(long profileID);
- public void getProfileData(long profileID, byte[] data);
- public void getTagData(long profileID, int tagSignature, byte[] data);
- public int getTagSize(long profileID, int tagSignature);
- public void setTagData(long profileID, int tagSignature, byte[] data);
+ public Profile loadProfile(byte[] data);
+ public void freeProfile(Profile p);
+ public int getProfileSize(Profile p);
+ public void getProfileData(Profile p, byte[] data);
+ public void getTagData(Profile p, int tagSignature, byte[] data);
+ public int getTagSize(Profile p, int tagSignature);
+ public void setTagData(Profile p, int tagSignature, byte[] data);
/* methods for creating ColorTransforms */
public ColorTransform createTransform(ICC_Profile profile, int renderType,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/java2d/cmm/Profile.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,43 @@
+/*
+ * 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. 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.java2d.cmm;
+
+import java.awt.color.CMMException;
+
+public class Profile {
+ private final long nativePtr;
+
+ protected Profile(long ptr) {
+ nativePtr = ptr;
+ }
+
+ protected final long getNativePtr() {
+ if (nativePtr == 0L) {
+ throw new CMMException("Invalid profile: ptr is null");
+ }
+ return nativePtr;
+ }
+}
--- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java Sat Sep 14 20:43:34 2013 +0100
@@ -25,96 +25,139 @@
package sun.java2d.cmm.lcms;
+import java.awt.color.CMMException;
import java.awt.color.ICC_Profile;
-import java.util.Arrays;
-import java.util.HashMap;
import sun.java2d.cmm.ColorTransform;
import sun.java2d.cmm.PCMM;
+import sun.java2d.cmm.Profile;
+import sun.java2d.cmm.lcms.LCMSProfile.TagData;
public class LCMS implements PCMM {
/* methods invoked from ICC_Profile */
@Override
- public long loadProfile(byte[] data) {
- long id = loadProfileNative(data);
+ public Profile loadProfile(byte[] data) {
+ final Object disposerRef = new Object();
+
+ final long ptr = loadProfileNative(data, disposerRef);
- if (id != 0L) {
- if (profiles == null) {
- profiles = new HashMap<>();
- }
- profiles.put(id, new TagCache(id));
+ if (ptr != 0L) {
+ return new LCMSProfile(ptr, disposerRef);
}
- return id;
+ return null;
}
- private native long loadProfileNative(byte[] data);
+ private native long loadProfileNative(byte[] data, Object ref);
+
+ private LCMSProfile getLcmsProfile(Profile p) {
+ if (p instanceof LCMSProfile) {
+ return (LCMSProfile)p;
+ }
+ throw new CMMException("Invalid profile: " + p);
+ }
+
@Override
- public void freeProfile(long profileID) {
- TagCache c = profiles.remove(profileID);
- if (c != null) {
- c.clear();
+ public void freeProfile(Profile p) {
+ // we use disposer, so this method does nothing
+ }
+
+ @Override
+ public int getProfileSize(final Profile p) {
+ synchronized (p) {
+ return getProfileSizeNative(getLcmsProfile(p).getLcmsPtr());
}
- if (profiles.isEmpty()) {
- profiles = null;
- }
- freeProfileNative(profileID);
}
- private native void freeProfileNative(long profileID);
+ private native int getProfileSizeNative(long ptr);
- public native synchronized int getProfileSize(long profileID);
+ @Override
+ public void getProfileData(final Profile p, byte[] data) {
+ synchronized (p) {
+ getProfileDataNative(getLcmsProfile(p).getLcmsPtr(), data);
+ }
+ }
- public native synchronized void getProfileData(long profileID, byte[] data);
+ private native void getProfileDataNative(long ptr, byte[] data);
@Override
- public synchronized int getTagSize(long profileID, int tagSignature) {
- TagCache cache = profiles.get(profileID);
+ public int getTagSize(Profile p, int tagSignature) {
+ final LCMSProfile profile = getLcmsProfile(p);
- if (cache == null) {
- cache = new TagCache(profileID);
- profiles.put(profileID, cache);
+ synchronized (profile) {
+ TagData t = profile.getTag(tagSignature);
+ return t == null ? 0 : t.getSize();
}
-
- TagData t = cache.getTag(tagSignature);
- return t == null ? 0 : t.getSize();
}
- private static native byte[] getTagNative(long profileID, int signature);
+ static native byte[] getTagNative(long profileID, int signature);
@Override
- public synchronized void getTagData(long profileID, int tagSignature,
- byte[] data)
+ public void getTagData(Profile p, int tagSignature, byte[] data)
{
- TagCache cache = profiles.get(profileID);
+ final LCMSProfile profile = getLcmsProfile(p);
- if (cache == null) {
- cache = new TagCache(profileID);
- profiles.put(profileID, cache);
- }
-
- TagData t = cache.getTag(tagSignature);
- if (t != null) {
- t.copyDataTo(data);
+ synchronized (profile) {
+ TagData t = profile.getTag(tagSignature);
+ if (t != null) {
+ t.copyDataTo(data);
+ }
}
}
@Override
- public synchronized void setTagData(long profileID, int tagSignature, byte[] data) {
- TagCache cache = profiles.get(profileID);
+ public synchronized void setTagData(Profile p, int tagSignature, byte[] data) {
+ final LCMSProfile profile = getLcmsProfile(p);
+
+ synchronized (profile) {
+ profile.clearTagCache();
- if (cache != null) {
- cache.clear();
+ // Now we are going to update the profile with new tag data
+ // In some cases, we may change the pointer to the native
+ // profile.
+ //
+ // If we fail to write tag data for any reason, the old pointer
+ // should be used.
+ setTagDataNative(profile.getLcmsPtr(),
+ tagSignature, data);
}
- setTagDataNative(profileID, tagSignature, data);
}
- private native synchronized void setTagDataNative(long profileID, int tagSignature,
+ /**
+ * Writes supplied data as a tag into the profile.
+ * Destroys old profile, if new one was successfully
+ * created.
+ *
+ * Returns valid pointer to new profile.
+ *
+ * Throws CMMException if operation fails, preserve old profile from
+ * destruction.
+ */
+ private native void setTagDataNative(long ptr, int tagSignature,
byte[] data);
- public static native long getProfileID(ICC_Profile profile);
+ public synchronized static native LCMSProfile getProfileID(ICC_Profile profile);
+
+ /* Helper method used from LCMSColorTransfrom */
+ static long createTransform(
+ LCMSProfile[] profiles, int renderType,
+ int inFormatter, boolean isInIntPacked,
+ int outFormatter, boolean isOutIntPacked,
+ Object disposerRef)
+ {
+ long[] ptrs = new long[profiles.length];
- public static native long createNativeTransform(
+ for (int i = 0; i < profiles.length; i++) {
+ if (profiles[i] == null) throw new CMMException("Unknown profile ID");
+
+ ptrs[i] = profiles[i].getLcmsPtr();
+ }
+
+ return createNativeTransform(ptrs, renderType, inFormatter,
+ isInIntPacked, outFormatter, isOutIntPacked, disposerRef);
+ }
+
+ private static native long createNativeTransform(
long[] profileIDs, int renderType,
int inFormatter, boolean isInIntPacked,
int outFormatter, boolean isOutIntPacked,
@@ -175,59 +218,4 @@
return theLcms;
}
-
- private static class TagData {
- private int signature;
- private byte[] data;
-
- TagData(int sig, byte[] data) {
- this.signature = sig;
- this.data = data;
- }
-
- int getSize() {
- return data.length;
- }
-
- byte[] getData() {
- return Arrays.copyOf(data, data.length);
- }
-
- void copyDataTo(byte[] dst) {
- System.arraycopy(data, 0, dst, 0, data.length);
- }
-
- int getSignature() {
- return signature;
- }
- }
-
- private static class TagCache {
- private long profileID;
- private HashMap<Integer, TagData> tags;
-
- TagCache(long id) {
- profileID = id;
-
- tags = new HashMap<>();
- }
-
- TagData getTag(int sig) {
- TagData t = tags.get(sig);
- if (t == null) {
- byte[] tagData = getTagNative(profileID, sig);
- if (tagData != null) {
- t = new TagData(sig, tagData);
- tags.put(sig, t);
- }
- }
- return t;
- }
-
- void clear() {
- tags.clear();
- }
- }
-
- private static HashMap<Long, TagCache> profiles;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSProfile.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,109 @@
+/*
+ * 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. 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.java2d.cmm.lcms;
+
+import java.awt.color.CMMException;
+import java.util.Arrays;
+import java.util.HashMap;
+import sun.java2d.cmm.Profile;
+
+final class LCMSProfile extends Profile {
+ private final TagCache tagCache;
+
+ private final Object disposerReferent;
+
+ LCMSProfile(long ptr, Object ref) {
+ super(ptr);
+
+ disposerReferent = ref;
+
+ tagCache = new TagCache(this);
+ }
+
+ final long getLcmsPtr() {
+ return this.getNativePtr();
+ }
+
+ TagData getTag(int sig) {
+ return tagCache.getTag(sig);
+ }
+
+ void clearTagCache() {
+ tagCache.clear();
+ }
+
+ static class TagCache {
+ final LCMSProfile profile;
+ private HashMap<Integer, TagData> tags;
+
+ TagCache(LCMSProfile p) {
+ profile = p;
+ tags = new HashMap<>();
+ }
+
+ TagData getTag(int sig) {
+ TagData t = tags.get(sig);
+ if (t == null) {
+ byte[] tagData = LCMS.getTagNative(profile.getNativePtr(), sig);
+ if (tagData != null) {
+ t = new TagData(sig, tagData);
+ tags.put(sig, t);
+ }
+ }
+ return t;
+ }
+
+ void clear() {
+ tags.clear();
+ }
+ }
+
+ static class TagData {
+ private int signature;
+ private byte[] data;
+
+ TagData(int sig, byte[] data) {
+ this.signature = sig;
+ this.data = data;
+ }
+
+ int getSize() {
+ return data.length;
+ }
+
+ byte[] getData() {
+ return Arrays.copyOf(data, data.length);
+ }
+
+ void copyDataTo(byte[] dst) {
+ System.arraycopy(data, 0, dst, 0, data.length);
+ }
+
+ int getSignature() {
+ return signature;
+ }
+ }
+}
--- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java Sat Sep 14 20:43:34 2013 +0100
@@ -62,7 +62,7 @@
private boolean isOutIntPacked = false;
ICC_Profile[] profiles;
- long [] profileIDs;
+ LCMSProfile[] lcmsProfiles;
int renderType;
int transformType;
@@ -84,8 +84,8 @@
/* Actually, it is not a complete transform but just part of it */
profiles = new ICC_Profile[1];
profiles[0] = profile;
- profileIDs = new long[1];
- profileIDs[0] = LCMS.getProfileID(profile);
+ lcmsProfiles = new LCMSProfile[1];
+ lcmsProfiles[0] = LCMS.getProfileID(profile);
this.renderType = (renderType == ColorTransform.Any)?
ICC_Profile.icPerceptual : renderType;
this.transformType = transformType;
@@ -105,14 +105,14 @@
size+=((LCMSTransform)transforms[i]).profiles.length;
}
profiles = new ICC_Profile[size];
- profileIDs = new long[size];
+ lcmsProfiles = new LCMSProfile[size];
int j = 0;
for (int i=0; i < transforms.length; i++) {
LCMSTransform curTrans = (LCMSTransform)transforms[i];
System.arraycopy(curTrans.profiles, 0, profiles, j,
curTrans.profiles.length);
- System.arraycopy(curTrans.profileIDs, 0, profileIDs, j,
- curTrans.profileIDs.length);
+ System.arraycopy(curTrans.lcmsProfiles, 0, lcmsProfiles, j,
+ curTrans.lcmsProfiles.length);
j += curTrans.profiles.length;
}
renderType = ((LCMSTransform)transforms[0]).renderType;
@@ -152,7 +152,7 @@
outFormatter = out.pixelType;
isOutIntPacked = out.isIntPacked;
- ID = LCMS.createNativeTransform(profileIDs, renderType,
+ ID = LCMS.createTransform(lcmsProfiles, renderType,
inFormatter, isInIntPacked,
outFormatter, isOutIntPacked,
disposerReferent);
--- a/jdk/src/share/classes/sun/misc/JavaAWTAccess.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/misc/JavaAWTAccess.java Sat Sep 14 20:43:34 2013 +0100
@@ -26,14 +26,16 @@
package sun.misc;
public interface JavaAWTAccess {
- public Object getContext();
- public Object getExecutionContext();
- public Object get(Object context, Object key);
- public void put(Object context, Object key, Object value);
- public void remove(Object context, Object key);
+ // Returns the AppContext used for applet logging isolation, or null if
+ // no isolation is required.
+ // If there's no applet, or if the caller is a stand alone application,
+ // or running in the main app context, returns null.
+ // Otherwise, returns the AppContext of the calling applet.
+ public Object getAppletContext();
- // convenience methods whose context is the object returned by getContext()
+ // convenience methods to cache objects in the current thread group's
+ // AppContext
public Object get(Object key);
public void put(Object key, Object value);
public void remove(Object key);
--- a/jdk/src/share/classes/sun/misc/SharedSecrets.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/misc/SharedSecrets.java Sat Sep 14 20:43:34 2013 +0100
@@ -170,7 +170,7 @@
public static JavaAWTAccess getJavaAWTAccess() {
// this may return null in which case calling code needs to
// provision for.
- if (javaAWTAccess == null || javaAWTAccess.getContext() == null) {
+ if (javaAWTAccess == null) {
return null;
}
return javaAWTAccess;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/print/DocumentPropertiesUI.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,62 @@
+/*
+ * 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. 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.print;
+
+import java.awt.Window;
+import java.awt.print.PrinterJob;
+import javax.print.PrintService;
+import javax.print.ServiceUIFactory;
+import javax.print.attribute.PrintRequestAttributeSet;
+
+public abstract class DocumentPropertiesUI {
+
+ /**
+ * For Win32 doc properties sheet.
+ */
+ public static final int
+ DOCUMENTPROPERTIES_ROLE = ServiceUIFactory.RESERVED_UIROLE +100;
+
+ /**
+ * Name of (this) abstract class for Document Properties.
+ */
+ public static final String
+ DOCPROPERTIESCLASSNAME = DocumentPropertiesUI.class.getName();
+
+ /**
+ * Invokes whatever code is needed to display a native dialog
+ * with the specified owner. The owner should be the cross-platform
+ * dialog. If the user cancels the dialog the return value is null.
+ * A non-null return value is always a new attribute set (or is it?)
+ * The cross-platform dialog may need to be updated to reflect the
+ * updated properties.
+ */
+ public abstract PrintRequestAttributeSet
+ showDocumentProperties(PrinterJob job,
+ Window owner,
+ PrintService service,
+ PrintRequestAttributeSet aset);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/print/PrinterJobWrapper.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,60 @@
+/*
+ * 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. 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.print;
+
+import java.awt.print.PrinterJob;
+import javax.print.attribute.PrintRequestAttribute;
+
+public class PrinterJobWrapper implements PrintRequestAttribute {
+
+ private static final long serialVersionUID = -8792124426995707237L;
+
+ private PrinterJob job;
+
+ public PrinterJobWrapper(PrinterJob job) {
+ this.job = job;
+ }
+
+ public PrinterJob getPrinterJob() {
+ return job;
+ }
+
+ public final Class getCategory() {
+ return PrinterJobWrapper.class;
+ }
+
+ public final String getName() {
+ return "printerjob-wrapper";
+ }
+
+ public String toString() {
+ return "printerjob-wrapper: " + job.toString();
+ }
+
+ public int hashCode() {
+ return job.hashCode();
+ }
+}
--- a/jdk/src/share/classes/sun/print/RasterPrinterJob.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/print/RasterPrinterJob.java Sat Sep 14 20:43:34 2013 +0100
@@ -903,6 +903,9 @@
int x = bounds.x+bounds.width/3;
int y = bounds.y+bounds.height/3;
PrintService newService;
+ // temporarily add an attribute pointing back to this job.
+ PrinterJobWrapper jobWrapper = new PrinterJobWrapper(this);
+ attributes.add(jobWrapper);
try {
newService =
ServiceUI.printDialog(gc, x, y,
@@ -915,6 +918,7 @@
DocFlavor.SERVICE_FORMATTED.PAGEABLE,
attributes);
}
+ attributes.remove(PrinterJobWrapper.class);
if (newService == null) {
return false;
--- a/jdk/src/share/classes/sun/print/ServiceDialog.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/print/ServiceDialog.java Sat Sep 14 20:43:34 2013 +0100
@@ -46,6 +46,7 @@
import java.awt.event.ItemListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowAdapter;
+import java.awt.print.PrinterJob;
import java.io.File;
import java.io.FilePermission;
import java.io.IOException;
@@ -119,8 +120,6 @@
private AppearancePanel pnlAppearance;
private boolean isAWT = false;
-
-
static {
initResource();
}
@@ -801,9 +800,32 @@
if (dialog != null) {
dialog.show();
} else {
- // REMIND: may want to notify the user why we're
- // disabling the button
- btnProperties.setEnabled(false);
+ DocumentPropertiesUI docPropertiesUI = null;
+ try {
+ docPropertiesUI =
+ (DocumentPropertiesUI)uiFactory.getUI
+ (DocumentPropertiesUI.DOCUMENTPROPERTIES_ROLE,
+ DocumentPropertiesUI.DOCPROPERTIESCLASSNAME);
+ } catch (Exception ex) {
+ }
+ if (docPropertiesUI != null) {
+ PrinterJobWrapper wrapper = (PrinterJobWrapper)
+ asCurrent.get(PrinterJobWrapper.class);
+ if (wrapper == null) {
+ return; // should not happen, defensive only.
+ }
+ PrinterJob job = wrapper.getPrinterJob();
+ if (job == null) {
+ return; // should not happen, defensive only.
+ }
+ PrintRequestAttributeSet newAttrs =
+ docPropertiesUI.showDocumentProperties
+ (job, ServiceDialog.this, psCurrent, asCurrent);
+ if (newAttrs != null) {
+ asCurrent.addAll(newAttrs);
+ updatePanels();
+ }
+ }
}
}
}
--- a/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java Sat Sep 14 20:43:34 2013 +0100
@@ -385,12 +385,12 @@
switch (responseStatus) {
case SUCCESSFUL:
break;
- case UNAUTHORIZED:
case TRY_LATER:
case INTERNAL_ERROR:
throw new CertPathValidatorException(
"OCSP response error: " + responseStatus, null, null, -1,
BasicReason.UNDETERMINED_REVOCATION_STATUS);
+ case UNAUTHORIZED:
default:
throw new CertPathValidatorException("OCSP response error: " +
responseStatus);
--- a/jdk/src/share/classes/sun/security/ssl/Handshaker.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/security/ssl/Handshaker.java Sat Sep 14 20:43:34 2013 +0100
@@ -145,6 +145,14 @@
/* True if it's OK to start a new SSL session */
boolean enableNewSession;
+ // Whether local cipher suites preference should be honored during
+ // handshaking?
+ //
+ // Note that in this provider, this option only applies to server side.
+ // Local cipher suites preference is always honored in client side in
+ // this provider.
+ boolean preferLocalCipherSuites = false;
+
// Temporary storage for the individual keys. Set by
// calculateConnectionKeys() and cleared once the ciphers are
// activated.
@@ -463,6 +471,13 @@
}
/**
+ * Sets the cipher suites preference.
+ */
+ void setUseCipherSuitesOrder(boolean on) {
+ this.preferLocalCipherSuites = on;
+ }
+
+ /**
* Prior to handshaking, activate the handshake and initialize the version,
* input stream and output stream.
*/
@@ -533,7 +548,9 @@
}
/**
- * Check if the given ciphersuite is enabled and available.
+ * Check if the given ciphersuite is enabled and available within the
+ * current active cipher suites.
+ *
* Does not check if the required server certificates are available.
*/
boolean isNegotiable(CipherSuite s) {
@@ -541,7 +558,17 @@
activeCipherSuites = getActiveCipherSuites();
}
- return activeCipherSuites.contains(s) && s.isNegotiable();
+ return isNegotiable(activeCipherSuites, s);
+ }
+
+ /**
+ * Check if the given ciphersuite is enabled and available within the
+ * proposed cipher suite list.
+ *
+ * Does not check if the required server certificates are available.
+ */
+ final static boolean isNegotiable(CipherSuiteList proposed, CipherSuite s) {
+ return proposed.contains(s) && s.isNegotiable();
}
/**
--- a/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java Sat Sep 14 20:43:34 2013 +0100
@@ -320,6 +320,12 @@
private boolean isFirstAppOutputRecord = true;
/*
+ * Whether local cipher suites preference in server side should be
+ * honored during handshaking?
+ */
+ private boolean preferLocalCipherSuites = false;
+
+ /*
* Class and subclass dynamic debugging support
*/
private static final Debug debug = Debug.getInstance("ssl");
@@ -470,6 +476,7 @@
protocolVersion, connectionState == cs_HANDSHAKE,
secureRenegotiation, clientVerifyData, serverVerifyData);
handshaker.setSNIMatchers(sniMatchers);
+ handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites);
} else {
handshaker = new ClientHandshaker(this, sslContext,
enabledProtocols,
@@ -2074,6 +2081,7 @@
params.setAlgorithmConstraints(algorithmConstraints);
params.setSNIMatchers(sniMatchers);
params.setServerNames(serverNames);
+ params.setUseCipherSuitesOrder(preferLocalCipherSuites);
return params;
}
@@ -2088,6 +2096,7 @@
// the super implementation does not handle the following parameters
identificationProtocol = params.getEndpointIdentificationAlgorithm();
algorithmConstraints = params.getAlgorithmConstraints();
+ preferLocalCipherSuites = params.getUseCipherSuitesOrder();
List<SNIServerName> sniNames = params.getServerNames();
if (sniNames != null) {
@@ -2104,6 +2113,7 @@
handshaker.setAlgorithmConstraints(algorithmConstraints);
if (roleIsServer) {
handshaker.setSNIMatchers(sniMatchers);
+ handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites);
} else {
handshaker.setSNIServerNames(serverNames);
}
--- a/jdk/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -92,6 +92,12 @@
Collection<SNIMatcher> sniMatchers =
Collections.<SNIMatcher>emptyList();
+ /*
+ * Whether local cipher suites preference in server side should be
+ * honored during handshaking?
+ */
+ private boolean preferLocalCipherSuites = false;
+
/**
* Create an SSL server socket on a port, using a non-default
* authentication context and a specified connection backlog.
@@ -304,6 +310,8 @@
params.setEndpointIdentificationAlgorithm(identificationProtocol);
params.setAlgorithmConstraints(algorithmConstraints);
params.setSNIMatchers(sniMatchers);
+ params.setUseCipherSuitesOrder(preferLocalCipherSuites);
+
return params;
}
@@ -318,6 +326,7 @@
// the super implementation does not handle the following parameters
identificationProtocol = params.getEndpointIdentificationAlgorithm();
algorithmConstraints = params.getAlgorithmConstraints();
+ preferLocalCipherSuites = params.getUseCipherSuitesOrder();
Collection<SNIMatcher> matchers = params.getSNIMatchers();
if (matchers != null) {
sniMatchers = params.getSNIMatchers();
@@ -334,7 +343,7 @@
SSLSocketImpl s = new SSLSocketImpl(sslContext, useServerMode,
enabledCipherSuites, doClientAuth, enableSessionCreation,
enabledProtocols, identificationProtocol, algorithmConstraints,
- sniMatchers);
+ sniMatchers, preferLocalCipherSuites);
implAccept(s);
s.doneConnect();
--- a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java Sat Sep 14 20:43:34 2013 +0100
@@ -377,6 +377,12 @@
*/
private ByteArrayOutputStream heldRecordBuffer = null;
+ /*
+ * Whether local cipher suites preference in server side should be
+ * honored during handshaking?
+ */
+ private boolean preferLocalCipherSuites = false;
+
//
// CONSTRUCTORS AND INITIALIZATION CODE
//
@@ -482,7 +488,8 @@
boolean sessionCreation, ProtocolList protocols,
String identificationProtocol,
AlgorithmConstraints algorithmConstraints,
- Collection<SNIMatcher> sniMatchers) throws IOException {
+ Collection<SNIMatcher> sniMatchers,
+ boolean preferLocalCipherSuites) throws IOException {
super();
doClientAuth = clientAuth;
@@ -490,6 +497,7 @@
this.identificationProtocol = identificationProtocol;
this.algorithmConstraints = algorithmConstraints;
this.sniMatchers = sniMatchers;
+ this.preferLocalCipherSuites = preferLocalCipherSuites;
init(context, serverMode);
/*
@@ -1284,6 +1292,7 @@
protocolVersion, connectionState == cs_HANDSHAKE,
secureRenegotiation, clientVerifyData, serverVerifyData);
handshaker.setSNIMatchers(sniMatchers);
+ handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites);
} else {
handshaker = new ClientHandshaker(this, sslContext,
enabledProtocols,
@@ -2502,6 +2511,7 @@
params.setAlgorithmConstraints(algorithmConstraints);
params.setSNIMatchers(sniMatchers);
params.setServerNames(serverNames);
+ params.setUseCipherSuitesOrder(preferLocalCipherSuites);
return params;
}
@@ -2516,6 +2526,7 @@
// the super implementation does not handle the following parameters
identificationProtocol = params.getEndpointIdentificationAlgorithm();
algorithmConstraints = params.getAlgorithmConstraints();
+ preferLocalCipherSuites = params.getUseCipherSuitesOrder();
List<SNIServerName> sniNames = params.getServerNames();
if (sniNames != null) {
@@ -2532,6 +2543,7 @@
handshaker.setAlgorithmConstraints(algorithmConstraints);
if (roleIsServer) {
handshaker.setSNIMatchers(sniMatchers);
+ handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites);
} else {
handshaker.setSNIServerNames(serverNames);
}
--- a/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java Sat Sep 14 20:43:34 2013 +0100
@@ -932,8 +932,18 @@
* the cipherSuite and keyExchange variables.
*/
private void chooseCipherSuite(ClientHello mesg) throws IOException {
- for (CipherSuite suite : mesg.getCipherSuites().collection()) {
- if (isNegotiable(suite) == false) {
+ CipherSuiteList prefered;
+ CipherSuiteList proposed;
+ if (preferLocalCipherSuites) {
+ prefered = getActiveCipherSuites();
+ proposed = mesg.getCipherSuites();
+ } else {
+ prefered = mesg.getCipherSuites();
+ proposed = getActiveCipherSuites();
+ }
+
+ for (CipherSuite suite : prefered.collection()) {
+ if (isNegotiable(proposed, suite) == false) {
continue;
}
@@ -948,8 +958,7 @@
}
return;
}
- fatalSE(Alerts.alert_handshake_failure,
- "no cipher suites in common");
+ fatalSE(Alerts.alert_handshake_failure, "no cipher suites in common");
}
/**
--- a/jdk/src/share/classes/sun/swing/SwingUtilities2.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/swing/SwingUtilities2.java Sat Sep 14 20:43:34 2013 +0100
@@ -1184,7 +1184,7 @@
canAccess = true;
} else {
try {
- sm.checkSystemClipboardAccess();
+ sm.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
canAccess = true;
} catch (SecurityException e) {
}
--- a/jdk/src/share/classes/sun/tools/jar/resources/jar.properties Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/tools/jar/resources/jar.properties Sat Sep 14 20:43:34 2013 +0100
@@ -61,7 +61,7 @@
out.extracted=\
extracted: {0}
out.inflated=\
- \ \inflated: {0}
+ \ inflated: {0}
out.size=\
(in = {0}) (out= {1})
--- a/jdk/src/share/classes/sun/tools/jconsole/Resources.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/tools/jconsole/Resources.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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
@@ -30,7 +30,7 @@
import java.lang.reflect.Modifier;
import java.text.MessageFormat;
import java.util.Collections;
-import java.util.HashMap;
+import java.util.IdentityHashMap;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
@@ -40,7 +40,7 @@
*/
public final class Resources {
private static Map<String, Integer> MNEMONIC_LOOKUP = Collections
- .synchronizedMap(new HashMap<String, Integer>());
+ .synchronizedMap(new IdentityHashMap<String, Integer>());
private Resources() {
throw new AssertionError();
--- a/jdk/src/share/classes/sun/tracing/ProviderSkeleton.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/tracing/ProviderSkeleton.java Sat Sep 14 20:43:34 2013 +0100
@@ -164,7 +164,10 @@
declaringClass == Object.class) {
return method.invoke(this, args);
} else {
- assert false;
+ // assert false : "this should never happen"
+ // reaching here would indicate a breach
+ // in security in the higher layers
+ throw new SecurityException();
}
} catch (IllegalAccessException e) {
assert false;
--- a/jdk/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java Sat Sep 14 20:43:34 2013 +0100
@@ -361,7 +361,7 @@
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken();
if (token.equals("|")) {
- if (isNonUSLangSupported()) {
+ if (isNonENLangSupported()) {
continue;
}
break;
@@ -398,7 +398,7 @@
*/
int barIndex = supportedLocaleString.indexOf('|');
StringTokenizer localeStringTokenizer;
- if (isNonUSLangSupported()) {
+ if (isNonENLangSupported()) {
localeStringTokenizer = new StringTokenizer(supportedLocaleString.substring(0, barIndex)
+ supportedLocaleString.substring(barIndex + 1));
} else {
@@ -427,17 +427,17 @@
return locales;
}
- private static volatile Boolean isNonUSSupported = null;
+ private static volatile Boolean isNonENSupported = null;
/*
- * Returns true if the non US resources jar file exists in jre
+ * Returns true if the non EN resources jar file exists in jre
* extension directory. @returns true if the jar file is there. Otherwise,
* returns false.
*/
- private static boolean isNonUSLangSupported() {
- if (isNonUSSupported == null) {
+ private static boolean isNonENLangSupported() {
+ if (isNonENSupported == null) {
synchronized (JRELocaleProviderAdapter.class) {
- if (isNonUSSupported == null) {
+ if (isNonENSupported == null) {
final String sep = File.separator;
String localeDataJar =
java.security.AccessController.doPrivileged(
@@ -449,7 +449,7 @@
* localedata.jar is installed or not.
*/
final File f = new File(localeDataJar);
- isNonUSSupported =
+ isNonENSupported =
AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
@@ -459,6 +459,6 @@
}
}
}
- return isNonUSSupported;
+ return isNonENSupported;
}
}
--- a/jdk/src/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template Sat Sep 14 20:43:34 2013 +0100
@@ -52,25 +52,25 @@
look up locale string such as "en" could be based on if it contains " en ".
*/
resourceNameToLocales.put("FormatData",
- " #FormatData_USLocales# | #FormatData_NonUSLocales# ");
+ " #FormatData_ENLocales# | #FormatData_NonENLocales# ");
resourceNameToLocales.put("CollationData",
- " #CollationData_USLocales# | #CollationData_NonUSLocales# ");
+ " #CollationData_ENLocales# | #CollationData_NonENLocales# ");
resourceNameToLocales.put("TimeZoneNames",
- " #TimeZoneNames_USLocales# | #TimeZoneNames_NonUSLocales# ");
+ " #TimeZoneNames_ENLocales# | #TimeZoneNames_NonENLocales# ");
resourceNameToLocales.put("LocaleNames",
- " #LocaleNames_USLocales# | #LocaleNames_NonUSLocales# ");
+ " #LocaleNames_ENLocales# | #LocaleNames_NonENLocales# ");
resourceNameToLocales.put("CurrencyNames",
- " #CurrencyNames_USLocales# | #CurrencyNames_NonUSLocales# ");
+ " #CurrencyNames_ENLocales# | #CurrencyNames_NonENLocales# ");
resourceNameToLocales.put("CalendarData",
- " #CalendarData_USLocales# | #CalendarData_NonUSLocales# ");
+ " #CalendarData_ENLocales# | #CalendarData_NonENLocales# ");
resourceNameToLocales.put("AvailableLocales",
- " #AvailableLocales_USLocales# | #AvailableLocales_NonUSLocales# ");
+ " #AvailableLocales_ENLocales# | #AvailableLocales_NonENLocales# ");
}
/*
--- a/jdk/src/share/classes/sun/util/locale/provider/LocaleResources.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/util/locale/provider/LocaleResources.java Sat Sep 14 20:43:34 2013 +0100
@@ -252,7 +252,7 @@
String[] getTimeZoneNames(String key, int size) {
String[] names = null;
- String cacheKey = TIME_ZONE_NAMES + key;
+ String cacheKey = TIME_ZONE_NAMES + size + '.' + key;
removeEmptyReferences();
ResourceReference data = cache.get(cacheKey);
--- a/jdk/src/share/classes/sun/util/logging/resources/logging.properties Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging.properties Sat Sep 14 20:43:34 2013 +0100
@@ -27,20 +27,20 @@
# these are the same as the non-localized level name.
# The following ALL CAPS words should be translated.
-ALL=ALL
+ALL=All
# The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=Severe
# The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=Warning
# The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=Info
# The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= Config
# The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=Fine
# The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=Finer
# The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=Finest
# The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=Off
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_de.properties Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_de.properties Sat Sep 14 20:43:34 2013 +0100
@@ -27,20 +27,20 @@
# these are the same as the non-localized level name.
# The following ALL CAPS words should be translated.
-ALL=ALL
+ALL=Alle
# The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=Schwerwiegend
# The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=Warnung
# The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=Information
# The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= Konfiguration
# The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=Fein
# The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=Feiner
# The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=Am feinsten
# The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=Deaktiviert
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_es.properties Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_es.properties Sat Sep 14 20:43:34 2013 +0100
@@ -27,20 +27,20 @@
# these are the same as the non-localized level name.
# The following ALL CAPS words should be translated.
-ALL=ALL
+ALL=Todo
# The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=Grave
# The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=Advertencia
# The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=Informaci\u00F3n
# The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= Configurar
# The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=Detallado
# The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=Muy Detallado
# The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=M\u00E1s Detallado
# The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=Desactivado
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_fr.properties Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_fr.properties Sat Sep 14 20:43:34 2013 +0100
@@ -27,20 +27,20 @@
# these are the same as the non-localized level name.
# The following ALL CAPS words should be translated.
-ALL=ALL
+ALL=Tout
# The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=Grave
# The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=Avertissement
# The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=Infos
# The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= Config
# The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=Pr\u00E9cis
# The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=Plus pr\u00E9cis
# The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=Le plus pr\u00E9cis
# The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=D\u00E9sactiv\u00E9
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_it.properties Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_it.properties Sat Sep 14 20:43:34 2013 +0100
@@ -27,20 +27,20 @@
# these are the same as the non-localized level name.
# The following ALL CAPS words should be translated.
-ALL=ALL
+ALL=Tutto
# The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=Grave
# The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=Avvertenza
# The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=Informazioni
# The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= Configurazione
# The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=Buono
# The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=Migliore
# The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=Ottimale
# The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=Non attivo
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_ja.properties Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_ja.properties Sat Sep 14 20:43:34 2013 +0100
@@ -29,18 +29,18 @@
# The following ALL CAPS words should be translated.
ALL=\u3059\u3079\u3066
# The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=\u91CD\u5927
# The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=\u8B66\u544A
# The following ALL CAPS words should be translated.
INFO=\u60C5\u5831
# The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= \u69CB\u6210
# The following ALL CAPS words should be translated.
-FINE=\u8A73\u7D30\u30EC\u30D9\u30EB(\u4F4E)
+FINE=\u666E\u901A
# The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=\u8A73\u7D30
# The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=\u6700\u3082\u8A73\u7D30
# The following ALL CAPS words should be translated.
OFF=\u30AA\u30D5
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_ko.properties Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_ko.properties Sat Sep 14 20:43:34 2013 +0100
@@ -27,20 +27,20 @@
# these are the same as the non-localized level name.
# The following ALL CAPS words should be translated.
-ALL=ALL
+ALL=\uBAA8\uB450
# The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=\uC2EC\uAC01
# The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=\uACBD\uACE0
# The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=\uC815\uBCF4
# The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= \uAD6C\uC131
# The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=\uBBF8\uC138
# The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=\uBCF4\uB2E4 \uBBF8\uC138
# The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=\uAC00\uC7A5 \uBBF8\uC138
# The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=\uD574\uC81C
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_pt_BR.properties Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_pt_BR.properties Sat Sep 14 20:43:34 2013 +0100
@@ -27,20 +27,20 @@
# these are the same as the non-localized level name.
# The following ALL CAPS words should be translated.
-ALL=ALL
+ALL=Tudo
# The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=Grave
# The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=Advert\u00EAncia
# The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=Informa\u00E7\u00F5es
# The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= Configura\u00E7\u00E3o
# The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=Detalhado
# The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=Mais Detalhado
# The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=O Mais Detalhado
# The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=Desativado
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_sv.properties Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_sv.properties Sat Sep 14 20:43:34 2013 +0100
@@ -27,20 +27,20 @@
# these are the same as the non-localized level name.
# The following ALL CAPS words should be translated.
-ALL=ALLA
+ALL=Alla
# The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=Allvarlig
# The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=Varning
# The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=Info
# The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= Konfig
# The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=Fin
# The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=Finare
# The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=Finaste
# The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=Av
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_zh_CN.properties Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_zh_CN.properties Sat Sep 14 20:43:34 2013 +0100
@@ -27,20 +27,20 @@
# these are the same as the non-localized level name.
# The following ALL CAPS words should be translated.
-ALL=ALL
+ALL=\u5168\u90E8
# The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=\u4E25\u91CD
# The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=\u8B66\u544A
# The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=\u4FE1\u606F
# The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= \u914D\u7F6E
# The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=\u8BE6\u7EC6
# The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=\u8F83\u8BE6\u7EC6
# The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=\u975E\u5E38\u8BE6\u7EC6
# The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=\u7981\u7528
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_zh_TW.properties Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_zh_TW.properties Sat Sep 14 20:43:34 2013 +0100
@@ -27,20 +27,20 @@
# these are the same as the non-localized level name.
# The following ALL CAPS words should be translated.
-ALL=\u6240\u6709
+ALL=\u5168\u90E8
# The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=\u56B4\u91CD
# The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=\u8B66\u544A
# The following ALL CAPS words should be translated.
INFO=\u8CC7\u8A0A
# The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= \u7D44\u614B
# The following ALL CAPS words should be translated.
FINE=\u8A73\u7D30
# The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=\u8F03\u8A73\u7D30
# The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=\u6700\u8A73\u7D30
# The following ALL CAPS words should be translated.
OFF=\u95DC\u9589
--- a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c Sat Sep 14 20:43:34 2013 +0100
@@ -930,9 +930,10 @@
* Now fill a complete buffer, or as much of one as the stream
* will give us if we are near the end.
*/
+ RELEASE_ARRAYS(env, data, src->next_input_byte);
+
GET_IO_REF(input);
- RELEASE_ARRAYS(env, data, src->next_input_byte);
ret = (*env)->CallIntMethod(env,
input,
JPEGImageReader_readInputDataID,
@@ -1017,9 +1018,11 @@
memcpy(sb->buf, src->next_input_byte, offset);
}
- GET_IO_REF(input);
RELEASE_ARRAYS(env, data, src->next_input_byte);
+
+ GET_IO_REF(input);
+
buflen = sb->bufferLength - offset;
if (buflen <= 0) {
if (!GET_ARRAYS(env, data, &(src->next_input_byte))) {
@@ -1121,9 +1124,10 @@
return;
}
+ RELEASE_ARRAYS(env, data, src->next_input_byte);
+
GET_IO_REF(input);
- RELEASE_ARRAYS(env, data, src->next_input_byte);
ret = (*env)->CallLongMethod(env,
input,
JPEGImageReader_skipInputBytesID,
@@ -2306,10 +2310,10 @@
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
jobject output = NULL;
+ RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
+
GET_IO_REF(output);
- RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
-
(*env)->CallVoidMethod(env,
output,
JPEGImageWriter_writeOutputDataID,
@@ -2348,10 +2352,10 @@
if (datacount != 0) {
jobject output = NULL;
+ RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
+
GET_IO_REF(output);
- RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
-
(*env)->CallVoidMethod(env,
output,
JPEGImageWriter_writeOutputDataID,
--- a/jdk/src/share/native/sun/font/layout/SunLayoutEngine.cpp Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/native/sun/font/layout/SunLayoutEngine.cpp Sat Sep 14 20:43:34 2013 +0100
@@ -179,6 +179,10 @@
FontInstanceAdapter fia(env, font2d, strike, mat, 72, 72, (le_int32) upem, (TTLayoutTableCache *) layoutTables);
LEErrorCode success = LE_NO_ERROR;
LayoutEngine *engine = LayoutEngine::layoutEngineFactory(&fia, script, lang, typo_flags & TYPO_MASK, success);
+ if (engine == NULL) {
+ env->SetIntField(gvdata, gvdCountFID, -1); // flag failure
+ return;
+ }
if (min < 0) min = 0; if (max < min) max = min; /* defensive coding */
// have to copy, yuck, since code does upcalls now. this will be soooo slow
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c Sat Sep 14 20:43:34 2013 +0100
@@ -94,8 +94,12 @@
# endif
#endif
+typedef struct lcmsProfile_s {
+ cmsHPROFILE pf;
+} lcmsProfile_t, *lcmsProfile_p;
+
typedef union storeID_s { /* store SProfile stuff in a Java Long */
- cmsHPROFILE pf;
+ lcmsProfile_p lcmsPf;
cmsHTRANSFORM xf;
jobject jobj;
jlong j;
@@ -106,7 +110,6 @@
jint j;
} TagSignature_t, *TagSignature_p;
-static jfieldID Trans_profileIDs_fID;
static jfieldID Trans_renderType_fID;
static jfieldID Trans_ID_fID;
static jfieldID IL_isIntPacked_fID;
@@ -118,7 +121,6 @@
static jfieldID IL_width_fID;
static jfieldID IL_height_fID;
static jfieldID IL_imageAtOnce_fID;
-static jfieldID PF_ID_fID;
JavaVM *javaVM;
@@ -145,6 +147,18 @@
return JNI_VERSION_1_6;
}
+void LCMS_freeProfile(JNIEnv *env, jlong ptr) {
+ storeID_t sProfile;
+ sProfile.j = ptr;
+
+ if (sProfile.lcmsPf != NULL) {
+ if (sProfile.lcmsPf->pf != NULL) {
+ cmsCloseProfile(sProfile.lcmsPf->pf);
+ }
+ free(sProfile.lcmsPf);
+ }
+}
+
void LCMS_freeTransform(JNIEnv *env, jlong ID)
{
storeID_t sTrans;
@@ -170,7 +184,7 @@
jlong* ids;
size = (*env)->GetArrayLength (env, profileIDs);
- ids = (*env)->GetPrimitiveArrayCritical(env, profileIDs, 0);
+ ids = (*env)->GetLongArrayElements(env, profileIDs, 0);
#ifdef _LITTLE_ENDIAN
/* Reversing data packed into int for LE archs */
@@ -186,6 +200,8 @@
iccArray = (cmsHPROFILE*) malloc(
size*2*sizeof(cmsHPROFILE));
if (iccArray == NULL) {
+ (*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);
+
J2dRlsTraceLn(J2D_TRACE_ERROR, "getXForm: iccArray == NULL");
return 0L;
}
@@ -197,7 +213,7 @@
cmsColorSpaceSignature cs;
sTrans.j = ids[i];
- icc = sTrans.pf;
+ icc = sTrans.lcmsPf->pf;
iccArray[j++] = icc;
/* Middle non-abstract profiles should be doubled before passing to
@@ -215,13 +231,15 @@
sTrans.xf = cmsCreateMultiprofileTransform(iccArray, j,
inFormatter, outFormatter, renderType, 0);
- (*env)->ReleasePrimitiveArrayCritical(env, profileIDs, ids, 0);
+ (*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);
if (sTrans.xf == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_createNativeTransform: "
"sTrans.xf == NULL");
- JNU_ThrowByName(env, "java/awt/color/CMMException",
- "Cannot get color transform");
+ if ((*env)->ExceptionOccurred(env) == NULL) {
+ JNU_ThrowByName(env, "java/awt/color/CMMException",
+ "Cannot get color transform");
+ }
} else {
Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, sTrans.j);
}
@@ -236,20 +254,23 @@
/*
* Class: sun_java2d_cmm_lcms_LCMS
* Method: loadProfile
- * Signature: ([B)J
+ * Signature: ([B,Lsun/java2d/cmm/lcms/LCMSProfile;)V
*/
JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative
- (JNIEnv *env, jobject obj, jbyteArray data)
+ (JNIEnv *env, jobject obj, jbyteArray data, jobject disposerRef)
{
jbyte* dataArray;
jint dataSize;
storeID_t sProf;
+ cmsHPROFILE pf;
if (JNU_IsNull(env, data)) {
JNU_ThrowIllegalArgumentException(env, "Invalid profile data");
return 0L;
}
+ sProf.j = 0L;
+
dataArray = (*env)->GetByteArrayElements (env, data, 0);
dataSize = (*env)->GetArrayLength (env, data);
@@ -258,22 +279,37 @@
return 0L;
}
- sProf.pf = cmsOpenProfileFromMem((const void *)dataArray,
+ pf = cmsOpenProfileFromMem((const void *)dataArray,
(cmsUInt32Number) dataSize);
(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
- if (sProf.pf == NULL) {
+ if (pf == NULL) {
JNU_ThrowIllegalArgumentException(env, "Invalid profile data");
} else {
/* Sanity check: try to save the profile in order
* to force basic validation.
*/
cmsUInt32Number pfSize = 0;
- if (!cmsSaveProfileToMem(sProf.pf, NULL, &pfSize) ||
+ if (!cmsSaveProfileToMem(pf, NULL, &pfSize) ||
pfSize < sizeof(cmsICCHeader))
{
JNU_ThrowIllegalArgumentException(env, "Invalid profile data");
+
+ cmsCloseProfile(pf);
+ pf = NULL;
+ }
+ }
+
+ if (pf != NULL) {
+ // create profile holder
+ sProf.lcmsPf = (lcmsProfile_p)malloc(sizeof(lcmsProfile_t));
+ if (sProf.lcmsPf != NULL) {
+ // register the disposer record
+ sProf.lcmsPf->pf = pf;
+ Disposer_AddRecord(env, disposerRef, LCMS_freeProfile, sProf.j);
+ } else {
+ cmsCloseProfile(pf);
}
}
@@ -282,37 +318,17 @@
/*
* Class: sun_java2d_cmm_lcms_LCMS
- * Method: freeProfile
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative
- (JNIEnv *env, jobject obj, jlong id)
-{
- storeID_t sProf;
-
- sProf.j = id;
- if (cmsCloseProfile(sProf.pf) == 0) {
- J2dRlsTraceLn1(J2D_TRACE_ERROR, "LCMS_freeProfile: cmsCloseProfile(%d)"
- "== 0", id);
- JNU_ThrowByName(env, "java/awt/color/CMMException",
- "Cannot close profile");
- }
-
-}
-
-/*
- * Class: sun_java2d_cmm_lcms_LCMS
- * Method: getProfileSize
+ * Method: getProfileSizeNative
* Signature: (J)I
*/
-JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileSize
+JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileSizeNative
(JNIEnv *env, jobject obj, jlong id)
{
storeID_t sProf;
cmsUInt32Number pfSize = 0;
sProf.j = id;
- if (cmsSaveProfileToMem(sProf.pf, NULL, &pfSize) && ((jint)pfSize > 0)) {
+ if (cmsSaveProfileToMem(sProf.lcmsPf->pf, NULL, &pfSize) && ((jint)pfSize > 0)) {
return (jint)pfSize;
} else {
JNU_ThrowByName(env, "java/awt/color/CMMException",
@@ -323,10 +339,10 @@
/*
* Class: sun_java2d_cmm_lcms_LCMS
- * Method: getProfileData
+ * Method: getProfileDataNative
* Signature: (J[B)V
*/
-JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileData
+JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileDataNative
(JNIEnv *env, jobject obj, jlong id, jbyteArray data)
{
storeID_t sProf;
@@ -338,7 +354,7 @@
sProf.j = id;
// determine actual profile size
- if (!cmsSaveProfileToMem(sProf.pf, NULL, &pfSize)) {
+ if (!cmsSaveProfileToMem(sProf.lcmsPf->pf, NULL, &pfSize)) {
JNU_ThrowByName(env, "java/awt/color/CMMException",
"Can not access specified profile.");
return;
@@ -354,7 +370,7 @@
dataArray = (*env)->GetByteArrayElements (env, data, 0);
- status = cmsSaveProfileToMem(sProf.pf, dataArray, &pfSize);
+ status = cmsSaveProfileToMem(sProf.lcmsPf->pf, dataArray, &pfSize);
(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
@@ -368,7 +384,7 @@
/* Get profile header info */
static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);
static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);
-static cmsBool _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size);
+static cmsHPROFILE _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size);
/*
@@ -412,7 +428,7 @@
return NULL;
}
- status = _getHeaderInfo(sProf.pf, dataArray, bufSize);
+ status = _getHeaderInfo(sProf.lcmsPf->pf, dataArray, bufSize);
(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
@@ -425,8 +441,8 @@
return data;
}
- if (cmsIsTag(sProf.pf, sig.cms)) {
- tagSize = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0);
+ if (cmsIsTag(sProf.lcmsPf->pf, sig.cms)) {
+ tagSize = cmsReadRawTag(sProf.lcmsPf->pf, sig.cms, NULL, 0);
} else {
JNU_ThrowByName(env, "java/awt/color/CMMException",
"ICC profile tag not found");
@@ -449,7 +465,7 @@
return NULL;
}
- bufSize = cmsReadRawTag(sProf.pf, sig.cms, dataArray, tagSize);
+ bufSize = cmsReadRawTag(sProf.lcmsPf->pf, sig.cms, dataArray, tagSize);
(*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
@@ -470,8 +486,10 @@
(JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data)
{
storeID_t sProf;
+ cmsHPROFILE pfReplace = NULL;
+
TagSignature_t sig;
- cmsBool status;
+ cmsBool status = FALSE;
jbyte* dataArray;
int tagSize;
@@ -493,15 +511,24 @@
}
if (tagSig == SigHead) {
- status = _setHeaderInfo(sProf.pf, dataArray, tagSize);
+ status = _setHeaderInfo(sProf.lcmsPf->pf, dataArray, tagSize);
} else {
- status = _writeCookedTag(sProf.pf, sig.cms, dataArray, tagSize);
+ /*
+ * New strategy for generic tags: create a place holder,
+ * dump all existing tags there, dump externally supplied
+ * tag, and return the new profile to the java.
+ */
+ pfReplace = _writeCookedTag(sProf.lcmsPf->pf, sig.cms, dataArray, tagSize);
+ status = (pfReplace != NULL);
}
(*env)->ReleaseByteArrayElements(env, data, dataArray, 0);
if (!status) {
JNU_ThrowIllegalArgumentException(env, "Can not write tag data.");
+ } else if (pfReplace != NULL) {
+ cmsCloseProfile(sProf.lcmsPf->pf);
+ sProf.lcmsPf->pf = pfReplace;
}
}
@@ -624,12 +651,27 @@
/*
* Class: sun_java2d_cmm_lcms_LCMS
* Method: getProfileID
- * Signature: (Ljava/awt/color/ICC_Profile;)J
+ * Signature: (Ljava/awt/color/ICC_Profile;)Lsun/java2d/cmm/lcms/LCMSProfile
*/
-JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileID
+JNIEXPORT jobject JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileID
(JNIEnv *env, jclass cls, jobject pf)
{
- return (*env)->GetLongField (env, pf, PF_ID_fID);
+ jfieldID fid = (*env)->GetFieldID (env,
+ (*env)->GetObjectClass(env, pf),
+ "cmmProfile", "Lsun/java2d/cmm/Profile;");
+
+ jclass clsLcmsProfile = (*env)->FindClass(env,
+ "sun/java2d/cmm/lcms/LCMSProfile");
+
+ jobject cmmProfile = (*env)->GetObjectField (env, pf, fid);
+
+ if (JNU_IsNull(env, cmmProfile)) {
+ return NULL;
+ }
+ if ((*env)->IsInstanceOf(env, cmmProfile, clsLcmsProfile)) {
+ return cmmProfile;
+ }
+ return NULL;
}
/*
@@ -644,7 +686,6 @@
* corresponding classes to avoid problems with invalidating ids by class
* unloading
*/
- Trans_profileIDs_fID = (*env)->GetFieldID (env, Trans, "profileIDs", "[J");
Trans_renderType_fID = (*env)->GetFieldID (env, Trans, "renderType", "I");
Trans_ID_fID = (*env)->GetFieldID (env, Trans, "ID", "J");
@@ -658,8 +699,6 @@
IL_offset_fID = (*env)->GetFieldID (env, IL, "offset", "I");
IL_imageAtOnce_fID = (*env)->GetFieldID (env, IL, "imageAtOnce", "Z");
IL_nextRowOffset_fID = (*env)->GetFieldID (env, IL, "nextRowOffset", "I");
-
- PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J");
}
static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)
@@ -714,76 +753,114 @@
return TRUE;
}
-static cmsBool _writeCookedTag(cmsHPROFILE pfTarget,
- cmsTagSignature sig,
+/* Returns new profile handler, if it was created successfully,
+ NULL otherwise.
+ */
+static cmsHPROFILE _writeCookedTag(const cmsHPROFILE pfTarget,
+ const cmsTagSignature sig,
jbyte *pData, jint size)
{
- cmsBool status;
cmsUInt32Number pfSize = 0;
- cmsUInt8Number* pfBuffer = NULL;
+ const cmsInt32Number tagCount = cmsGetTagCount(pfTarget);
+ cmsInt32Number i;
+ cmsHPROFILE pfSanity = NULL;
+
+ cmsICCHeader hdr = { 0 };
cmsHPROFILE p = cmsCreateProfilePlaceholder(NULL);
- if (NULL != p) {
- cmsICCHeader hdr = { 0 };
+
+ if (NULL == p) {
+ return NULL;
+ }
- /* Populate the placeholder's header according to target profile */
- hdr.flags = cmsGetHeaderFlags(pfTarget);
- hdr.renderingIntent = cmsGetHeaderRenderingIntent(pfTarget);
- hdr.manufacturer = cmsGetHeaderManufacturer(pfTarget);
- hdr.model = cmsGetHeaderModel(pfTarget);
- hdr.pcs = cmsGetPCS(pfTarget);
- hdr.colorSpace = cmsGetColorSpace(pfTarget);
- hdr.deviceClass = cmsGetDeviceClass(pfTarget);
- hdr.version = cmsGetEncodedICCversion(pfTarget);
- cmsGetHeaderAttributes(pfTarget, &hdr.attributes);
- cmsGetHeaderProfileID(pfTarget, (cmsUInt8Number*)&hdr.profileID);
+ // Populate the placeholder's header according to target profile
+ hdr.flags = cmsGetHeaderFlags(pfTarget);
+ hdr.renderingIntent = cmsGetHeaderRenderingIntent(pfTarget);
+ hdr.manufacturer = cmsGetHeaderManufacturer(pfTarget);
+ hdr.model = cmsGetHeaderModel(pfTarget);
+ hdr.pcs = cmsGetPCS(pfTarget);
+ hdr.colorSpace = cmsGetColorSpace(pfTarget);
+ hdr.deviceClass = cmsGetDeviceClass(pfTarget);
+ hdr.version = cmsGetEncodedICCversion(pfTarget);
+ cmsGetHeaderAttributes(pfTarget, &hdr.attributes);
+ cmsGetHeaderProfileID(pfTarget, (cmsUInt8Number*)&hdr.profileID);
- cmsSetHeaderFlags(p, hdr.flags);
- cmsSetHeaderManufacturer(p, hdr.manufacturer);
- cmsSetHeaderModel(p, hdr.model);
- cmsSetHeaderAttributes(p, hdr.attributes);
- cmsSetHeaderProfileID(p, (cmsUInt8Number*)&(hdr.profileID));
- cmsSetHeaderRenderingIntent(p, hdr.renderingIntent);
- cmsSetPCS(p, hdr.pcs);
- cmsSetColorSpace(p, hdr.colorSpace);
- cmsSetDeviceClass(p, hdr.deviceClass);
- cmsSetEncodedICCversion(p, hdr.version);
+ cmsSetHeaderFlags(p, hdr.flags);
+ cmsSetHeaderManufacturer(p, hdr.manufacturer);
+ cmsSetHeaderModel(p, hdr.model);
+ cmsSetHeaderAttributes(p, hdr.attributes);
+ cmsSetHeaderProfileID(p, (cmsUInt8Number*)&(hdr.profileID));
+ cmsSetHeaderRenderingIntent(p, hdr.renderingIntent);
+ cmsSetPCS(p, hdr.pcs);
+ cmsSetColorSpace(p, hdr.colorSpace);
+ cmsSetDeviceClass(p, hdr.deviceClass);
+ cmsSetEncodedICCversion(p, hdr.version);
+
+ // now write the user supplied tag
+ if (size <= 0 || !cmsWriteRawTag(p, sig, pData, size)) {
+ cmsCloseProfile(p);
+ return NULL;
+ }
+ // copy tags from the original profile
+ for (i = 0; i < tagCount; i++) {
+ cmsBool isTagReady = FALSE;
+ const cmsTagSignature s = cmsGetTagSignature(pfTarget, i);
+ const cmsInt32Number tagSize = cmsReadRawTag(pfTarget, s, NULL, 0);
- if (cmsWriteRawTag(p, sig, pData, size)) {
- if (cmsSaveProfileToMem(p, NULL, &pfSize)) {
- pfBuffer = malloc(pfSize);
- if (pfBuffer != NULL) {
- /* load raw profile data into the buffer */
- if (!cmsSaveProfileToMem(p, pfBuffer, &pfSize)) {
- free(pfBuffer);
- pfBuffer = NULL;
- }
+ if (s == sig) {
+ // skip the user supplied tag
+ continue;
+ }
+
+ // read raw tag from the original profile
+ if (tagSize > 0) {
+ cmsUInt8Number* buf = (cmsUInt8Number*)malloc(tagSize);
+ if (buf != NULL) {
+ if (tagSize == cmsReadRawTag(pfTarget, s, buf, tagSize)) {
+ // now we are ready to write the tag
+ isTagReady = cmsWriteRawTag(p, s, buf, tagSize);
}
+ free(buf);
}
}
- cmsCloseProfile(p);
+
+ if (!isTagReady) {
+ cmsCloseProfile(p);
+ return NULL;
+ }
}
- if (pfBuffer == NULL) {
- return FALSE;
+ // now we have all tags moved to the new profile.
+ // do some sanity checks: write it to a memory buffer and read again.
+ if (cmsSaveProfileToMem(p, NULL, &pfSize)) {
+ void* buf = malloc(pfSize);
+ if (buf != NULL) {
+ // load raw profile data into the buffer
+ if (cmsSaveProfileToMem(p, buf, &pfSize)) {
+ pfSanity = cmsOpenProfileFromMem(buf, pfSize);
+ }
+ free(buf);
+ }
}
- /* re-open the placeholder profile */
- p = cmsOpenProfileFromMem(pfBuffer, pfSize);
- free(pfBuffer);
- status = FALSE;
+ if (pfSanity == NULL) {
+ // for some reason, we failed to save and read the updated profile
+ // It likely indicates that the profile is not correct, so we report
+ // a failure here.
+ cmsCloseProfile(p);
+ p = NULL;
+ } else {
+ // do final check whether we can read and handle the the target tag.
+ const void* pTag = cmsReadTag(pfSanity, sig);
+ if (pTag == NULL) {
+ // the tag can not be cooked
+ cmsCloseProfile(p);
+ p = NULL;
+ }
+ cmsCloseProfile(pfSanity);
+ pfSanity = NULL;
+ }
- if (p != NULL) {
- /* Note that pCookedTag points to internal structures of the placeholder,
- * so this data is valid only while the placeholder is open.
- */
- void *pCookedTag = cmsReadTag(p, sig);
- if (pCookedTag != NULL) {
- status = cmsWriteTag(pfTarget, sig, pCookedTag);
- }
- pCookedTag = NULL;
- cmsCloseProfile(p);
- }
- return status;
+ return p;
}
--- a/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java Sat Sep 14 20:43:34 2013 +0100
@@ -54,6 +54,7 @@
import sun.security.action.GetPropertyAction;
import sun.security.action.GetBooleanAction;
import sun.util.logging.PlatformLogger;
+import sun.security.util.SecurityConstants;
public final class XToolkit extends UNIXToolkit implements Runnable {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XToolkit");
@@ -1152,7 +1153,7 @@
public Clipboard getSystemClipboard() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
- security.checkSystemClipboardAccess();
+ security.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
}
synchronized (this) {
if (clipboard == null) {
@@ -1165,7 +1166,7 @@
public Clipboard getSystemSelection() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
- security.checkSystemClipboardAccess();
+ security.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
}
synchronized (this) {
if (selection == null) {
--- a/jdk/src/solaris/classes/sun/font/XRTextRenderer.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/solaris/classes/sun/font/XRTextRenderer.java Sat Sep 14 20:43:34 2013 +0100
@@ -142,7 +142,7 @@
}
int maskFormat = containsLCDGlyphs ? XRUtils.PictStandardARGB32 : XRUtils.PictStandardA8;
- maskBuffer.compositeText(x11sd.picture, 0, maskFormat, eltList);
+ maskBuffer.compositeText(x11sd, (int) gl.getX(), (int) gl.getY(), 0, maskFormat, eltList);
eltList.clear();
} finally {
--- a/jdk/src/solaris/classes/sun/java2d/xr/XRBackendNative.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/solaris/classes/sun/java2d/xr/XRBackendNative.java Sat Sep 14 20:43:34 2013 +0100
@@ -267,8 +267,9 @@
private static native void
XRenderCompositeTextNative(int op, int src, int dst,
- long maskFormat, int[] eltArray,
- int[] glyphIDs, int eltCnt, int glyphCnt);
+ int srcX, int srcY, long maskFormat,
+ int[] eltArray, int[] glyphIDs, int eltCnt,
+ int glyphCnt);
public int XRenderCreateGlyphSet(int formatID) {
return XRenderCreateGlyphSetNative(getFormatPtr(formatID));
@@ -278,11 +279,11 @@
public void XRenderCompositeText(byte op, int src, int dst,
int maskFormatID,
- int src2, int src3, int dst2, int dst3,
+ int sx, int sy, int dx, int dy,
int glyphset, GrowableEltArray elts) {
GrowableIntArray glyphs = elts.getGlyphs();
- XRenderCompositeTextNative(op, src, dst, 0, elts.getArray(),
+ XRenderCompositeTextNative(op, src, dst, sx, sy, 0, elts.getArray(),
glyphs.getArray(), elts.getSize(),
glyphs.getSize());
}
--- a/jdk/src/solaris/classes/sun/java2d/xr/XRCompositeManager.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/solaris/classes/sun/java2d/xr/XRCompositeManager.java Sat Sep 14 20:43:34 2013 +0100
@@ -285,7 +285,12 @@
if (xorEnabled) {
con.GCRectangles(dst.getXid(), dst.getGC(), rects);
} else {
- con.renderRectangles(dst.getPicture(), compRule, solidColor, rects);
+ if (rects.getSize() == 1) {
+ con.renderRectangle(dst.getPicture(), compRule, solidColor,
+ rects.getX(0), rects.getY(0), rects.getWidth(0), rects.getHeight(0));
+ } else {
+ con.renderRectangles(dst.getPicture(), compRule, solidColor, rects);
+ }
}
}
@@ -295,10 +300,10 @@
sy, 0, 0, dx, dy, w, h);
}
- public void compositeText(int dst, int glyphSet, int maskFormat,
- GrowableEltArray elts) {
- con.XRenderCompositeText(compRule, src.picture, dst, maskFormat, 0, 0,
- 0, 0, glyphSet, elts);
+ public void compositeText(XRSurfaceData dst, int sx, int sy,
+ int glyphSet, int maskFormat, GrowableEltArray elts) {
+ con.XRenderCompositeText(compRule, src.picture, dst.picture,
+ maskFormat, sx, sy, 0, 0, glyphSet, elts);
}
public XRColor getMaskColor() {
--- a/jdk/src/solaris/classes/sun/java2d/xr/XRPMBlitLoops.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/solaris/classes/sun/java2d/xr/XRPMBlitLoops.java Sat Sep 14 20:43:34 2013 +0100
@@ -225,6 +225,9 @@
* @author Clemens Eisserer
*/
class XRPMTransformedBlit extends TransformBlit {
+ final Rectangle compositeBounds = new Rectangle();
+ final double[] srcCoords = new double[8];
+ final double[] dstCoords = new double[8];
public XRPMTransformedBlit(SurfaceType srcType, SurfaceType dstType) {
super(srcType, CompositeType.AnyAlpha, dstType);
@@ -235,61 +238,68 @@
* method is functionally equal to: Shape shp =
* xform.createTransformedShape(rect); Rectangle bounds = shp.getBounds();
* but performs significantly better.
+ * Returns true if the destination shape is parallel to x/y axis
*/
- public Rectangle getCompositeBounds(AffineTransform tr, int dstx, int dsty, int width, int height) {
- double[] compBounds = new double[8];
- compBounds[0] = dstx;
- compBounds[1] = dsty;
- compBounds[2] = dstx + width;
- compBounds[3] = dsty;
- compBounds[4] = dstx + width;
- compBounds[5] = dsty + height;
- compBounds[6] = dstx;
- compBounds[7] = dsty + height;
+ protected boolean adjustCompositeBounds(AffineTransform tr, int dstx, int dsty, int width, int height) {
+ srcCoords[0] = dstx;
+ srcCoords[1] = dsty;
+ srcCoords[2] = dstx + width;
+ srcCoords[3] = dsty;
+ srcCoords[4] = dstx + width;
+ srcCoords[5] = dsty + height;
+ srcCoords[6] = dstx;
+ srcCoords[7] = dsty + height;
+
+ tr.transform(srcCoords, 0, dstCoords, 0, 4);
- tr.transform(compBounds, 0, compBounds, 0, 4);
+ double minX = Math.min(dstCoords[0], Math.min(dstCoords[2], Math.min(dstCoords[4], dstCoords[6])));
+ double minY = Math.min(dstCoords[1], Math.min(dstCoords[3], Math.min(dstCoords[5], dstCoords[7])));
+ double maxX = Math.max(dstCoords[0], Math.max(dstCoords[2], Math.max(dstCoords[4], dstCoords[6])));
+ double maxY = Math.max(dstCoords[1], Math.max(dstCoords[3], Math.max(dstCoords[5], dstCoords[7])));
- double minX = Math.min(compBounds[0], Math.min(compBounds[2], Math.min(compBounds[4], compBounds[6])));
- double minY = Math.min(compBounds[1], Math.min(compBounds[3], Math.min(compBounds[5], compBounds[7])));
- double maxX = Math.max(compBounds[0], Math.max(compBounds[2], Math.max(compBounds[4], compBounds[6])));
- double maxY = Math.max(compBounds[1], Math.max(compBounds[3], Math.max(compBounds[5], compBounds[7])));
+ minX = Math.round(minX);
+ minY = Math.round(minY);
+ maxX = Math.round(maxX);
+ maxY = Math.round(maxY);
- minX = Math.floor(minX);
- minY = Math.floor(minY);
- maxX = Math.ceil(maxX);
- maxY = Math.ceil(maxY);
+ compositeBounds.x = (int) minX;
+ compositeBounds.y = (int) minY;
+ compositeBounds.width = (int) (maxX - minX);
+ compositeBounds.height = (int) (maxY - minY);
- return new Rectangle((int) minX, (int) minY, (int) (maxX - minX), (int) (maxY - minY));
+ boolean is0or180 = (dstCoords[1] == dstCoords[3]) && (dstCoords[2] == dstCoords[4]);
+ boolean is90or270 = (dstCoords[0] == dstCoords[2]) && (dstCoords[3] == dstCoords[5]);
+
+ return is0or180 || is90or270;
}
- public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform xform, int hint, int srcx, int srcy,
- int dstx, int dsty, int width, int height) {
+ public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform xform,
+ int hint, int srcx, int srcy, int dstx, int dsty, int width, int height) {
try {
SunToolkit.awtLock();
- int filter = XRUtils.ATransOpToXRQuality(hint);
+ XRSurfaceData x11sdDst = (XRSurfaceData) dst;
+ XRSurfaceData x11sdSrc = (XRSurfaceData) src;
- XRSurfaceData x11sdDst = (XRSurfaceData) dst;
+ int filter = XRUtils.ATransOpToXRQuality(hint);
+ boolean isAxisAligned = adjustCompositeBounds(xform, dstx, dsty, width, height);
+
x11sdDst.validateAsDestination(null, clip);
- XRSurfaceData x11sdSrc = (XRSurfaceData) src;
x11sdDst.maskBuffer.validateCompositeState(comp, null, null, null);
- Rectangle bounds = getCompositeBounds(xform, dstx, dsty, width, height);
-
- AffineTransform trx = AffineTransform.getTranslateInstance((-bounds.x), (-bounds.y));
+ AffineTransform trx = AffineTransform.getTranslateInstance(-compositeBounds.x, -compositeBounds.y);
trx.concatenate(xform);
AffineTransform maskTX = (AffineTransform) trx.clone();
-
trx.translate(-srcx, -srcy);
try {
trx.invert();
} catch (NoninvertibleTransformException ex) {
trx.setToIdentity();
- System.err.println("Reseted to identity!");
}
- boolean omitMask = isMaskOmittable(trx, comp, filter);
+ boolean omitMask = (filter == XRUtils.FAST)
+ || (isAxisAligned && ((AlphaComposite) comp).getAlpha() == 1.0f);
if (!omitMask) {
XRMaskImage mask = x11sdSrc.maskBuffer.getMaskImage();
@@ -297,33 +307,17 @@
x11sdSrc.validateAsSource(trx, XRUtils.RepeatPad, filter);
int maskPicture = mask.prepareBlitMask(x11sdDst, maskTX, width, height);
x11sdDst.maskBuffer.con.renderComposite(XRCompositeManager.getInstance(x11sdSrc).getCompRule(), x11sdSrc.picture, maskPicture, x11sdDst.picture,
- 0, 0, 0, 0, bounds.x, bounds.y, bounds.width, bounds.height);
+ 0, 0, 0, 0, compositeBounds.x, compositeBounds.y, compositeBounds.width, compositeBounds.height);
} else {
int repeat = filter == XRUtils.FAST ? XRUtils.RepeatNone : XRUtils.RepeatPad;
x11sdSrc.validateAsSource(trx, repeat, filter);
- x11sdDst.maskBuffer.compositeBlit(x11sdSrc, x11sdDst, 0, 0, bounds.x, bounds.y, bounds.width, bounds.height);
+ x11sdDst.maskBuffer.compositeBlit(x11sdSrc, x11sdDst, 0, 0, compositeBounds.x, compositeBounds.y, compositeBounds.width, compositeBounds.height);
}
} finally {
SunToolkit.awtUnlock();
}
}
-
- /* TODO: Is mask ever omitable??? ... should be for 90 degree rotation and no shear, but we always need to use RepeatPad */
- protected static boolean isMaskOmittable(AffineTransform trx, Composite comp, int filter) {
- return (filter == XRUtils.FAST || trx.getTranslateX() == (int) trx.getTranslateX() /*
- * If
- * translate
- * is
- * integer
- * only
- */
- && trx.getTranslateY() == (int) trx.getTranslateY() && (trx.getShearX() == 0 && trx.getShearY() == 0 // Only
- // 90 degree
- // rotation
- || trx.getShearX() == -trx.getShearY())) && ((AlphaComposite) comp).getAlpha() == 1.0f; // No
- // ExtraAlpha!=1
- }
}
class XrSwToPMBlit extends Blit {
--- a/jdk/src/solaris/native/java/lang/java_props_macosx.c Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/solaris/native/java/lang/java_props_macosx.c Sat Sep 14 20:43:34 2013 +0100
@@ -31,6 +31,7 @@
#include <Security/AuthSession.h>
#include <CoreFoundation/CoreFoundation.h>
#include <SystemConfiguration/SystemConfiguration.h>
+#include <Foundation/Foundation.h>
#include "java_props_macosx.h"
@@ -271,9 +272,20 @@
return c_exception;
}
+/*
+ * Method for fetching the user.home path and storing it in the property list.
+ * For signed .apps running in the Mac App Sandbox, user.home is set to the
+ * app's sandbox container.
+ */
+void setUserHome(java_props_t *sprops) {
+ if (sprops == NULL) { return; }
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ sprops->user_home = createUTF8CString((CFStringRef)NSHomeDirectory());
+ [pool drain];
+}
/*
- * Method for fetching proxy info and storing it in the propery list.
+ * Method for fetching proxy info and storing it in the property list.
*/
void setProxyProperties(java_props_t *sProps) {
if (sProps == NULL) return;
--- a/jdk/src/solaris/native/java/lang/java_props_macosx.h Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/solaris/native/java/lang/java_props_macosx.h Sat Sep 14 20:43:34 2013 +0100
@@ -27,6 +27,7 @@
char *setupMacOSXLocale(int cat);
void setOSNameAndVersion(java_props_t *sprops);
+void setUserHome(java_props_t *sprops);
void setProxyProperties(java_props_t *sProps);
enum PreferredToolkit_enum {
--- a/jdk/src/solaris/native/java/lang/java_props_md.c Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/solaris/native/java/lang/java_props_md.c Sat Sep 14 20:43:34 2013 +0100
@@ -591,7 +591,14 @@
{
struct passwd *pwent = getpwuid(getuid());
sprops.user_name = pwent ? strdup(pwent->pw_name) : "?";
- sprops.user_home = pwent ? strdup(pwent->pw_dir) : "?";
+#ifdef MACOSX
+ setUserHome(&sprops);
+#else
+ sprops.user_home = pwent ? strdup(pwent->pw_dir) : NULL;
+#endif
+ if (sprops.user_home == NULL) {
+ sprops.user_home = "?";
+ }
}
/* User TIMEZONE */
--- a/jdk/src/solaris/native/sun/java2d/x11/XRBackendNative.c Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/solaris/native/sun/java2d/x11/XRBackendNative.c Sat Sep 14 20:43:34 2013 +0100
@@ -911,8 +911,9 @@
JNIEXPORT void JNICALL
Java_sun_java2d_xr_XRBackendNative_XRenderCompositeTextNative
- (JNIEnv *env, jclass cls, jint op, jint src, jint dst, jlong maskFmt,
- jintArray eltArray, jintArray glyphIDArray, jint eltCnt, jint glyphCnt) {
+ (JNIEnv *env, jclass cls, jint op, jint src, jint dst,
+ jint sx, jint sy, jlong maskFmt, jintArray eltArray,
+ jintArray glyphIDArray, jint eltCnt, jint glyphCnt) {
jint i;
jint *ids;
jint *elts;
@@ -991,7 +992,7 @@
XRenderCompositeText32(awt_display, op, (Picture) src, (Picture) dst,
(XRenderPictFormat *) jlong_to_ptr(maskFmt),
- 0, 0, 0, 0, xelts, eltCnt);
+ sx, sy, 0, 0, xelts, eltCnt);
(*env)->ReleasePrimitiveArrayCritical(env, glyphIDArray, ids, JNI_ABORT);
(*env)->ReleasePrimitiveArrayCritical(env, eltArray, elts, JNI_ABORT);
--- a/jdk/src/windows/classes/sun/awt/windows/WPrinterJob.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/windows/classes/sun/awt/windows/WPrinterJob.java Sat Sep 14 20:43:34 2013 +0100
@@ -179,6 +179,7 @@
private static final int SET_RES_LOW = 0x00000080;
private static final int SET_COLOR = 0x00000200;
private static final int SET_ORIENTATION = 0x00004000;
+ private static final int SET_COLLATED = 0x00008000;
/**
* Values must match those defined in wingdi.h & commdlg.h
@@ -189,10 +190,33 @@
private static final int PD_NOSELECTION = 0x00000004;
private static final int PD_COLLATE = 0x00000010;
private static final int PD_PRINTTOFILE = 0x00000020;
- private static final int DM_ORIENTATION = 0x00000001;
- private static final int DM_PRINTQUALITY = 0x00000400;
- private static final int DM_COLOR = 0x00000800;
- private static final int DM_DUPLEX = 0x00001000;
+ private static final int DM_ORIENTATION = 0x00000001;
+ private static final int DM_PAPERSIZE = 0x00000002;
+ private static final int DM_COPIES = 0x00000100;
+ private static final int DM_DEFAULTSOURCE = 0x00000200;
+ private static final int DM_PRINTQUALITY = 0x00000400;
+ private static final int DM_COLOR = 0x00000800;
+ private static final int DM_DUPLEX = 0x00001000;
+ private static final int DM_YRESOLUTION = 0x00002000;
+ private static final int DM_COLLATE = 0x00008000;
+
+ private static final short DMCOLLATE_FALSE = 0;
+ private static final short DMCOLLATE_TRUE = 1;
+
+ private static final short DMORIENT_PORTRAIT = 1;
+ private static final short DMORIENT_LANDSCAPE = 2;
+
+ private static final short DMCOLOR_MONOCHROME = 1;
+ private static final short DMCOLOR_COLOR = 2;
+
+ private static final short DMRES_DRAFT = -1;
+ private static final short DMRES_LOW = -2;
+ private static final short DMRES_MEDIUM = -3;
+ private static final short DMRES_HIGH = -4;
+
+ private static final short DMDUP_SIMPLEX = 1;
+ private static final short DMDUP_VERTICAL = 2;
+ private static final short DMDUP_HORIZONTAL = 3;
/**
* Pageable MAX pages
@@ -592,13 +616,23 @@
}
driverDoesMultipleCopies = false;
driverDoesCollation = false;
- setNativePrintService(service.getName());
+ setNativePrintServiceIfNeeded(service.getName());
}
/* associates this job with the specified native service */
private native void setNativePrintService(String name)
throws PrinterException;
+ private String lastNativeService = null;
+ private void setNativePrintServiceIfNeeded(String name)
+ throws PrinterException {
+
+ if (name != null && !(name.equals(lastNativeService))) {
+ setNativePrintService(name);
+ lastNativeService = name;
+ }
+ }
+
public PrintService getPrintService() {
if (myService == null) {
String printerName = getNativePrintService();
@@ -616,7 +650,7 @@
myService = PrintServiceLookup.lookupDefaultPrintService();
if (myService != null) {
try {
- setNativePrintService(myService.getName());
+ setNativePrintServiceIfNeeded(myService.getName());
} catch (Exception e) {
myService = null;
}
@@ -1754,8 +1788,13 @@
mAttMediaSizeName = ((Win32PrintService)myService).findPaperID(msn);
}
- private void setWin32MediaAttrib(int dmIndex, int width, int length) {
- MediaSizeName msn =
+ private void addPaperSize(PrintRequestAttributeSet aset,
+ int dmIndex, int width, int length) {
+
+ if (aset == null) {
+ return;
+ }
+ MediaSizeName msn =
((Win32PrintService)myService).findWin32Media(dmIndex);
if (msn == null) {
msn = ((Win32PrintService)myService).
@@ -1763,10 +1802,12 @@
}
if (msn != null) {
- if (attributes != null) {
- attributes.add(msn);
- }
+ aset.add(msn);
}
+ }
+
+ private void setWin32MediaAttrib(int dmIndex, int width, int length) {
+ addPaperSize(attributes, dmIndex, width, length);
mAttMediaSizeName = dmIndex;
}
@@ -1788,7 +1829,7 @@
// no equivalent predefined value
mAttMediaTray = 7; // DMBIN_AUTO
} else if (attr == MediaTray.TOP) {
- mAttMediaTray =1; // DMBIN_UPPER
+ mAttMediaTray = 1; // DMBIN_UPPER
} else {
if (attr instanceof Win32MediaTray) {
mAttMediaTray = ((Win32MediaTray)attr).winID;
@@ -1914,6 +1955,254 @@
}
}
+ private static final class DevModeValues {
+ int dmFields;
+ short copies;
+ short collate;
+ short color;
+ short duplex;
+ short orient;
+ short paper;
+ short bin;
+ short xres_quality;
+ short yres;
+ }
+
+ private void getDevModeValues(PrintRequestAttributeSet aset,
+ DevModeValues info) {
+
+ Copies c = (Copies)aset.get(Copies.class);
+ if (c != null) {
+ info.dmFields |= DM_COPIES;
+ info.copies = (short)c.getValue();
+ }
+
+ SheetCollate sc = (SheetCollate)aset.get(SheetCollate.class);
+ if (sc != null) {
+ info.dmFields |= DM_COLLATE;
+ info.collate = (sc == SheetCollate.COLLATED) ?
+ DMCOLLATE_TRUE : DMCOLLATE_FALSE;
+ }
+
+ Chromaticity ch = (Chromaticity)aset.get(Chromaticity.class);
+ if (ch != null) {
+ info.dmFields |= DM_COLOR;
+ if (ch == Chromaticity.COLOR) {
+ info.color = DMCOLOR_COLOR;
+ } else {
+ info.color = DMCOLOR_MONOCHROME;
+ }
+ }
+
+ Sides s = (Sides)aset.get(Sides.class);
+ if (s != null) {
+ info.dmFields |= DM_DUPLEX;
+ if (s == Sides.TWO_SIDED_LONG_EDGE) {
+ info.duplex = DMDUP_VERTICAL;
+ } else if (s == Sides.TWO_SIDED_SHORT_EDGE) {
+ info.duplex = DMDUP_HORIZONTAL;
+ } else { // Sides.ONE_SIDED
+ info.duplex = DMDUP_SIMPLEX;
+ }
+ }
+
+ OrientationRequested or =
+ (OrientationRequested)aset.get(OrientationRequested.class);
+ if (or != null) {
+ info.dmFields |= DM_ORIENTATION;
+ info.orient = (or == OrientationRequested.LANDSCAPE)
+ ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT;
+ }
+
+ Media m = (Media)aset.get(Media.class);
+ if (m instanceof MediaSizeName) {
+ info.dmFields |= DM_PAPERSIZE;
+ MediaSizeName msn = (MediaSizeName)m;
+ info.paper =
+ (short)((Win32PrintService)myService).findPaperID(msn);
+ }
+
+ MediaTray mt = null;
+ if (m instanceof MediaTray) {
+ mt = (MediaTray)m;
+ }
+ if (mt == null) {
+ SunAlternateMedia sam =
+ (SunAlternateMedia)aset.get(SunAlternateMedia.class);
+ if (sam != null && (sam.getMedia() instanceof MediaTray)) {
+ mt = (MediaTray)sam.getMedia();
+ }
+ }
+
+ if (mt != null) {
+ info.dmFields |= DM_DEFAULTSOURCE;
+ info.bin = (short)(((Win32PrintService)myService).findTrayID(mt));
+ }
+
+ PrintQuality q = (PrintQuality)aset.get(PrintQuality.class);
+ if (q != null) {
+ info.dmFields |= DM_PRINTQUALITY;
+ if (q == PrintQuality.DRAFT) {
+ info.xres_quality = DMRES_DRAFT;
+ } else if (q == PrintQuality.HIGH) {
+ info.xres_quality = DMRES_HIGH;
+ } else {
+ info.xres_quality = DMRES_MEDIUM;
+ }
+ }
+
+ PrinterResolution r =
+ (PrinterResolution)aset.get(PrinterResolution.class);
+ if (r != null) {
+ info.dmFields |= DM_PRINTQUALITY | DM_YRESOLUTION;
+ info.xres_quality =
+ (short)r.getCrossFeedResolution(PrinterResolution.DPI);
+ info.yres = (short)r.getFeedResolution(PrinterResolution.DPI);
+ }
+ }
+
+ /* This method is called from native to update the values in the
+ * attribute set which originates from the cross-platform dialog,
+ * but updated by the native DocumentPropertiesUI which updates the
+ * devmode. This syncs the devmode back in to the attributes so that
+ * we can update the cross-platform dialog.
+ * The attribute set here is a temporary one installed whilst this
+ * happens,
+ */
+ private final void setJobAttributes(PrintRequestAttributeSet attributes,
+ int fields, int values,
+ short copies,
+ short dmPaperSize,
+ short dmPaperWidth,
+ short dmPaperLength,
+ short dmDefaultSource,
+ short xRes,
+ short yRes) {
+
+ if (attributes == null) {
+ return;
+ }
+
+ if ((fields & DM_COPIES) != 0) {
+ attributes.add(new Copies(copies));
+ }
+
+ if ((fields & DM_COLLATE) != 0) {
+ if ((values & SET_COLLATED) != 0) {
+ attributes.add(SheetCollate.COLLATED);
+ } else {
+ attributes.add(SheetCollate.UNCOLLATED);
+ }
+ }
+
+ if ((fields & DM_ORIENTATION) != 0) {
+ if ((values & SET_ORIENTATION) != 0) {
+ attributes.add(OrientationRequested.LANDSCAPE);
+ } else {
+ attributes.add(OrientationRequested.PORTRAIT);
+ }
+ }
+
+ if ((fields & DM_COLOR) != 0) {
+ if ((values & SET_COLOR) != 0) {
+ attributes.add(Chromaticity.COLOR);
+ } else {
+ attributes.add(Chromaticity.MONOCHROME);
+ }
+ }
+
+ if ((fields & DM_PRINTQUALITY) != 0) {
+ /* value < 0 indicates quality setting.
+ * value > 0 indicates X resolution. In that case
+ * hopefully we will also find y-resolution specified.
+ * If its not, assume its the same as x-res.
+ * Maybe Java code should try to reconcile this against
+ * the printers claimed set of supported resolutions.
+ */
+ if (xRes < 0) {
+ PrintQuality quality;
+ if ((values & SET_RES_LOW) != 0) {
+ quality = PrintQuality.DRAFT;
+ } else if ((fields & SET_RES_HIGH) != 0) {
+ quality = PrintQuality.HIGH;
+ } else {
+ quality = PrintQuality.NORMAL;
+ }
+ attributes.add(quality);
+ } else if (xRes > 0 && yRes > 0) {
+ attributes.add(
+ new PrinterResolution(xRes, yRes, PrinterResolution.DPI));
+ }
+ }
+
+ if ((fields & DM_DUPLEX) != 0) {
+ Sides sides;
+ if ((values & SET_DUP_VERTICAL) != 0) {
+ sides = Sides.TWO_SIDED_LONG_EDGE;
+ } else if ((values & SET_DUP_HORIZONTAL) != 0) {
+ sides = Sides.TWO_SIDED_SHORT_EDGE;
+ } else {
+ sides = Sides.ONE_SIDED;
+ }
+ attributes.add(sides);
+ }
+
+ if ((fields & DM_PAPERSIZE) != 0) {
+ addPaperSize(attributes, dmPaperSize, dmPaperWidth, dmPaperLength);
+ }
+
+ if ((fields & DM_DEFAULTSOURCE) != 0) {
+ MediaTray tray =
+ ((Win32PrintService)myService).findMediaTray(dmDefaultSource);
+ attributes.add(new SunAlternateMedia(tray));
+ }
+ }
+
+ private native boolean showDocProperties(long hWnd,
+ PrintRequestAttributeSet aset,
+ int dmFields,
+ short copies,
+ short collate,
+ short color,
+ short duplex,
+ short orient,
+ short paper,
+ short bin,
+ short xres_quality,
+ short yres);
+
+ @SuppressWarnings("deprecation")
+ public PrintRequestAttributeSet
+ showDocumentProperties(Window owner,
+ PrintService service,
+ PrintRequestAttributeSet aset)
+ {
+ try {
+ setNativePrintServiceIfNeeded(service.getName());
+ } catch (PrinterException e) {
+ }
+ long hWnd = ((WWindowPeer)(owner.getPeer())).getHWnd();
+ DevModeValues info = new DevModeValues();
+ getDevModeValues(aset, info);
+ boolean ok =
+ showDocProperties(hWnd, aset,
+ info.dmFields,
+ info.copies,
+ info.collate,
+ info.color,
+ info.duplex,
+ info.orient,
+ info.paper,
+ info.bin,
+ info.xres_quality,
+ info.yres);
+
+ if (ok) {
+ return aset;
+ } else {
+ return null;
+ }
+ }
/* Printer Resolution. See also getXRes() and getYRes() */
private final void setResolutionDPI(int xres, int yres) {
@@ -1956,7 +2245,7 @@
}
//** END Functions called by native code for querying/updating attributes
- }
+ }
class PrintToFileErrorDialog extends Dialog implements ActionListener{
public PrintToFileErrorDialog(Frame parent, String title, String message,
--- a/jdk/src/windows/classes/sun/awt/windows/WToolkit.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/windows/classes/sun/awt/windows/WToolkit.java Sat Sep 14 20:43:34 2013 +0100
@@ -64,6 +64,7 @@
import sun.font.SunFontManager;
import sun.misc.PerformanceLogger;
import sun.util.logging.PlatformLogger;
+import sun.security.util.SecurityConstants;
public class WToolkit extends SunToolkit implements Runnable {
@@ -681,7 +682,7 @@
public Clipboard getSystemClipboard() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
- security.checkSystemClipboardAccess();
+ security.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
}
synchronized (this) {
if (clipboard == null) {
--- a/jdk/src/windows/classes/sun/print/Win32MediaTray.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/windows/classes/sun/print/Win32MediaTray.java Sat Sep 14 20:43:34 2013 +0100
@@ -70,6 +70,10 @@
winEnumTable.add(this);
}
+ public int getDMBinID() {
+ return winID;
+ }
+
private static final String[] myStringTable ={
"Manual-Envelope",
"Automatic-Feeder",
--- a/jdk/src/windows/classes/sun/print/Win32PrintService.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/windows/classes/sun/print/Win32PrintService.java Sat Sep 14 20:43:34 2013 +0100
@@ -25,6 +25,8 @@
package sun.print;
+import java.awt.Window;
+import java.awt.print.PrinterJob;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
@@ -39,6 +41,7 @@
import javax.print.attribute.AttributeSetUtilities;
import javax.print.attribute.EnumSyntax;
import javax.print.attribute.HashAttributeSet;
+import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.PrintServiceAttribute;
import javax.print.attribute.PrintServiceAttributeSet;
import javax.print.attribute.HashPrintServiceAttributeSet;
@@ -69,6 +72,7 @@
import javax.print.attribute.standard.PrinterResolution;
import javax.print.attribute.standard.SheetCollate;
import javax.print.event.PrintServiceAttributeListener;
+import sun.awt.windows.WPrinterJob;
public class Win32PrintService implements PrintService, AttributeUpdater,
SunPrinterJobService {
@@ -282,6 +286,22 @@
return 0;
}
+ public int findTrayID(MediaTray tray) {
+
+ getMediaTrays(); // make sure they are initialised.
+
+ if (tray instanceof Win32MediaTray) {
+ Win32MediaTray winTray = (Win32MediaTray)tray;
+ return winTray.getDMBinID();
+ }
+ for (int id=0; id<dmPaperBinToPrintService.length; id++) {
+ if (tray.equals(dmPaperBinToPrintService[id])) {
+ return id+1; // DMBIN_FIRST = 1;
+ }
+ }
+ return 0; // didn't find the tray
+ }
+
public MediaTray findMediaTray(int dmBin) {
if (dmBin >= 1 && dmBin <= dmPaperBinToPrintService.length) {
return dmPaperBinToPrintService[dmBin-1];
@@ -673,7 +693,6 @@
return arr2;
}
-
private PrinterIsAcceptingJobs getPrinterIsAcceptingJobs() {
if (getJobStatus(printer, 2) != 1) {
return PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS;
@@ -1596,8 +1615,76 @@
}
}
- public ServiceUIFactory getServiceUIFactory() {
- return null;
+ private Win32DocumentPropertiesUI docPropertiesUI = null;
+
+ private static class Win32DocumentPropertiesUI
+ extends DocumentPropertiesUI {
+
+ Win32PrintService service;
+
+ private Win32DocumentPropertiesUI(Win32PrintService s) {
+ service = s;
+ }
+
+ public PrintRequestAttributeSet
+ showDocumentProperties(PrinterJob job,
+ Window owner,
+ PrintService service,
+ PrintRequestAttributeSet aset) {
+
+ if (!(job instanceof WPrinterJob)) {
+ return null;
+ }
+ WPrinterJob wJob = (WPrinterJob)job;
+ return wJob.showDocumentProperties(owner, service, aset);
+ }
+ }
+
+ private synchronized DocumentPropertiesUI getDocumentPropertiesUI() {
+ return new Win32DocumentPropertiesUI(this);
+ }
+
+ private static class Win32ServiceUIFactory extends ServiceUIFactory {
+
+ Win32PrintService service;
+
+ Win32ServiceUIFactory(Win32PrintService s) {
+ service = s;
+ }
+
+ public Object getUI(int role, String ui) {
+ if (role <= ServiceUIFactory.MAIN_UIROLE) {
+ return null;
+ }
+ if (role == DocumentPropertiesUI.DOCUMENTPROPERTIES_ROLE &&
+ DocumentPropertiesUI.DOCPROPERTIESCLASSNAME.equals(ui))
+ {
+ return service.getDocumentPropertiesUI();
+ }
+ throw new IllegalArgumentException("Unsupported role");
+ }
+
+ public String[] getUIClassNamesForRole(int role) {
+
+ if (role <= ServiceUIFactory.MAIN_UIROLE) {
+ return null;
+ }
+ if (role == DocumentPropertiesUI.DOCUMENTPROPERTIES_ROLE) {
+ String[] names = new String[0];
+ names[0] = DocumentPropertiesUI.DOCPROPERTIESCLASSNAME;
+ return names;
+ }
+ throw new IllegalArgumentException("Unsupported role");
+ }
+ }
+
+ private Win32ServiceUIFactory uiFactory = null;
+
+ public synchronized ServiceUIFactory getServiceUIFactory() {
+ if (uiFactory == null) {
+ uiFactory = new Win32ServiceUIFactory(this);
+ }
+ return uiFactory;
}
public String toString() {
--- a/jdk/src/windows/classes/sun/security/mscapi/Key.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/windows/classes/sun/security/mscapi/Key.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -39,6 +39,7 @@
*/
abstract class Key implements java.security.Key, Length
{
+ private static final long serialVersionUID = -1088859394025049194L;
// Native handle
protected long hCryptProv = 0;
--- a/jdk/src/windows/native/java/net/NetworkInterface.c Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/windows/native/java/net/NetworkInterface.c Sat Sep 14 20:43:34 2013 +0100
@@ -900,7 +900,7 @@
MIB_IFROW *ifRowP;
ifRowP = getIF(index);
if (ifRowP != NULL) {
- ret = ifRowP->dwAdminStatus == 1 &&
+ ret = ifRowP->dwAdminStatus == MIB_IF_ADMIN_STATUS_UP &&
(ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL ||
ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED);
free(ifRowP);
--- a/jdk/src/windows/native/java/net/NetworkInterface_winXP.c Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/windows/native/java/net/NetworkInterface_winXP.c Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -82,7 +82,6 @@
IP_ADAPTER_ADDRESSES *adapterInfo;
ULONG len;
adapterInfo = (IP_ADAPTER_ADDRESSES *)malloc (bufsize);
-
if (adapterInfo == NULL) {
JNU_ThrowByName(env, "java/lang/OutOfMemoryError", "Native heap allocation failure");
return -1;
@@ -160,8 +159,12 @@
ptr = adapterInfo;
ret = NULL;
while (ptr != NULL) {
- // IPv4 interface
- if (ptr->Ipv6IfIndex == index) {
+ // in theory the IPv4 index and the IPv6 index can be the same
+ // where an interface is enabled for v4 and v6
+ // IfIndex == 0 IPv4 not available on this interface
+ // Ipv6IfIndex == 0 IPv6 not available on this interface
+ if (((ptr->IfIndex != 0)&&(ptr->IfIndex == index)) ||
+ ((ptr->Ipv6IfIndex !=0) && (ptr->Ipv6IfIndex == index))) {
ret = (IP_ADAPTER_ADDRESSES *) malloc(sizeof(IP_ADAPTER_ADDRESSES));
if (ret == NULL) {
free(adapterInfo);
@@ -172,6 +175,7 @@
//copy the memory and break out of the while loop.
memcpy(ret, ptr, sizeof(IP_ADAPTER_ADDRESSES));
break;
+
}
ptr=ptr->Next;
}
@@ -192,7 +196,6 @@
int tun=0, net=0;
*netifPP = NULL;
-
/*
* Get the IPv4 interfaces. This information is the same
* as what previous JDK versions would return.
@@ -264,7 +267,7 @@
* set the index to the IPv6 index and add the
* IPv6 addresses
*/
- nif->index = ptr->Ipv6IfIndex;
+ nif->ipv6Index = ptr->Ipv6IfIndex;
c = getAddrsFromAdapter(ptr, &nif->addrs);
nif->naddrs += c;
break;
@@ -309,6 +312,9 @@
strcpy (nif->name, newname);
wcscpy ((PWCHAR)nif->displayName, ptr->FriendlyName);
nif->dNameIsUnicode = TRUE;
+
+ // the java.net.NetworkInterface abstraction only has index
+ // so the Ipv6IfIndex needs to map onto index
nif->index = ptr->Ipv6IfIndex;
nif->ipv6Index = ptr->Ipv6IfIndex;
nif->hasIpv6Address = TRUE;
@@ -487,7 +493,6 @@
(*env)->SetObjectField(env, netifObj, ni_nameID, name);
(*env)->SetObjectField(env, netifObj, ni_displayNameID, displayName);
(*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);
-
/*
* Get the IP addresses for this interface if necessary
* Note that 0 is a valid number of addresses.
--- a/jdk/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c Sat Sep 14 20:43:34 2013 +0100
@@ -43,6 +43,7 @@
#include "java_net_SocketOptions.h"
#include "java_net_NetworkInterface.h"
+#include "NetworkInterface.h"
#include "jvm.h"
#include "jni_util.h"
#include "net_util.h"
@@ -1644,6 +1645,33 @@
return (*env)->GetIntField(env, nif, ni_indexID);
}
+static int isAdapterIpv6Enabled(JNIEnv *env, int index) {
+ netif *ifList, *curr;
+ int ipv6Enabled = 0;
+ if (getAllInterfacesAndAddresses (env, &ifList) < 0) {
+ return ipv6Enabled;
+ }
+
+ /* search by index */
+ curr = ifList;
+ while (curr != NULL) {
+ if (index == curr->index) {
+ break;
+ }
+ curr = curr->next;
+ }
+
+ /* if found ipv6Index != 0 then interface is configured with IPV6 */
+ if ((curr != NULL) && (curr->ipv6Index !=0)) {
+ ipv6Enabled = 1;
+ }
+
+ /* release the interface list */
+ free_netif(ifList);
+
+ return ipv6Enabled;
+}
+
/*
* Sets the multicast interface.
*
@@ -1703,7 +1731,6 @@
struct in_addr in;
in.s_addr = htonl(getInetAddress_addr(env, value));
-
if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
(const char*)&in, sizeof(in)) < 0) {
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
@@ -1734,19 +1761,20 @@
}
index = (*env)->GetIntField(env, value, ni_indexID);
- if (setsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+ if ( isAdapterIpv6Enabled(env, index) != 0 ) {
+ if (setsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
(const char*)&index, sizeof(index)) < 0) {
- if (errno == EINVAL && index > 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "IPV6_MULTICAST_IF failed (interface has IPv4 "
- "address only?)");
- } else {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+ if (errno == EINVAL && index > 0) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "IPV6_MULTICAST_IF failed (interface has IPv4 "
+ "address only?)");
+ } else {
+ NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
"Error setting socket option");
+ }
+ return;
}
- return;
}
-
/* If there are any IPv4 addresses on this interface then
* repeat the operation on the IPv4 fd */
@@ -1797,7 +1825,6 @@
char c;
} optval;
int ipv6_supported = ipv6_available();
-
fd = getFD(env, this);
if (ipv6_supported) {
@@ -1898,42 +1925,21 @@
}
/*
- * Return the multicast interface:
- *
- * SocketOptions.IP_MULTICAST_IF
- * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
- * Create InetAddress
- * IP_MULTICAST_IF returns struct ip_mreqn on 2.2
- * kernel but struct in_addr on 2.4 kernel
- * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF or
- * obtain from impl is Linux 2.2 kernel
- * If index == 0 return InetAddress representing
- * anyLocalAddress.
- * If index > 0 query NetworkInterface by index
- * and returns addrs[0]
*
- * SocketOptions.IP_MULTICAST_IF2
- * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
- * Query NetworkInterface by IP address and
- * return the NetworkInterface that the address
- * is bound too.
- * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
- * (except Linux .2 kernel)
- * Query NetworkInterface by index and
- * return NetworkInterface.
+ * called by getMulticastInterface to retrieve a NetworkInterface
+ * configured for IPv4.
+ * The ipv4Mode parameter, is a closet boolean, which allows for a NULL return,
+ * or forces the creation of a NetworkInterface object with null data.
+ * It relates to its calling context in getMulticastInterface.
+ * ipv4Mode == 1, the context is IPV4 processing only.
+ * ipv4Mode == 0, the context is IPV6 processing
+ *
*/
-jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint opt) {
- jboolean isIPV4 = !ipv6_available() || fd1 == -1;
-
- /*
- * IPv4 implementation
- */
- if (isIPV4) {
+static jobject getIPv4NetworkInterface (JNIEnv *env, jobject this, int fd, jint opt, int ipv4Mode) {
static jclass inet4_class;
static jmethodID inet4_ctrID;
- static jclass ni_class;
- static jmethodID ni_ctrID;
+ static jclass ni_class; static jmethodID ni_ctrID;
static jfieldID ni_indexID;
static jfieldID ni_addrsID;
@@ -1944,7 +1950,6 @@
struct in_addr in;
struct in_addr *inP = ∈
int len = sizeof(struct in_addr);
-
if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
(char *)inP, &len) < 0) {
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
@@ -1996,24 +2001,58 @@
if (ni) {
return ni;
}
+ if (ipv4Mode) {
+ ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
+ CHECK_NULL_RETURN(ni, NULL);
- /*
- * The address doesn't appear to be bound at any known
- * NetworkInterface. Therefore we construct a NetworkInterface
- * with this address.
- */
- ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
- CHECK_NULL_RETURN(ni, NULL);
+ (*env)->SetIntField(env, ni, ni_indexID, -1);
+ addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL);
+ CHECK_NULL_RETURN(addrArray, NULL);
+ (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
+ (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
+ } else {
+ ni = NULL;
+ }
+ return ni;
+}
- (*env)->SetIntField(env, ni, ni_indexID, -1);
- addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL);
- CHECK_NULL_RETURN(addrArray, NULL);
- (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
- (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
- return ni;
+/*
+ * Return the multicast interface:
+ *
+ * SocketOptions.IP_MULTICAST_IF
+ * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
+ * Create InetAddress
+ * IP_MULTICAST_IF returns struct ip_mreqn on 2.2
+ * kernel but struct in_addr on 2.4 kernel
+ * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF or
+ * obtain from impl is Linux 2.2 kernel
+ * If index == 0 return InetAddress representing
+ * anyLocalAddress.
+ * If index > 0 query NetworkInterface by index
+ * and returns addrs[0]
+ *
+ * SocketOptions.IP_MULTICAST_IF2
+ * IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
+ * Query NetworkInterface by IP address and
+ * return the NetworkInterface that the address
+ * is bound too.
+ * IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
+ * (except Linux .2 kernel)
+ * Query NetworkInterface by index and
+ * return NetworkInterface.
+ */
+jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint opt) {
+ jboolean isIPV4 = !ipv6_available() || fd1 == -1;
+
+ /*
+ * IPv4 implementation
+ */
+ if (isIPV4) {
+ jobject netObject = NULL; // return is either an addr or a netif
+ netObject = getIPv4NetworkInterface(env, this, fd, opt, 1);
+ return netObject;
}
-
/*
* IPv6 implementation
*/
@@ -2103,6 +2142,13 @@
addr = (*env)->GetObjectArrayElement(env, addrArray, 0);
return addr;
+ } else if (index == 0) { // index == 0 typically means IPv6 not configured on the interfaces
+ // falling back to treat interface as configured for IPv4
+ jobject netObject = NULL;
+ netObject = getIPv4NetworkInterface(env, this, fd, opt, 0);
+ if (netObject != NULL) {
+ return netObject;
+ }
}
/*
@@ -2127,6 +2173,8 @@
}
return NULL;
}
+
+
/*
* Returns relevant info as a jint.
*
--- a/jdk/src/windows/native/sun/windows/awt_PrintControl.cpp Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/windows/native/sun/windows/awt_PrintControl.cpp Sat Sep 14 20:43:34 2013 +0100
@@ -81,6 +81,7 @@
jmethodID AwtPrintControl::setNativeAttID;
jmethodID AwtPrintControl::setRangeCopiesID;
jmethodID AwtPrintControl::setResID;
+jmethodID AwtPrintControl::setJobAttributesID;
BOOL AwtPrintControl::IsSupportedLevel(HANDLE hPrinter, DWORD dwLevel) {
@@ -297,6 +298,10 @@
AwtPrintControl::setPrinterID =
env->GetMethodID(cls, "setPrinterNameAttrib", "(Ljava/lang/String;)V");
+ AwtPrintControl::setJobAttributesID =
+ env->GetMethodID(cls, "setJobAttributes",
+ "(Ljavax/print/attribute/PrintRequestAttributeSet;IISSSSSSS)V");
+
DASSERT(AwtPrintControl::driverDoesMultipleCopiesID != NULL);
DASSERT(AwtPrintControl::getPrintDCID != NULL);
DASSERT(AwtPrintControl::setPrintDCID != NULL);
@@ -327,6 +332,7 @@
DASSERT(AwtPrintControl::getSidesID != NULL);
DASSERT(AwtPrintControl::getSelectID != NULL);
DASSERT(AwtPrintControl::getPrintToFileEnabledID != NULL);
+ DASSERT(AwtPrintControl::setJobAttributesID != NULL);
CATCH_BAD_ALLOC;
--- a/jdk/src/windows/native/sun/windows/awt_PrintControl.h Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/windows/native/sun/windows/awt_PrintControl.h Sat Sep 14 20:43:34 2013 +0100
@@ -47,7 +47,6 @@
static jmethodID setDevmodeID;
static jmethodID getDevnamesID;
static jmethodID setDevnamesID;
-
static jmethodID getWin32MediaID;
static jmethodID setWin32MediaID;
static jmethodID getWin32MediaTrayID;
@@ -73,6 +72,7 @@
static jmethodID setNativeAttID;
static jmethodID setRangeCopiesID;
static jmethodID setResID;
+ static jmethodID setJobAttributesID;
static void initIDs(JNIEnv *env, jclass cls);
static BOOL FindPrinter(jstring printerName, LPBYTE pPrinterEnum,
--- a/jdk/src/windows/native/sun/windows/awt_PrintJob.cpp Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/src/windows/native/sun/windows/awt_PrintJob.cpp Sat Sep 14 20:43:34 2013 +0100
@@ -329,6 +329,156 @@
static int embolden(int currentWeight);
static BOOL getPrintableArea(HDC pdc, HANDLE hDevMode, RectDouble *margin);
+
+
+/************************************************************************
+ * DocumentProperties native support
+ */
+
+/* Values must match those defined in WPrinterJob.java */
+static const DWORD SET_COLOR = 0x00000200;
+static const DWORD SET_ORIENTATION = 0x00004000;
+static const DWORD SET_COLLATED = 0x00008000;
+static const DWORD SET_DUP_VERTICAL = 0x00000010;
+static const DWORD SET_DUP_HORIZONTAL = 0x00000020;
+static const DWORD SET_RES_HIGH = 0x00000040;
+static const DWORD SET_RES_LOW = 0x00000080;
+
+/*
+ * Copy DEVMODE state back into JobAttributes.
+ */
+
+static void UpdateJobAttributes(JNIEnv *env,
+ jobject wJob,
+ jobject attrSet,
+ DEVMODE *devmode) {
+
+ DWORD dmValues = 0;
+ int xRes = 0, yRes = 0;
+
+ if (devmode->dmFields & DM_COLOR) {
+ if (devmode->dmColor == DMCOLOR_COLOR) {
+ dmValues |= SET_COLOR;
+ }
+ }
+
+ if (devmode->dmFields & DM_ORIENTATION) {
+ if (devmode->dmOrientation == DMORIENT_LANDSCAPE) {
+ dmValues |= SET_ORIENTATION;
+ }
+ }
+
+ if (devmode->dmFields & DM_COLLATE &&
+ devmode->dmCollate == DMCOLLATE_TRUE) {
+ dmValues |= SET_COLLATED;
+ }
+
+ if (devmode->dmFields & DM_PRINTQUALITY) {
+ /* value < 0 indicates quality setting.
+ * value > 0 indicates X resolution. In that case
+ * hopefully we will also find y-resolution specified.
+ * If its not, assume its the same as x-res.
+ * Maybe Java code should try to reconcile this against
+ * the printers claimed set of supported resolutions.
+ */
+ if (devmode->dmPrintQuality < 0) {
+ if (devmode->dmPrintQuality == DMRES_HIGH) {
+ dmValues |= SET_RES_HIGH;
+ } else if ((devmode->dmPrintQuality == DMRES_LOW) ||
+ (devmode->dmPrintQuality == DMRES_DRAFT)) {
+ dmValues |= SET_RES_LOW;
+ }
+ /* else if (devmode->dmPrintQuality == DMRES_MEDIUM)
+ * will set to NORMAL.
+ */
+ } else {
+ xRes = devmode->dmPrintQuality;
+ yRes = (devmode->dmFields & DM_YRESOLUTION) ?
+ devmode->dmYResolution : devmode->dmPrintQuality;
+ }
+ }
+
+ if (devmode->dmFields & DM_DUPLEX) {
+ if (devmode->dmDuplex == DMDUP_HORIZONTAL) {
+ dmValues |= SET_DUP_HORIZONTAL;
+ } else if (devmode->dmDuplex == DMDUP_VERTICAL) {
+ dmValues |= SET_DUP_VERTICAL;
+ }
+ }
+
+ env->CallVoidMethod(wJob, AwtPrintControl::setJobAttributesID, attrSet,
+ devmode->dmFields, dmValues, devmode->dmCopies,
+ devmode->dmPaperSize, devmode->dmPaperWidth,
+ devmode->dmPaperLength, devmode->dmDefaultSource,
+ xRes, yRes);
+
+}
+
+JNIEXPORT jboolean JNICALL
+Java_sun_awt_windows_WPrinterJob_showDocProperties(JNIEnv *env,
+ jobject wJob,
+ jlong hWndParent,
+ jobject attrSet,
+ jint dmFields,
+ jshort copies,
+ jshort collate,
+ jshort color,
+ jshort duplex,
+ jshort orient,
+ jshort paper,
+ jshort bin,
+ jshort xres_quality,
+ jshort yres)
+{
+ TRY;
+
+ HGLOBAL hDevMode = AwtPrintControl::getPrintHDMode(env, wJob);
+ HGLOBAL hDevNames = AwtPrintControl::getPrintHDName(env, wJob);
+ DEVMODE *devmode = NULL;
+ DEVNAMES *devnames = NULL;
+ LONG rval = IDCANCEL;
+ jboolean ret = JNI_FALSE;
+
+ if (hDevMode != NULL && hDevNames != NULL) {
+ devmode = (DEVMODE *)::GlobalLock(hDevMode);
+ devnames = (DEVNAMES *)::GlobalLock(hDevNames);
+
+ LPTSTR lpdevnames = (LPTSTR)devnames;
+ // No need to call _tcsdup as we won't unlock until we are done.
+ LPTSTR printerName = lpdevnames+devnames->wDeviceOffset;
+ LPTSTR portName = lpdevnames+devnames->wOutputOffset;
+
+ HANDLE hPrinter;
+ if (::OpenPrinter(printerName, &hPrinter, NULL) == TRUE) {
+ devmode->dmFields |= dmFields;
+ devmode->dmCopies = copies;
+ devmode->dmCollate = collate;
+ devmode->dmColor = color;
+ devmode->dmDuplex = duplex;
+ devmode->dmOrientation = orient;
+ devmode->dmPrintQuality = xres_quality;
+ devmode->dmYResolution = yres;
+ devmode->dmPaperSize = paper;
+ devmode->dmDefaultSource = bin;
+
+ rval = ::DocumentProperties((HWND)hWndParent,
+ hPrinter, printerName, devmode, devmode,
+ DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT);
+ if (rval == IDOK) {
+ UpdateJobAttributes(env, wJob, attrSet, devmode);
+ ret = JNI_TRUE;
+ }
+ VERIFY(::ClosePrinter(hPrinter));
+ }
+ ::GlobalUnlock(hDevNames);
+ ::GlobalUnlock(hDevMode);
+ }
+
+ return ret;
+
+ CATCH_BAD_ALLOC_RET(0);
+}
+
/************************************************************************
* WPageDialog native methods
*/
@@ -732,7 +882,6 @@
memset(&pd, 0, sizeof(PRINTDLG));
pd.lStructSize = sizeof(PRINTDLG);
pd.Flags = PD_RETURNDEFAULT | PD_RETURNDC;
-
if (::PrintDlg(&pd)) {
printDC = pd.hDC;
hDevMode = pd.hDevMode;
@@ -792,8 +941,19 @@
jint imgPixelWid = GetDeviceCaps(printDC, HORZRES);
jint imgPixelHgt = GetDeviceCaps(printDC, VERTRES);
+ // The DC may be obtained when we first selected the printer as a
+ // result of a call to setNativePrintService.
+ // If the Devmode was obtained later on from the DocumentProperties dialog
+ // the DC won't have been updated and its settings may be for PORTRAIT.
+ // This may happen in other cases too, but was observed for the above.
+ // To get a DC compatible with this devmode we should really call
+ // CreateDC() again to get a DC for the devmode we are using.
+ // The changes for that are a lot more risk, so to minimise that
+ // risk, assume its not LANDSCAPE unless width > height, even if the
+ // devmode says its LANDSCAPE.
// if the values were obtained from a rotated device, swap.
- if (getOrientationFromDevMode2(hDevMode) == DMORIENT_LANDSCAPE) {
+ if ((getOrientationFromDevMode2(hDevMode) == DMORIENT_LANDSCAPE) &&
+ (imgPixelWid > imgPixelHgt)) {
jint tmp;
tmp = xPixelRes;
xPixelRes = yPixelRes;
@@ -941,6 +1101,9 @@
setBooleanField(env, self, DRIVER_COLLATE_STR, JNI_FALSE);
}
+ if (dmFields & DM_COPIES) {
+ setBooleanField(env, self, DRIVER_COPIES_STR, JNI_TRUE);
+ }
}
CATCH_BAD_ALLOC;
--- a/jdk/test/ProblemList.txt Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/ProblemList.txt Sat Sep 14 20:43:34 2013 +0100
@@ -212,13 +212,6 @@
############################################################################
-# jdk_io
-
-# 7160013
-#java/io/File/MaxPathLength.java windows-all
-
-############################################################################
-
# jdk_nio
# 6963118
@@ -319,10 +312,6 @@
# 6461635
com/sun/tools/attach/BasicTests.sh generic-all
-# 7172176
-sun/tools/jconsole/ResourceCheckTest.sh generic-all
-sun/tools/jconsole/ImmutableResourceTest.sh generic-all
-
# 7132203
sun/jvmstat/monitor/MonitoredVm/CR6672135.java generic-all
--- a/jdk/test/TEST.groups Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/TEST.groups Sat Sep 14 20:43:34 2013 +0100
@@ -20,6 +20,7 @@
# questions.
#
+# java.lang package and VM runtime support
jdk_lang = \
java/lang \
-java/lang/management \
@@ -27,11 +28,67 @@
sun/invoke \
sun/misc \
sun/reflect \
+ jdk/lambda \
vm
+# All of the java.util package
jdk_util = \
+ :jdk_util_other \
+ :jdk_collections \
+ :jdk_concurrent \
+ :jdk_stream
+
+# All util components not part of some other util category
+jdk_util_other = \
java/util \
- sun/util
+ sun/util \
+ -:jdk_collections \
+ -:jdk_concurrent \
+ -:jdk_stream
+
+# java.util.concurrent (JSR-166)
+# Maintained by JSR-166 EG (Doug Lea et al)
+# Deque and PriorityQueue are also generally maintained by JSR-166
+jdk_concurrent = \
+ java/util/concurrent \
+ java/util/Deque \
+ java/util/PriorityQueue
+
+# Java Collections Framework
+jdk_collections = \
+ java/util/AbstractCollection \
+ java/util/AbstractList \
+ java/util/AbstractMap \
+ java/util/AbstractSequentialList \
+ java/util/ArrayList \
+ java/util/Arrays \
+ java/util/BitSet \
+ java/util/Collection \
+ java/util/Collections \
+ java/util/EnumMap \
+ java/util/EnumSet \
+ java/util/Comparator \
+ java/util/Iterator \
+ java/util/HashMap \
+ java/util/Hashtable \
+ java/util/IdentityHashMap \
+ java/util/List \
+ java/util/LinkedHashMap \
+ java/util/LinkedHashSet \
+ java/util/LinkedList \
+ java/util/Map \
+ java/util/NavigableMap \
+ java/util/TimSort \
+ java/util/TreeMap \
+ java/util/Vector \
+ java/util/WeakHashMap
+
+# java.util.stream (JSR-335)
+jdk_stream = \
+ java/util/Optional \
+ java/util/SummaryStatistics \
+ java/util/function \
+ java/util/stream
jdk_math = \
java/math
@@ -133,7 +190,6 @@
javax/xml \
-javax/xml/crypto \
jdk/asm \
- jdk/lambda \
com/sun/jndi \
com/sun/corba \
lib/testlibrary \
@@ -212,3 +268,341 @@
:jdk_swing \
:jdk_sound \
:jdk_imageio
+
+###############################################################################
+# Profile-based Test Group Definitions
+#
+# These groups define the tests that cover the different possible runtimes:
+# - compact1, compact2, compact3, full JRE, JDK
+#
+# In addition they support testing of the minimal VM on compact1 and compact2.
+# Essentially this defines groups based around the specified API's and VM
+# services available in the runtime.
+#
+# The groups are defined hierarchically in two forms:
+# - The need_xxx groups list all the tests that have a dependency on
+# a specific profile. This is either because it tests a feature in
+# that profile, or the test infrastructure uses a feature in that
+# profile.
+# - The primary groups are defined in terms of the other primary groups
+# combined with the needs_xxx groups (including and excluding them as
+# appropriate). For example the jre can run all tests from compact3, plus
+# those from needs_jre, but excluding those from need_jdk.
+#
+# The bottom group defines all the actual tests to be considered, simply
+# by listing the top-level test directories.
+
+# Full JDK can run all tests
+#
+jdk = \
+ :jre \
+ :needs_jdk
+
+# Tests that require a full JDK to execute. Either they test a feature
+# only in the JDK or they use tools that are only in the JDK. The latter
+# can be resolved in some cases by using tools from the compile-jdk.
+#
+needs_jdk = \
+ :jdk_jdi \
+ com/sun/tools \
+ demo \
+ sun/security/tools/jarsigner \
+ sun/rmi/rmic \
+ sun/tools \
+ sun/jvmstat \
+ tools \
+ com/sun/jmx/remote/NotificationMarshalVersions/TestSerializationMismatch.java \
+ java/io/Serializable/serialver \
+ java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java \
+ java/lang/invoke/lambda/LambdaAccessControlTest.java \
+ java/lang/System/MacEncoding/TestFileEncoding.java \
+ java/net/URLClassLoader/closetest/GetResourceAsStream.java \
+ java/util/Collections/EmptyIterator.java \
+ java/util/concurrent/locks/Lock/TimedAcquireLeak.java \
+ java/util/jar/Manifest/CreateManifest.java \
+ java/util/jar/JarInputStream/ExtraFileInMetaInf.java \
+ java/util/logging/AnonLoggerWeakRefLeak.sh \
+ java/util/logging/LoggerWeakRefLeak.sh \
+ java/util/zip/3GBZipFiles.sh \
+ jdk/lambda/FDTest.java \
+ jdk/lambda/separate/Compiler.java \
+ sun/management/jdp/JdpTest.sh \
+ sun/management/jmxremote/bootstrap/JvmstatCountersTest.java \
+ sun/management/jmxremote/bootstrap/LocalManagementTest.sh \
+ sun/misc/JarIndex/metaInfFilenames/Basic.java \
+ sun/misc/JarIndex/JarIndexMergeForClassLoaderTest.java \
+ sun/reflect/CallerSensitive/CallerSensitiveFinder.java \
+ sun/reflect/CallerSensitive/MissingCallerSensitive.java \
+ sun/security/util/Resources/NewNamesFormat.java \
+ vm/verifier/defaultMethods/DefaultMethodRegressionTestsRun.java
+
+# JRE adds further tests to compact3
+#
+jre = \
+ :compact3 \
+ :needs_jre \
+ -:needs_jdk
+
+# Tests that require the full JRE
+#
+needs_jre = \
+ :needs_charsets \
+ :jdk_desktop \
+ com/sun/corba \
+ com/sun/jndi/cosnaming \
+ sun/net/ftp \
+ sun/net/www/protocol/ftp \
+ sun/security/tools/policytool \
+ java/net/URI/URItoURLTest.java \
+ java/net/URL/URIToURLTest.java \
+ java/net/URLConnection/HandleContentTypeWithAttrs.java \
+ java/security/Security/ClassLoaderDeadlock/ClassLoaderDeadlock.sh \
+ java/security/Security/ClassLoaderDeadlock/Deadlock.sh \
+ java/util/logging/Listeners.java \
+ java/util/logging/ListenersWithSM.java \
+ java/util/ResourceBundle/Control/Bug6530694.java \
+ java/text/Bidi/BidiConformance.java \
+ java/text/Bidi/BidiEmbeddingTest.java \
+ java/text/Bidi/Bug6665028.java \
+ java/text/Bidi/Bug7042148.java \
+ java/text/Bidi/Bug7051769.java \
+ javax/crypto/Cipher/CipherStreamClose.java \
+ javax/management/monitor/AttributeArbitraryDataTypeTest.java \
+ jdk/lambda/vm/InterfaceAccessFlagsTest.java \
+ sun/misc/URLClassPath/ClassnameCharTest.java
+
+# Tests dependent on the optional charsets.jar
+# These are isolated for easy exclusions
+#
+needs_charsets = \
+ java/io/OutputStreamWriter/TestWrite.java \
+ java/nio/charset/RemovingSunIO/SunioAlias.java \
+ java/nio/charset/coders/Check.java \
+ java/nio/charset/Charset/CharsetContainmentTest.java \
+ java/nio/charset/Charset/Contains.java \
+ java/nio/charset/Charset/NIOCharsetAvailabilityTest.java \
+ java/nio/charset/Charset/RegisteredCharsets.java \
+ java/nio/charset/CharsetEncoder/Flush.java \
+ java/nio/charset/coders/CheckSJISMappingProp.sh \
+ java/nio/charset/coders/ResetISO2022JP.java \
+ java/util/Locale/InternationalBAT.java \
+ java/util/Locale/LocaleProviders.sh \
+ java/util/Calendar/CldrFormatNamesTest.java \
+ java/util/TimeZone/CLDRDisplayNamesTest.java \
+ java/util/zip/ZipCoding.java \
+ sun/nio/cs/EucJpLinux0212.java \
+ sun/nio/cs/EUCJPUnderflowDecodeTest.java \
+ sun/nio/cs/EuroConverter.java \
+ sun/nio/cs/JISAutoDetectTest.java \
+ sun/nio/cs/OLD/TestIBMDB.java \
+ sun/nio/cs/SJISCanEncode.java \
+ sun/nio/cs/Test6254467.java \
+ sun/nio/cs/TestCompoundTest.java \
+ sun/nio/cs/TestCp834_SBCS.java \
+ sun/nio/cs/TestEUC_TW.java \
+ sun/nio/cs/TestISO2022CNDecoder.java \
+ sun/nio/cs/TestISO2022JPEncoder.java \
+ sun/nio/cs/TestISO2022JPSubBytes.java \
+ sun/nio/cs/TestIllegalSJIS.java \
+ sun/nio/cs/TestJIS0208Decoder.java \
+ sun/nio/cs/TestJIS0212Decoder.java \
+ sun/nio/cs/TestMiscEUC_JP.java \
+ sun/nio/cs/TestSJIS0213_SM.java \
+ sun/nio/cs/BufferUnderflowEUCTWTest.java \
+ sun/nio/cs/CheckCaseInsensitiveEncAliases.java \
+ sun/nio/cs/CheckHistoricalNames.java \
+ sun/nio/cs/EucJpLinuxDecoderRecoveryTest.java \
+ sun/nio/cs/HWKatakanaMS932EncodeTest.java \
+ sun/nio/cs/ISCIITest.java \
+ sun/nio/cs/LatinCharReplacementTWTest.java \
+ sun/nio/cs/NIOJISAutoDetectTest.java \
+ sun/nio/cs/StreamEncoderClose.java \
+ sun/nio/cs/SurrogateGB18030Test.java \
+ sun/nio/cs/SurrogateTestEUCTW.java \
+ sun/nio/cs/SurrogateTestHKSCS.java \
+ sun/nio/cs/TestConverterDroppedCharacters.java \
+ sun/nio/cs/TestCp93xSISO.java \
+ sun/nio/cs/TestIBM1364.java \
+ sun/nio/cs/TestIBMBugs.java \
+ sun/nio/cs/TestIllegalISO2022Esc.java \
+ sun/nio/cs/TestISO2022JP.java \
+ sun/nio/cs/TestMS5022X.java \
+ sun/nio/cs/TestSJIS0213.java \
+ sun/nio/cs/TestTrailingEscapesISO2022JP.java \
+ sun/nio/cs/TestUni2HKSCS.java \
+ sun/nio/cs/ZeroedByteArrayEUCTWTest.java
+
+# Compact 3 adds further tests to compact2
+#
+compact3 = \
+ :compact2 \
+ :needs_compact3 \
+ -:needs_jre \
+ -:needs_jdk
+
+
+# Tests that require compact3 API's
+#
+needs_compact3 = \
+ :jdk_instrument \
+ :jdk_jmx \
+ :jdk_management \
+ :jdk_sctp \
+ com/sun/jndi \
+ com/sun/org/apache/xml/internal/security \
+ com/sun/security/auth \
+ com/sun/security/sasl \
+ com/sun/security/jgss \
+ com/sun/tracing \
+ java/util/prefs \
+ javax/naming \
+ javax/security \
+ javax/smartcardio \
+ javax/sql/rowset \
+ javax/xml/crypto \
+ sun/security/acl \
+ sun/security/jgss \
+ sun/security/krb5 \
+ java/lang/System/MacEncoding/TestFileEncoding.java \
+ java/nio/channels/AsynchronousSocketChannel/Leaky.java \
+ java/security/PermissionCollection/Concurrent.java \
+ java/security/Principal/Implies.java \
+ java/security/cert/GetInstance.java \
+ java/util/logging/DrainFindDeadlockTest.java \
+ java/util/logging/LoggingMXBeanTest.java \
+ sun/net/www/http/KeepAliveCache/B5045306.java \
+ sun/security/provider/PolicyFile/Alias.java \
+ sun/security/provider/PolicyFile/Comparator.java \
+ sun/security/provider/PolicyFile/SelfWildcard.java \
+ sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineDeadlock.java \
+ sun/security/util/Oid/OidFormat.java \
+ sun/security/util/Resources/Format.java \
+ sun/security/util/Resources/NewNamesFormat.java
+
+# Compact 2 adds full VM tests
+compact2 = \
+ :compact2_minimal \
+ :compact1 \
+ :needs_full_vm_compact2 \
+ -:needs_compact3 \
+ -:needs_jre \
+ -:needs_jdk
+
+# Tests that require compact2 API's and a full VM
+#
+needs_full_vm_compact2 =
+
+# Minimal VM on Compact 2 adds in some compact2 tests
+#
+compact2_minimal = \
+ :compact1_minimal \
+ :needs_compact2 \
+ -:needs_compact3 \
+ -:needs_jre \
+ -:needs_jdk
+
+# Tests that require compact2 API's
+#
+needs_compact2 = \
+ :jdk_rmi \
+ :jdk_time \
+ com/sun/org/apache \
+ com/sun/net/httpserver \
+ java/sql \
+ javax/sql \
+ javax/xml \
+ jdk/lambda \
+ sun/net/www/http \
+ sun/net/www/protocol/http \
+ java/io/BufferedReader/Lines.java \
+ java/lang/reflect/DefaultStaticTest/DefaultStaticInvokeTest.java \
+ java/lang/CharSequence/DefaultTest.java \
+ java/lang/IntegralPrimitiveToString.java \
+ java/lang/PrimitiveSumMinMaxTest.java \
+ java/lang/String/StringJoinTest.java \
+ java/lang/Thread/StopThrowable.java \
+ java/net/Authenticator/Deadlock.java \
+ java/net/CookieHandler/LocalHostCookie.java \
+ java/net/CookieHandler/CookieManagerTest.java \
+ java/net/CookieHandler/EmptyCookieHeader.java \
+ java/net/HttpCookie/IllegalCookieNameTest.java \
+ java/net/HttpURLConnection/UnmodifiableMaps.java \
+ java/net/HttpURLPermission/URLTest.java \
+ java/net/ResponseCache/Test.java \
+ java/net/URLClassLoader/ClassLoad.java \
+ java/net/URLClassLoader/closetest/CloseTest.java \
+ java/nio/Buffer/Chars.java \
+ java/nio/file/Files/StreamTest.java \
+ java/security/BasicPermission/Wildcard.java \
+ java/util/Arrays/ParallelPrefix.java \
+ java/util/Arrays/SetAllTest.java \
+ java/util/BitSet/BitSetStreamTest.java \
+ java/util/Collection/CollectionDefaults.java \
+ java/util/Collection/ListDefaults.java \
+ java/util/Collections/CheckedIdentityMap.java \
+ java/util/Collections/CheckedMapBash.java \
+ java/util/Collections/CheckedSetBash.java \
+ java/util/Collections/EmptyCollectionSerialization.java \
+ java/util/Collections/EmptyNavigableMap.java \
+ java/util/Collections/EmptyNavigableSet.java \
+ java/util/Collections/UnmodifiableMapEntrySet.java \
+ java/util/Comparator/BasicTest.java \
+ java/util/Comparator/TypeTest.java \
+ java/util/Iterator/IteratorDefaults.java \
+ java/util/Iterator/PrimitiveIteratorDefaults.java \
+ java/util/Map/BasicSerialization.java \
+ java/util/Map/Defaults.java \
+ java/util/Map/EntryComparators.java \
+ java/util/Optional/Basic.java \
+ java/util/Optional/BasicDouble.java \
+ java/util/Optional/BasicInt.java \
+ java/util/Optional/BasicLong.java \
+ java/util/Random/RandomStreamTest.java \
+ java/util/ResourceBundle/Bug6359330.java \
+ java/util/Spliterator/SpliteratorCharacteristics.java \
+ java/util/Spliterator/SpliteratorCollisions.java \
+ java/util/Spliterator/SpliteratorLateBindingFailFastTest.java \
+ java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java \
+ java/util/StringJoiner/MergeTest.java \
+ java/util/StringJoiner/StringJoinerTest.java \
+ java/util/concurrent/atomic/AtomicReferenceTest.java \
+ java/util/function/BinaryOperator/BasicTest.java \
+ java/util/logging/LoggerSupplierAPIsTest.java \
+ java/util/zip/ZipFile/StreamZipEntriesTest.java \
+ java/util/zip/ZipFile/DeleteTempJar.java \
+ javax/crypto/Cipher/CipherStreamClose.java \
+ sun/misc/URLClassPath/ClassnameCharTest.java \
+ sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/HttpsCreateSockTest.java \
+ sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/HttpsSocketFacTest.java
+
+# Compact 1 adds full VM tests
+#
+compact1 = \
+ :compact1_minimal \
+ :needs_full_vm_compact1 \
+ -:needs_compact2 \
+ -:needs_full_vm_compact2 \
+ -:needs_compact3 \
+ -:needs_jre \
+ -:needs_jdk
+
+# Tests that require compact1 API's and a full VM
+#
+needs_full_vm_compact1 =
+
+# All tests that run on the most minimal configuration: Minimal VM on Compact 1
+compact1_minimal = \
+ com \
+ java \
+ javax \
+ jdk \
+ lib \
+ sample \
+ sun \
+ vm \
+ -:needs_full_vm_compact1 \
+ -:needs_full_vm_compact2 \
+ -:needs_compact2 \
+ -:needs_compact3 \
+ -:needs_jre \
+ -:needs_jdk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/corba/transport/KeepAliveSockets.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8017195
+ * @summary Introduce option to setKeepAlive parameter on CORBA sockets
+ *
+ * @run main/othervm KeepAliveSockets
+ * @run main/othervm -Dcom.sun.CORBA.transport.enableTcpKeepAlive KeepAliveSockets
+ * @run main/othervm -Dcom.sun.CORBA.transport.enableTcpKeepAlive=true KeepAliveSockets
+ * @run main/othervm -Dcom.sun.CORBA.transport.enableTcpKeepAlive=false KeepAliveSockets
+ */
+
+import java.lang.*;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.nio.channels.ServerSocketChannel;
+import java.util.*;
+import com.sun.corba.se.impl.orb.*;
+
+import com.sun.corba.se.impl.transport.*;
+
+public class KeepAliveSockets {
+
+ public static void main(String[] args) throws Exception {
+
+ boolean keepAlive = false;
+ String prop = System.getProperty("com.sun.CORBA.transport.enableTcpKeepAlive");
+ if (prop != null)
+ keepAlive = !"false".equalsIgnoreCase(prop);
+
+ DefaultSocketFactoryImpl sfImpl = new DefaultSocketFactoryImpl();
+ ORBImpl orb = new ORBImpl();
+ orb.set_parameters(null);
+ sfImpl.setORB(orb);
+
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ ssc.socket().bind(new InetSocketAddress(0));
+
+ InetSocketAddress isa = new InetSocketAddress("localhost", ssc.socket().getLocalPort());
+ Socket s = sfImpl.createSocket("ignore", isa);
+ System.out.println("Received factory socket" + s);
+ if (keepAlive != s.getKeepAlive())
+ throw new RuntimeException("KeepAlive value not honoured in CORBA socket");
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/security/Permissions.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+/* @test
+ * @bug 8008981
+ * @summary Test that selected Toolkit and Window methods/constructors do
+ * the appropriate permission check
+ * @run main/othervm Permissions
+ */
+
+import java.awt.AWTPermission;
+import java.awt.Frame;
+import java.awt.GraphicsConfiguration;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.util.ArrayList;
+import java.util.List;
+import java.security.Permission;
+
+public class Permissions {
+
+ static class MySecurityManager extends SecurityManager {
+ private List<Permission> permissionsChecked = new ArrayList<>();
+
+ static MySecurityManager install() {
+ MySecurityManager sm = new MySecurityManager();
+ System.setSecurityManager(sm);
+ return sm;
+ }
+
+ @Override
+ public void checkPermission(Permission perm) {
+ permissionsChecked.add(perm);
+ }
+
+ void prepare(String msg) {
+ System.out.println(msg);
+ permissionsChecked.clear();
+ }
+
+ /**
+ * Checks the security manager's checkPermission method was invoked
+ * to check the given permission and target name.
+ */
+ void assertChecked(Class<? extends Permission> type, String name) {
+ for (Permission perm: permissionsChecked) {
+ if (type.isInstance(perm) && perm.getName().equals(name))
+ return;
+ }
+ throw new RuntimeException(type.getName() + "(\"" + name + "\") not checked");
+ }
+ }
+
+ public static void main(String[] args) {
+ MySecurityManager sm = MySecurityManager.install();
+
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+
+ sm.prepare("Toolkit.getSystemClipboard()");
+ toolkit.getSystemClipboard();
+ sm.assertChecked(AWTPermission.class, "accessClipboard");
+
+ sm.prepare("Toolkit.getSystemEventQueue()");
+ toolkit.getSystemEventQueue();
+ sm.assertChecked(AWTPermission.class, "accessEventQueue");
+
+ sm.prepare("Toolkit.getSystemSelection()");
+ toolkit.getSystemSelection();
+ //sm.assertChecked(AWTPermission.class, "accessClipboard");
+
+ sm.prepare("Window(Frame)");
+ new Window((Frame)null);
+ sm.assertChecked(AWTPermission.class, "showWindowWithoutWarningBanner");
+
+ sm.prepare("Window(Window)");
+ new Window((Window)null);
+ sm.assertChecked(AWTPermission.class, "showWindowWithoutWarningBanner");
+
+ sm.prepare("Window(Window,GraphicsConfiguration)");
+ new Window((Window)null, (GraphicsConfiguration)null);
+ sm.assertChecked(AWTPermission.class, "showWindowWithoutWarningBanner");
+ }
+}
--- a/jdk/test/java/io/File/MaxPathLength.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/io/File/MaxPathLength.java Sat Sep 14 20:43:34 2013 +0100
@@ -22,7 +22,7 @@
*/
/* @test
- @bug 4759207 4403166 4165006 4403166 6182812 6274272
+ @bug 4759207 4403166 4165006 4403166 6182812 6274272 7160013
@summary Test to see if win32 path length can be greater than 260
*/
@@ -37,6 +37,10 @@
"areallylongfilenamethatsforsur";
private static boolean isWindows = false;
+ private final static int MAX_LENGTH = 256;
+
+ private static int counter = 0;
+
public static void main(String[] args) throws Exception {
String osName = System.getProperty("os.name");
if (osName.startsWith("Windows")) {
@@ -45,33 +49,39 @@
for (int i = 4; i < 7; i++) {
String name = fileName;
- while (name.length() < 256) {
+ while (name.length() < MAX_LENGTH) {
testLongPath (i, name, false);
testLongPath (i, name, true);
- name += "A";
+ name = getNextName(name);
}
}
// test long paths on windows
+ // And these long pathes cannot be handled on Solaris and Mac platforms
if (isWindows) {
String name = fileName;
- while (name.length() < 256) {
+ while (name.length() < MAX_LENGTH) {
testLongPath (20, name, false);
testLongPath (20, name, true);
- name += "A";
+ name = getNextName(name);
}
}
}
+ private static String getNextName(String fName) {
+ return (fName.length() < MAX_LENGTH/2) ? fName + fName
+ : fName + "A";
+ }
+
static void testLongPath(int max, String fn,
boolean tryAbsolute) throws Exception {
String[] created = new String[max];
String pathString = ".";
for (int i = 0; i < max -1; i++) {
- pathString = pathString + pathComponent;
+ pathString = pathString + pathComponent + (counter++);
created[max - 1 -i] = pathString;
+ }
- }
File dirFile = new File(pathString);
File f = new File(pathString + sep + fn);
@@ -88,9 +98,10 @@
System.err.println("Warning: Test directory structure exists already!");
return;
}
- Files.createDirectories(dirFile.toPath());
try {
+ Files.createDirectories(dirFile.toPath());
+
if (tryAbsolute)
dirFile = new File(dirFile.getCanonicalPath());
if (!dirFile.isDirectory())
@@ -99,6 +110,7 @@
if (!f.createNewFile()) {
throw new RuntimeException ("File.createNewFile() failed");
}
+
if (!f.exists())
throw new RuntimeException ("File.exists() failed");
if (!f.isFile())
@@ -107,11 +119,14 @@
throw new RuntimeException ("File.canRead() failed");
if (!f.canWrite())
throw new RuntimeException ("File.canWrite() failed");
+
if (!f.delete())
throw new RuntimeException ("File.delete() failed");
+
FileOutputStream fos = new FileOutputStream(f);
fos.write(1);
fos.close();
+
if (f.length() != 1)
throw new RuntimeException ("File.length() failed");
long time = System.currentTimeMillis();
@@ -148,30 +163,26 @@
throw new RuntimeException ("File.renameTo() failed for lenth="
+ abPath.length());
}
- return;
+ } else {
+ if (!nf.canRead())
+ throw new RuntimeException ("Renamed file is not readable");
+ if (!nf.canWrite())
+ throw new RuntimeException ("Renamed file is not writable");
+ if (nf.length() != 1)
+ throw new RuntimeException ("Renamed file's size is not correct");
+ if (!nf.renameTo(f)) {
+ created[0] = nf.getPath();
+ }
+ /* add a script to test these two if we got a regression later
+ if (!f.setReadOnly())
+ throw new RuntimeException ("File.setReadOnly() failed");
+ f.deleteOnExit();
+ */
}
- if (!nf.canRead())
- throw new RuntimeException ("Renamed file is not readable");
- if (!nf.canWrite())
- throw new RuntimeException ("Renamed file is not writable");
- if (nf.length() != 1)
- throw new RuntimeException ("Renamed file's size is not correct");
- nf.renameTo(f);
- /* add a script to test these two if we got a regression later
- if (!f.setReadOnly())
- throw new RuntimeException ("File.setReadOnly() failed");
- f.deleteOnExit();
- */
} finally {
// Clean up
for (int i = 0; i < max; i++) {
- pathString = created[i];
- // Only works with completex canonical paths
- File df = new File(pathString);
- pathString = df.getCanonicalPath();
- df = new File(pathString);
- if (!df.delete())
- System.out.printf("Delete failed->%s\n", pathString);
+ Files.deleteIfExists((new File(created[i])).toPath());
}
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Class/ArrayMethods.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+/* @test
+ * @bug 4987375
+ * @summary make sure clone() isn't reflected and that Cloneable and
+ * Serializable are found
+ */
+
+import java.lang.reflect.*;
+import java.util.Arrays;
+
+public class ArrayMethods {
+ public int failed = 0;
+
+ public static void main(String[] args) throws Exception {
+ ArrayMethods m = new ArrayMethods();
+
+ m.testGetMethod();
+ m.testGetMethods();
+ m.testGetDeclaredMethod();
+ m.testGetDeclaredMethods();
+ m.testGetInterfaces();
+
+ if (m.failed != 0)
+ throw new RuntimeException("Test failed, check log for details");
+ }
+
+ public void testGetMethod() {
+ try {
+ Method m = new String[0].getClass().getMethod("clone", (Class<?>[])null);
+
+ failed++;
+ System.out.println("getMethod(\"clone\", null) Should not find clone()");
+ } catch (NoSuchMethodException e) {
+ ; //all good
+ }
+ }
+
+ public void testGetMethods() {
+ Method[] m = new Integer[0][0][0].getClass().getMethods();
+ for (Method mm : m)
+ if(mm.getName().contentEquals("clone")) {
+ failed++;
+ System.out.println("getMethods() Should not find clone()");
+ }
+ }
+
+ public void testGetDeclaredMethod() {
+ try {
+ Method m = new Object[0][0].getClass().getDeclaredMethod("clone", (Class<?>[])null);
+
+ failed++;
+ System.out.println("getDeclaredMethod(\"clone\", null) Should not find clone()");
+
+ } catch (NoSuchMethodException e) {
+ ; //all good
+ }
+ }
+
+ public void testGetDeclaredMethods() {
+ Method[] m = new Throwable[0][0][0][0].getClass().getDeclaredMethods();
+ if (m.length != 0) {
+ failed++;
+ System.out.println("getDeclaredMethods().length should be 0");
+ }
+ }
+
+ public void testGetInterfaces() {
+ Class<?>[] is = new Integer[0].getClass().getInterfaces();
+ boolean thisFailed = false;
+
+ if (is.length != 2)
+ thisFailed = true;
+
+ if (!is[0].getCanonicalName().equals("java.lang.Cloneable"))
+ thisFailed = true;
+
+ if (!is[1].getCanonicalName().equals("java.io.Serializable"))
+ thisFailed = true;
+
+ if (thisFailed) {
+ failed++;
+ System.out.println(Arrays.asList(is));
+ System.out.println("Should contain exactly Cloneable, Serializable in that order.");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Class/getField/ArrayLength.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 5047859
+ * @summary verify that for an array type class instance, getField("length")
+ * throws an exception, and getFields() does not contain a Field for
+ * 'length'
+ */
+
+import java.lang.reflect.Field;
+
+public class ArrayLength {
+ public static void main(String [] args) {
+ int failed = 0;
+
+ try {
+ new String[0].getClass().getField("length");
+ failed++;
+ System.out.println("getField(\"length\") should throw NoSuchFieldException");
+ } catch (NoSuchFieldException e) {
+ }
+ try {
+ new String[0].getClass().getDeclaredField("length");
+ failed++;
+ System.out.println("getDeclaredField(\"length\") should throw NoSuchFieldException");
+ } catch (NoSuchFieldException e) {
+ }
+
+ if (new String[0].getClass().getFields().length != 0) {
+ failed++;
+ System.out.println("getFields() for an array type should return a zero length array");
+ }
+
+ if (new String[0].getClass().getDeclaredFields().length != 0) {
+ failed++;
+ System.out.println("getDeclaredFields() for an array type should return a zero length array");
+ }
+
+ if (failed != 0)
+ throw new RuntimeException("Test failed see log for details");
+ }
+}
--- a/jdk/test/java/lang/Math/RoundTests.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/lang/Math/RoundTests.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6430675
+ * @bug 6430675 8010430
* @summary Check for correct implementation of {Math, StrictMath}.round
*/
public class RoundTests {
@@ -32,6 +32,8 @@
failures += testNearFloatHalfCases();
failures += testNearDoubleHalfCases();
+ failures += testUnityULPCases();
+ failures += testSpecialCases();
if (failures > 0) {
System.err.println("Testing {Math, StrictMath}.round incurred "
@@ -95,4 +97,69 @@
return failures;
}
+
+ private static int testUnityULPCases() {
+ int failures = 0;
+ for (float sign : new float[]{-1, 1}) {
+ for (float v1 : new float[]{1 << 23, 1 << 24}) {
+ for (int k = -5; k <= 5; k++) {
+ float value = (v1 + k) * sign;
+ float actual = Math.round(value);
+ failures += Tests.test("Math.round", value, actual, value);
+ }
+ }
+ }
+
+ if (failures != 0) {
+ System.out.println();
+ }
+
+ for (double sign : new double[]{-1, 1}) {
+ for (double v1 : new double[]{1L << 52, 1L << 53}) {
+ for (int k = -5; k <= 5; k++) {
+ double value = (v1 + k) * sign;
+ double actual = Math.round(value);
+ failures += Tests.test("Math.round", value, actual, value);
+ }
+ }
+ }
+
+ return failures;
+ }
+
+ private static int testSpecialCases() {
+ int failures = 0;
+
+ failures += Tests.test("Math.round", Float.NaN, Math.round(Float.NaN), 0.0F);
+ failures += Tests.test("Math.round", Float.POSITIVE_INFINITY,
+ Math.round(Float.POSITIVE_INFINITY), Integer.MAX_VALUE);
+ failures += Tests.test("Math.round", Float.NEGATIVE_INFINITY,
+ Math.round(Float.NEGATIVE_INFINITY), Integer.MIN_VALUE);
+ failures += Tests.test("Math.round", -(float)Integer.MIN_VALUE,
+ Math.round(-(float)Integer.MIN_VALUE), Integer.MAX_VALUE);
+ failures += Tests.test("Math.round", (float) Integer.MIN_VALUE,
+ Math.round((float) Integer.MIN_VALUE), Integer.MIN_VALUE);
+ failures += Tests.test("Math.round", 0F, Math.round(0F), 0.0F);
+ failures += Tests.test("Math.round", Float.MIN_VALUE,
+ Math.round(Float.MIN_VALUE), 0.0F);
+ failures += Tests.test("Math.round", -Float.MIN_VALUE,
+ Math.round(-Float.MIN_VALUE), 0.0F);
+
+ failures += Tests.test("Math.round", Double.NaN, Math.round(Double.NaN), 0.0);
+ failures += Tests.test("Math.round", Double.POSITIVE_INFINITY,
+ Math.round(Double.POSITIVE_INFINITY), Long.MAX_VALUE);
+ failures += Tests.test("Math.round", Double.NEGATIVE_INFINITY,
+ Math.round(Double.NEGATIVE_INFINITY), Long.MIN_VALUE);
+ failures += Tests.test("Math.round", -(double)Long.MIN_VALUE,
+ Math.round(-(double)Long.MIN_VALUE), Long.MAX_VALUE);
+ failures += Tests.test("Math.round", (double) Long.MIN_VALUE,
+ Math.round((double) Long.MIN_VALUE), Long.MIN_VALUE);
+ failures += Tests.test("Math.round", 0, Math.round(0), 0.0);
+ failures += Tests.test("Math.round", Double.MIN_VALUE,
+ Math.round(Double.MIN_VALUE), 0.0);
+ failures += Tests.test("Math.round", -Double.MIN_VALUE,
+ Math.round(-Double.MIN_VALUE), 0.0);
+
+ return failures;
+ }
}
--- a/jdk/test/java/lang/invoke/7087570/Test7087570.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/lang/invoke/7087570/Test7087570.java Sat Sep 14 20:43:34 2013 +0100
@@ -35,20 +35,9 @@
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
+import static java.lang.invoke.MethodHandleInfo.*;
public class Test7087570 {
- // XXX may remove the following constant declarations when MethodHandleInfo is made public
- private static final int
- REF_getField = 1,
- REF_getStatic = 2,
- REF_putField = 3,
- REF_putStatic = 4,
- REF_invokeVirtual = 5,
- REF_invokeStatic = 6,
- REF_invokeSpecial = 7,
- REF_newInvokeSpecial = 8,
- REF_invokeInterface = 9,
- REF_LIMIT = 10;
private static final TestMethodData[] TESTS = new TestMethodData[] {
// field accessors
@@ -87,17 +76,17 @@
}
private static void doTest(MethodHandle mh, TestMethodData testMethod) {
- Object mhi = newMethodHandleInfo(mh);
+ MethodHandleInfo mhi = LOOKUP.revealDirect(mh);
System.out.printf("%s.%s: %s, nominal refKind: %s, actual refKind: %s\n",
testMethod.clazz.getName(), testMethod.name, testMethod.methodType,
- REF_KIND_NAMES[testMethod.referenceKind],
- REF_KIND_NAMES[getReferenceKind(mhi)]);
- assertEquals(testMethod.name, getName(mhi));
- assertEquals(testMethod.methodType, getMethodType(mhi));
- assertEquals(testMethod.declaringClass, getDeclaringClass(mhi));
+ referenceKindToString(testMethod.referenceKind),
+ referenceKindToString(mhi.getReferenceKind()));
+ assertEquals(testMethod.name, mhi.getName());
+ assertEquals(testMethod.methodType, mhi.getMethodType());
+ assertEquals(testMethod.declaringClass, mhi.getDeclaringClass());
assertEquals(testMethod.referenceKind == REF_invokeSpecial, isInvokeSpecial(mh));
- assertRefKindEquals(testMethod.referenceKind, getReferenceKind(mhi));
+ assertRefKindEquals(testMethod.referenceKind, mhi.getReferenceKind());
}
private static void testWithLookup() throws Throwable {
@@ -122,50 +111,8 @@
return methodType(void.class, clazz);
}
- private static final String[] REF_KIND_NAMES = {
- "MH::invokeBasic",
- "REF_getField", "REF_getStatic", "REF_putField", "REF_putStatic",
- "REF_invokeVirtual", "REF_invokeStatic", "REF_invokeSpecial",
- "REF_newInvokeSpecial", "REF_invokeInterface"
- };
-
private static final Lookup LOOKUP = lookup();
- // XXX may remove the following reflective logic when MethodHandleInfo is made public
- private static final MethodHandle MH_IS_INVOKESPECIAL;
- private static final MethodHandle MHI_CONSTRUCTOR;
- private static final MethodHandle MHI_GET_NAME;
- private static final MethodHandle MHI_GET_METHOD_TYPE;
- private static final MethodHandle MHI_GET_DECLARING_CLASS;
- private static final MethodHandle MHI_GET_REFERENCE_KIND;
-
- static {
- try {
- // This is white box testing. Use reflection to grab private implementation bits.
- String magicName = "IMPL_LOOKUP";
- Field magicLookup = MethodHandles.Lookup.class.getDeclaredField(magicName);
- // This unit test will fail if a security manager is installed.
- magicLookup.setAccessible(true);
- // Forbidden fruit...
- Lookup directInvokeLookup = (Lookup) magicLookup.get(null);
- Class<?> mhiClass = Class.forName("java.lang.invoke.MethodHandleInfo", false, MethodHandle.class.getClassLoader());
- MH_IS_INVOKESPECIAL = directInvokeLookup
- .findVirtual(MethodHandle.class, "isInvokeSpecial", methodType(boolean.class));
- MHI_CONSTRUCTOR = directInvokeLookup
- .findConstructor(mhiClass, methodType(void.class, MethodHandle.class));
- MHI_GET_NAME = directInvokeLookup
- .findVirtual(mhiClass, "getName", methodType(String.class));
- MHI_GET_METHOD_TYPE = directInvokeLookup
- .findVirtual(mhiClass, "getMethodType", methodType(MethodType.class));
- MHI_GET_DECLARING_CLASS = directInvokeLookup
- .findVirtual(mhiClass, "getDeclaringClass", methodType(Class.class));
- MHI_GET_REFERENCE_KIND = directInvokeLookup
- .findVirtual(mhiClass, "getReferenceKind", methodType(int.class));
- } catch (ReflectiveOperationException ex) {
- throw new Error(ex);
- }
- }
-
private static class TestMethodData {
final Class<?> clazz;
final String name;
@@ -208,7 +155,9 @@
return LOOKUP.findStatic(testMethod.clazz, testMethod.name, testMethod.methodType);
case REF_invokeSpecial:
Class<?> thisClass = LOOKUP.lookupClass();
- return LOOKUP.findSpecial(testMethod.clazz, testMethod.name, testMethod.methodType, thisClass);
+ MethodHandle smh = LOOKUP.findSpecial(testMethod.clazz, testMethod.name, testMethod.methodType, thisClass);
+ noteInvokeSpecial(smh);
+ return smh;
case REF_newInvokeSpecial:
return LOOKUP.findConstructor(testMethod.clazz, testMethod.methodType);
default:
@@ -238,7 +187,9 @@
case REF_invokeSpecial: {
Method m = testMethod.clazz.getDeclaredMethod(testMethod.name, testMethod.methodType.parameterArray());
Class<?> thisClass = LOOKUP.lookupClass();
- return LOOKUP.unreflectSpecial(m, thisClass);
+ MethodHandle smh = LOOKUP.unreflectSpecial(m, thisClass);
+ noteInvokeSpecial(smh);
+ return smh;
}
case REF_newInvokeSpecial: {
Constructor c = testMethod.clazz.getDeclaredConstructor(testMethod.methodType.parameterArray());
@@ -249,59 +200,20 @@
}
}
- private static Object newMethodHandleInfo(MethodHandle mh) {
- try {
- return MHI_CONSTRUCTOR.invoke(mh);
- } catch (Throwable ex) {
- throw new Error(ex);
- }
- }
-
- private static boolean isInvokeSpecial(MethodHandle mh) {
- try {
- return (boolean) MH_IS_INVOKESPECIAL.invokeExact(mh);
- } catch (Throwable ex) {
- throw new Error(ex);
- }
- }
-
- private static String getName(Object mhi) {
- try {
- return (String) MHI_GET_NAME.invoke(mhi);
- } catch (Throwable ex) {
- throw new Error(ex);
- }
+ private static List<MethodHandle> specialMethodHandles = new ArrayList<>();
+ private static void noteInvokeSpecial(MethodHandle mh) {
+ specialMethodHandles.add(mh);
+ assert(isInvokeSpecial(mh));
}
-
- private static MethodType getMethodType(Object mhi) {
- try {
- return (MethodType) MHI_GET_METHOD_TYPE.invoke(mhi);
- } catch (Throwable ex) {
- throw new Error(ex);
- }
- }
-
- private static Class<?> getDeclaringClass(Object mhi) {
- try {
- return (Class<?>) MHI_GET_DECLARING_CLASS.invoke(mhi);
- } catch (Throwable ex) {
- throw new Error(ex);
- }
- }
-
- private static int getReferenceKind(Object mhi) {
- try {
- return (int) MHI_GET_REFERENCE_KIND.invoke(mhi);
- } catch (Throwable ex) {
- throw new Error(ex);
- }
+ private static boolean isInvokeSpecial(MethodHandle mh) {
+ return specialMethodHandles.contains(mh);
}
private static void assertRefKindEquals(int expect, int observed) {
if (expect == observed) return;
- String msg = "expected " + REF_KIND_NAMES[(int) expect] +
- " but observed " + REF_KIND_NAMES[(int) observed];
+ String msg = "expected " + referenceKindToString(expect) +
+ " but observed " + referenceKindToString(observed);
System.out.println("FAILED: " + msg);
throw new AssertionError(msg);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/RevealDirectTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,753 @@
+/*
+ * 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. 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
+ * @summary verify Lookup.revealDirect on a variety of input handles
+ * @compile -XDignore.symbol.file RevealDirectTest.java
+ * @run junit/othervm -ea -esa test.java.lang.invoke.RevealDirectTest
+ *
+ * @test
+ * @summary verify Lookup.revealDirect on a variety of input handles, with security manager
+ * @run main/othervm/policy=jtreg.security.policy/secure=java.lang.SecurityManager -ea -esa test.java.lang.invoke.RevealDirectTest
+ */
+
+/* To run manually:
+ * $ $JAVA8X_HOME/bin/javac -cp $JUNIT4_JAR -d ../../../.. -XDignore.symbol.file RevealDirectTest.java
+ * $ $JAVA8X_HOME/bin/java -cp $JUNIT4_JAR:../../../.. -ea -esa org.junit.runner.JUnitCore test.java.lang.invoke.RevealDirectTest
+ * $ $JAVA8X_HOME/bin/java -cp $JUNIT4_JAR:../../../.. -ea -esa -Djava.security.manager test.java.lang.invoke.RevealDirectTest
+ */
+
+package test.java.lang.invoke;
+
+import java.lang.reflect.*;
+import java.lang.invoke.*;
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+import static java.lang.invoke.MethodHandleInfo.*;
+import java.util.*;
+import static org.junit.Assert.*;
+import org.junit.*;
+
+public class RevealDirectTest {
+ public static void main(String... av) throws Throwable {
+ // Run the @Test methods explicitly, in case we don't want to use the JUnitCore driver.
+ // This appears to be necessary when running with a security manager.
+ Throwable fail = null;
+ for (Method test : RevealDirectTest.class.getDeclaredMethods()) {
+ if (!test.isAnnotationPresent(Test.class)) continue;
+ try {
+ test.invoke(new RevealDirectTest());
+ } catch (Throwable ex) {
+ if (ex instanceof InvocationTargetException)
+ ex = ex.getCause();
+ if (fail == null) fail = ex;
+ System.out.println("Testcase: "+test.getName()
+ +"("+test.getDeclaringClass().getName()
+ +"):\tCaused an ERROR");
+ System.out.println(ex);
+ ex.printStackTrace(System.out);
+ }
+ }
+ if (fail != null) throw fail;
+ }
+
+ public interface SimpleSuperInterface {
+ public abstract int getInt();
+ public static void printAll(String... args) {
+ System.out.println(Arrays.toString(args));
+ }
+ public int NICE_CONSTANT = 42;
+ }
+ public interface SimpleInterface extends SimpleSuperInterface {
+ default float getFloat() { return getInt(); }
+ public static void printAll(String[] args) {
+ System.out.println(Arrays.toString(args));
+ }
+ }
+ public static class Simple implements SimpleInterface, Cloneable {
+ public int intField;
+ public final int finalField;
+ private static String stringField;
+ public int getInt() { return NICE_CONSTANT; }
+ private static Number getNum() { return 804; }
+ public Simple clone() {
+ try {
+ return (Simple) super.clone();
+ } catch (CloneNotSupportedException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ Simple() { finalField = -NICE_CONSTANT; }
+ private static Lookup localLookup() { return lookup(); }
+ private static List<Member> members() { return getMembers(lookup().lookupClass()); };
+ }
+
+ static boolean VERBOSE = false;
+
+ @Test public void testSimple() throws Throwable {
+ if (VERBOSE) System.out.println("@Test testSimple");
+ testOnMembers("testSimple", Simple.members(), Simple.localLookup());
+ }
+ @Test public void testPublicLookup() throws Throwable {
+ if (VERBOSE) System.out.println("@Test testPublicLookup");
+ List<Member> mems = publicOnly(Simple.members());
+ Lookup pubLookup = publicLookup(), privLookup = Simple.localLookup();
+ testOnMembers("testPublicLookup/1", mems, pubLookup);
+ // reveal using publicLookup:
+ testOnMembers("testPublicLookup/2", mems, privLookup, pubLookup);
+ // lookup using publicLookup, but reveal using private:
+ testOnMembers("testPublicLookup/3", mems, pubLookup, privLookup);
+ }
+ @Test public void testPublicLookupNegative() throws Throwable {
+ if (VERBOSE) System.out.println("@Test testPublicLookupNegative");
+ List<Member> mems = nonPublicOnly(Simple.members());
+ Lookup pubLookup = publicLookup(), privLookup = Simple.localLookup();
+ testOnMembersNoLookup("testPublicLookupNegative/1", mems, pubLookup);
+ testOnMembersNoReveal("testPublicLookupNegative/2", mems, privLookup, pubLookup);
+ testOnMembersNoReflect("testPublicLookupNegative/3", mems, privLookup, pubLookup);
+ }
+ @Test public void testJavaLangClass() throws Throwable {
+ if (VERBOSE) System.out.println("@Test testJavaLangClass");
+ List<Member> mems = callerSensitive(false, publicOnly(getMembers(Class.class)));
+ mems = limit(20, mems);
+ testOnMembers("testJavaLangClass", mems, Simple.localLookup());
+ }
+ @Test public void testCallerSensitive() throws Throwable {
+ if (VERBOSE) System.out.println("@Test testCallerSensitive");
+ List<Member> mems = union(getMembers(MethodHandles.class, "lookup"),
+ getMembers(Method.class, "invoke"),
+ getMembers(Field.class, "get", "set", "getLong"),
+ getMembers(Class.class));
+ mems = callerSensitive(true, publicOnly(mems));
+ mems = limit(10, mems);
+ testOnMembers("testCallerSensitive", mems, Simple.localLookup());
+ }
+ @Test public void testCallerSensitiveNegative() throws Throwable {
+ if (VERBOSE) System.out.println("@Test testCallerSensitiveNegative");
+ List<Member> mems = union(getMembers(MethodHandles.class, "lookup"),
+ getMembers(Class.class, "forName"),
+ getMembers(Method.class, "invoke"));
+ mems = callerSensitive(true, publicOnly(mems));
+ // CS methods cannot be looked up with publicLookup
+ testOnMembersNoLookup("testCallerSensitiveNegative", mems, publicLookup());
+ }
+ @Test public void testMethodHandleNatives() throws Throwable {
+ if (VERBOSE) System.out.println("@Test testMethodHandleNatives");
+ List<Member> mems = getMembers(MethodHandle.class, "invoke", "invokeExact");
+ testOnMembers("testMethodHandleNatives", mems, Simple.localLookup());
+ }
+ @Test public void testMethodHandleInvokes() throws Throwable {
+ if (VERBOSE) System.out.println("@Test testMethodHandleInvokes");
+ List<MethodType> types = new ArrayList<>();
+ Class<?>[] someParamTypes = { void.class, int.class, Object.class, Object[].class };
+ for (Class<?> rt : someParamTypes) {
+ for (Class<?> p0 : someParamTypes) {
+ if (p0 == void.class) { types.add(methodType(rt)); continue; }
+ for (Class<?> p1 : someParamTypes) {
+ if (p1 == void.class) { types.add(methodType(rt, p0)); continue; }
+ for (Class<?> p2 : someParamTypes) {
+ if (p2 == void.class) { types.add(methodType(rt, p0, p1)); continue; }
+ types.add(methodType(rt, p0, p1, p2));
+ }
+ }
+ }
+ }
+ List<Member> mems = union(getPolyMembers(MethodHandle.class, "invoke", types),
+ getPolyMembers(MethodHandle.class, "invokeExact", types));
+ testOnMembers("testMethodHandleInvokes/1", mems, Simple.localLookup());
+ testOnMembers("testMethodHandleInvokes/2", mems, publicLookup());
+ }
+
+ static List<Member> getPolyMembers(Class<?> cls, String name, List<MethodType> types) {
+ assert(cls == MethodHandle.class);
+ ArrayList<Member> mems = new ArrayList<>();
+ for (MethodType type : types) {
+ mems.add(new SignaturePolymorphicMethod(name, type));
+ }
+ return mems;
+ }
+ static List<Member> getMembers(Class<?> cls) {
+ return getMembers(cls, (String[]) null);
+ }
+ static List<Member> getMembers(Class<?> cls, String... onlyNames) {
+ List<String> names = (onlyNames == null || onlyNames.length == 0 ? null : Arrays.asList(onlyNames));
+ ArrayList<Member> res = new ArrayList<>();
+ for (Class<?> sup : getSupers(cls)) {
+ res.addAll(getDeclaredMembers(sup, "getDeclaredFields"));
+ res.addAll(getDeclaredMembers(sup, "getDeclaredMethods"));
+ res.addAll(getDeclaredMembers(sup, "getDeclaredConstructors"));
+ }
+ res = new ArrayList<>(new LinkedHashSet<>(res));
+ for (int i = 0; i < res.size(); i++) {
+ Member mem = res.get(i);
+ if (!canBeReached(mem, cls) ||
+ res.indexOf(mem) != i ||
+ mem.isSynthetic() ||
+ (names != null && !names.contains(mem.getName()))
+ ) {
+ res.remove(i--);
+ }
+ }
+ return res;
+ }
+ static List<Class<?>> getSupers(Class<?> cls) {
+ ArrayList<Class<?>> res = new ArrayList<>();
+ ArrayList<Class<?>> intfs = new ArrayList<>();
+ for (Class<?> sup = cls; sup != null; sup = sup.getSuperclass()) {
+ res.add(sup);
+ for (Class<?> intf : cls.getInterfaces()) {
+ if (!intfs.contains(intf))
+ intfs.add(intf);
+ }
+ }
+ for (int i = 0; i < intfs.size(); i++) {
+ for (Class<?> intf : intfs.get(i).getInterfaces()) {
+ if (!intfs.contains(intf))
+ intfs.add(intf);
+ }
+ }
+ res.addAll(intfs);
+ //System.out.println("getSupers => "+res);
+ return res;
+ }
+ static boolean hasSM() {
+ return (System.getSecurityManager() != null);
+ }
+ static List<Member> getDeclaredMembers(Class<?> cls, String accessor) {
+ Member[] mems = {};
+ Method getter = getMethod(Class.class, accessor);
+ if (hasSM()) {
+ try {
+ mems = (Member[]) invokeMethod(getter, cls);
+ } catch (SecurityException ex) {
+ //if (VERBOSE) ex.printStackTrace();
+ accessor = accessor.replace("Declared", "");
+ getter = getMethod(Class.class, accessor);
+ if (VERBOSE) System.out.println("replaced accessor: "+getter);
+ }
+ }
+ if (mems.length == 0) {
+ try {
+ mems = (Member[]) invokeMethod(getter, cls);
+ } catch (SecurityException ex) {
+ ex.printStackTrace();
+ }
+ }
+ if (VERBOSE) System.out.println(accessor+" "+cls.getName()+" => "+mems.length+" members");
+ return Arrays.asList(mems);
+ }
+ static Method getMethod(Class<?> cls, String name) {
+ try {
+ return cls.getMethod(name);
+ } catch (ReflectiveOperationException ex) {
+ throw new AssertionError(ex);
+ }
+ }
+ static Object invokeMethod(Method m, Object recv, Object... args) {
+ try {
+ return m.invoke(recv, args);
+ } catch (InvocationTargetException ex) {
+ Throwable ex2 = ex.getCause();
+ if (ex2 instanceof RuntimeException) throw (RuntimeException) ex2;
+ if (ex2 instanceof Error) throw (Error) ex2;
+ throw new AssertionError(ex);
+ } catch (ReflectiveOperationException ex) {
+ throw new AssertionError(ex);
+ }
+ }
+
+ static List<Member> limit(int len, List<Member> mems) {
+ if (mems.size() <= len) return mems;
+ return mems.subList(0, len);
+ }
+ @SafeVarargs
+ static List<Member> union(List<Member> mems, List<Member>... mem2s) {
+ for (List<Member> mem2 : mem2s) {
+ for (Member m : mem2) {
+ if (!mems.contains(m))
+ mems.add(m);
+ }
+ }
+ return mems;
+ }
+ static List<Member> callerSensitive(boolean cond, List<Member> members) {
+ for (Iterator<Member> i = members.iterator(); i.hasNext(); ) {
+ Member mem = i.next();
+ if (isCallerSensitive(mem) != cond)
+ i.remove();
+ }
+ if (members.isEmpty()) throw new AssertionError("trivial result");
+ return members;
+ }
+ static boolean isCallerSensitive(Member mem) {
+ if (!(mem instanceof AnnotatedElement)) return false;
+ AnnotatedElement ae = (AnnotatedElement) mem;
+ if (CS_CLASS != null)
+ return ae.isAnnotationPresent(sun.reflect.CallerSensitive.class);
+ for (java.lang.annotation.Annotation a : ae.getDeclaredAnnotations()) {
+ if (a.toString().contains(".CallerSensitive"))
+ return true;
+ }
+ return false;
+ }
+ static final Class<?> CS_CLASS;
+ static {
+ Class<?> c = null;
+ try {
+ c = sun.reflect.CallerSensitive.class;
+ } catch (SecurityException | LinkageError ex) {
+ }
+ CS_CLASS = c;
+ }
+ static List<Member> publicOnly(List<Member> members) {
+ return removeMods(members, Modifier.PUBLIC, 0);
+ }
+ static List<Member> nonPublicOnly(List<Member> members) {
+ return removeMods(members, Modifier.PUBLIC, -1);
+ }
+ static List<Member> removeMods(List<Member> members, int mask, int bits) {
+ int publicMods = (mask & Modifier.PUBLIC);
+ members = new ArrayList<>(members);
+ for (Iterator<Member> i = members.iterator(); i.hasNext(); ) {
+ Member mem = i.next();
+ int mods = mem.getModifiers();
+ if ((publicMods & mods) != 0 &&
+ (publicMods & mem.getDeclaringClass().getModifiers()) == 0)
+ mods -= publicMods;
+ if ((mods & mask) == (bits & mask))
+ i.remove();
+ }
+ return members;
+ }
+
+ void testOnMembers(String tname, List<Member> mems, Lookup lookup, Lookup... lookups) throws Throwable {
+ if (VERBOSE) System.out.println("testOnMembers "+mems);
+ Lookup revLookup = (lookups.length > 0) ? lookups[0] : null;
+ if (revLookup == null) revLookup = lookup;
+ Lookup refLookup = (lookups.length > 1) ? lookups[1] : null;
+ if (refLookup == null) refLookup = lookup;
+ assert(lookups.length <= 2);
+ testOnMembersImpl(tname, mems, lookup, revLookup, refLookup, NO_FAIL);
+ }
+ void testOnMembersNoLookup(String tname, List<Member> mems, Lookup lookup) throws Throwable {
+ if (VERBOSE) System.out.println("testOnMembersNoLookup "+mems);
+ testOnMembersImpl(tname, mems, lookup, null, null, FAIL_LOOKUP);
+ }
+ void testOnMembersNoReveal(String tname, List<Member> mems,
+ Lookup lookup, Lookup negLookup) throws Throwable {
+ if (VERBOSE) System.out.println("testOnMembersNoReveal "+mems);
+ testOnMembersImpl(tname, mems, lookup, negLookup, null, FAIL_REVEAL);
+ }
+ void testOnMembersNoReflect(String tname, List<Member> mems,
+ Lookup lookup, Lookup negLookup) throws Throwable {
+ if (VERBOSE) System.out.println("testOnMembersNoReflect "+mems);
+ testOnMembersImpl(tname, mems, lookup, lookup, negLookup, FAIL_REFLECT);
+ }
+ void testOnMembersImpl(String tname, List<Member> mems,
+ Lookup lookup,
+ Lookup revLookup,
+ Lookup refLookup,
+ int failureMode) throws Throwable {
+ Throwable fail = null;
+ int failCount = 0;
+ failureModeCounts = new int[FAIL_MODE_COUNT];
+ long tm0 = System.currentTimeMillis();
+ for (Member mem : mems) {
+ try {
+ testWithMember(mem, lookup, revLookup, refLookup, failureMode);
+ } catch (Throwable ex) {
+ if (fail == null) fail = ex;
+ if (++failCount > 10) { System.out.println("*** FAIL: too many failures"); break; }
+ System.out.println("*** FAIL: "+mem+" => "+ex);
+ if (VERBOSE) ex.printStackTrace(System.out);
+ }
+ }
+ long tm1 = System.currentTimeMillis();
+ System.out.printf("@Test %s executed %s tests in %d ms",
+ tname, testKinds(failureModeCounts), (tm1-tm0)).println();
+ if (fail != null) throw fail;
+ }
+ static String testKinds(int[] modes) {
+ int pos = modes[0], neg = -pos;
+ for (int n : modes) neg += n;
+ if (neg == 0) return pos + " positive";
+ String negs = "";
+ for (int n : modes) negs += "/"+n;
+ negs = negs.replaceFirst("/"+pos+"/", "");
+ negs += " negative";
+ if (pos == 0) return negs;
+ return pos + " positive, " + negs;
+ }
+ static class SignaturePolymorphicMethod implements Member { // non-reflected instance of MH.invoke*
+ final String name;
+ final MethodType type;
+ SignaturePolymorphicMethod(String name, MethodType type) {
+ this.name = name;
+ this.type = type;
+ }
+ public String toString() {
+ String typeStr = type.toString();
+ if (isVarArgs()) typeStr = typeStr.replaceFirst("\\[\\])$", "...)");
+ return (Modifier.toString(getModifiers())
+ +typeStr.substring(0, typeStr.indexOf('('))+" "
+ +getDeclaringClass().getTypeName()+"."
+ +getName()+typeStr.substring(typeStr.indexOf('(')));
+ }
+ public boolean equals(Object x) {
+ return (x instanceof SignaturePolymorphicMethod && equals((SignaturePolymorphicMethod)x));
+ }
+ public boolean equals(SignaturePolymorphicMethod that) {
+ return this.name.equals(that.name) && this.type.equals(that.type);
+ }
+ public int hashCode() {
+ return name.hashCode() * 31 + type.hashCode();
+ }
+ public Class<?> getDeclaringClass() { return MethodHandle.class; }
+ public String getName() { return name; }
+ public MethodType getMethodType() { return type; }
+ public int getModifiers() { return Modifier.PUBLIC | Modifier.FINAL | Modifier.NATIVE | SYNTHETIC; }
+ public boolean isVarArgs() { return Modifier.isTransient(getModifiers()); }
+ public boolean isSynthetic() { return true; }
+ public Class<?> getReturnType() { return type.returnType(); }
+ public Class<?>[] getParameterTypes() { return type.parameterArray(); }
+ static final int SYNTHETIC = 0x00001000;
+ }
+ static class UnreflectResult { // a tuple
+ final MethodHandle mh;
+ final Throwable ex;
+ final byte kind;
+ final Member mem;
+ final int var;
+ UnreflectResult(MethodHandle mh, byte kind, Member mem, int var) {
+ this.mh = mh;
+ this.ex = null;
+ this.kind = kind;
+ this.mem = mem;
+ this.var = var;
+ }
+ UnreflectResult(Throwable ex, byte kind, Member mem, int var) {
+ this.mh = null;
+ this.ex = ex;
+ this.kind = kind;
+ this.mem = mem;
+ this.var = var;
+ }
+ public String toString() {
+ return toInfoString()+"/v"+var;
+ }
+ public String toInfoString() {
+ return String.format("%s %s.%s:%s", MethodHandleInfo.referenceKindToString(kind),
+ mem.getDeclaringClass().getName(), name(mem), type(mem, kind));
+ }
+ static String name(Member mem) {
+ if (mem instanceof Constructor) return "<init>";
+ return mem.getName();
+ }
+ static MethodType type(Member mem, byte kind) {
+ if (mem instanceof Field) {
+ Class<?> type = ((Field)mem).getType();
+ if (kind == REF_putStatic || kind == REF_putField)
+ return methodType(void.class, type);
+ return methodType(type);
+ } else if (mem instanceof SignaturePolymorphicMethod) {
+ return ((SignaturePolymorphicMethod)mem).getMethodType();
+ }
+ Class<?>[] params = ((Executable)mem).getParameterTypes();
+ if (mem instanceof Constructor)
+ return methodType(void.class, params);
+ Class<?> type = ((Method)mem).getReturnType();
+ return methodType(type, params);
+ }
+ }
+ static UnreflectResult unreflectMember(Lookup lookup, Member mem, int variation) {
+ byte[] refKind = {0};
+ try {
+ return unreflectMemberOrThrow(lookup, mem, variation, refKind);
+ } catch (ReflectiveOperationException|SecurityException ex) {
+ return new UnreflectResult(ex, refKind[0], mem, variation);
+ }
+ }
+ static UnreflectResult unreflectMemberOrThrow(Lookup lookup, Member mem, int variation,
+ byte[] refKind) throws ReflectiveOperationException {
+ Class<?> cls = lookup.lookupClass();
+ Class<?> defc = mem.getDeclaringClass();
+ String name = mem.getName();
+ int mods = mem.getModifiers();
+ boolean isStatic = Modifier.isStatic(mods);
+ MethodHandle mh = null;
+ byte kind = 0;
+ if (mem instanceof Method) {
+ Method m = (Method) mem;
+ MethodType type = methodType(m.getReturnType(), m.getParameterTypes());
+ boolean canBeSpecial = (!isStatic &&
+ (lookup.lookupModes() & Modifier.PRIVATE) != 0 &&
+ defc.isAssignableFrom(cls) &&
+ (!defc.isInterface() || Arrays.asList(cls.getInterfaces()).contains(defc)));
+ if (variation >= 2)
+ kind = REF_invokeSpecial;
+ else if (isStatic)
+ kind = REF_invokeStatic;
+ else if (defc.isInterface())
+ kind = REF_invokeInterface;
+ else
+ kind = REF_invokeVirtual;
+ refKind[0] = kind;
+ switch (variation) {
+ case 0:
+ mh = lookup.unreflect(m);
+ break;
+ case 1:
+ if (defc == MethodHandle.class &&
+ !isStatic &&
+ m.isVarArgs() &&
+ Modifier.isFinal(mods) &&
+ Modifier.isNative(mods)) {
+ break;
+ }
+ if (isStatic)
+ mh = lookup.findStatic(defc, name, type);
+ else
+ mh = lookup.findVirtual(defc, name, type);
+ break;
+ case 2:
+ if (!canBeSpecial)
+ break;
+ mh = lookup.unreflectSpecial(m, lookup.lookupClass());
+ break;
+ case 3:
+ if (!canBeSpecial)
+ break;
+ mh = lookup.findSpecial(defc, name, type, lookup.lookupClass());
+ break;
+ }
+ } else if (mem instanceof SignaturePolymorphicMethod) {
+ SignaturePolymorphicMethod m = (SignaturePolymorphicMethod) mem;
+ MethodType type = methodType(m.getReturnType(), m.getParameterTypes());
+ kind = REF_invokeVirtual;
+ refKind[0] = kind;
+ switch (variation) {
+ case 0:
+ mh = lookup.findVirtual(defc, name, type);
+ break;
+ }
+ } else if (mem instanceof Constructor) {
+ name = "<init>"; // not used
+ Constructor<?> m = (Constructor<?>) mem;
+ MethodType type = methodType(void.class, m.getParameterTypes());
+ kind = REF_newInvokeSpecial;
+ refKind[0] = kind;
+ switch (variation) {
+ case 0:
+ mh = lookup.unreflectConstructor(m);
+ break;
+ case 1:
+ mh = lookup.findConstructor(defc, type);
+ break;
+ }
+ } else if (mem instanceof Field) {
+ Field m = (Field) mem;
+ Class<?> type = m.getType();
+ boolean canHaveSetter = !Modifier.isFinal(mods);
+ if (variation >= 2)
+ kind = (byte)(isStatic ? REF_putStatic : REF_putField);
+ else
+ kind = (byte)(isStatic ? REF_getStatic : REF_getField);
+ refKind[0] = kind;
+ switch (variation) {
+ case 0:
+ mh = lookup.unreflectGetter(m);
+ break;
+ case 1:
+ if (isStatic)
+ mh = lookup.findStaticGetter(defc, name, type);
+ else
+ mh = lookup.findGetter(defc, name, type);
+ break;
+ case 3:
+ if (!canHaveSetter)
+ break;
+ mh = lookup.unreflectSetter(m);
+ break;
+ case 2:
+ if (!canHaveSetter)
+ break;
+ if (isStatic)
+ mh = lookup.findStaticSetter(defc, name, type);
+ else
+ mh = lookup.findSetter(defc, name, type);
+ break;
+ }
+ } else {
+ throw new IllegalArgumentException(String.valueOf(mem));
+ }
+ if (mh == null)
+ // ran out of valid variations; return null to caller
+ return null;
+ return new UnreflectResult(mh, kind, mem, variation);
+ }
+ static boolean canBeReached(Member mem, Class<?> cls) {
+ Class<?> defc = mem.getDeclaringClass();
+ String name = mem.getName();
+ int mods = mem.getModifiers();
+ if (mem instanceof Constructor) {
+ name = "<init>"; // according to 292 spec.
+ }
+ if (defc == cls)
+ return true;
+ if (name.startsWith("<"))
+ return false; // only my own constructors
+ if (Modifier.isPrivate(mods))
+ return false; // only my own constructors
+ if (defc.getPackage() == cls.getPackage())
+ return true; // package access or greater OK
+ if (Modifier.isPublic(mods))
+ return true; // publics always OK
+ if (Modifier.isProtected(mods) && defc.isAssignableFrom(cls))
+ return true; // protected OK
+ return false;
+ }
+ static boolean consistent(UnreflectResult res, MethodHandleInfo info) {
+ assert(res.mh != null);
+ assertEquals(res.kind, info.getReferenceKind());
+ assertEquals(res.mem.getModifiers(), info.getModifiers());
+ assertEquals(res.mem.getDeclaringClass(), info.getDeclaringClass());
+ String expectName = res.mem.getName();
+ if (res.kind == REF_newInvokeSpecial)
+ expectName = "<init>";
+ assertEquals(expectName, info.getName());
+ MethodType expectType = res.mh.type();
+ if ((res.kind & 1) == (REF_getField & 1))
+ expectType = expectType.dropParameterTypes(0, 1);
+ if (res.kind == REF_newInvokeSpecial)
+ expectType = expectType.changeReturnType(void.class);
+ assertEquals(expectType, info.getMethodType());
+ assertEquals(res.mh.isVarargsCollector(), isVarArgs(info));
+ assertEquals(res.toInfoString(), info.toString());
+ assertEquals(res.toInfoString(), MethodHandleInfo.toString(info.getReferenceKind(), info.getDeclaringClass(), info.getName(), info.getMethodType()));
+ return true;
+ }
+ static boolean isVarArgs(MethodHandleInfo info) {
+ return info.isVarArgs();
+ }
+ static boolean consistent(Member mem, Member mem2) {
+ assertEquals(mem, mem2);
+ return true;
+ }
+ static boolean consistent(MethodHandleInfo info, MethodHandleInfo info2) {
+ assertEquals(info.getReferenceKind(), info2.getReferenceKind());
+ assertEquals(info.getModifiers(), info2.getModifiers());
+ assertEquals(info.getDeclaringClass(), info2.getDeclaringClass());
+ assertEquals(info.getName(), info2.getName());
+ assertEquals(info.getMethodType(), info2.getMethodType());
+ assertEquals(isVarArgs(info), isVarArgs(info));
+ return true;
+ }
+ static boolean consistent(MethodHandle mh, MethodHandle mh2) {
+ assertEquals(mh.type(), mh2.type());
+ assertEquals(mh.isVarargsCollector(), mh2.isVarargsCollector());
+ return true;
+ }
+ int[] failureModeCounts;
+ static final int NO_FAIL=0, FAIL_LOOKUP=1, FAIL_REVEAL=2, FAIL_REFLECT=3, FAIL_MODE_COUNT=4;
+ void testWithMember(Member mem,
+ Lookup lookup, // initial lookup of member => MH
+ Lookup revLookup, // reveal MH => info
+ Lookup refLookup, // reflect info => member
+ int failureMode) throws Throwable {
+ boolean expectEx1 = (failureMode == FAIL_LOOKUP); // testOnMembersNoLookup
+ boolean expectEx2 = (failureMode == FAIL_REVEAL); // testOnMembersNoReveal
+ boolean expectEx3 = (failureMode == FAIL_REFLECT); // testOnMembersNoReflect
+ for (int variation = 0; ; variation++) {
+ UnreflectResult res = unreflectMember(lookup, mem, variation);
+ failureModeCounts[failureMode] += 1;
+ if (variation == 0) assert(res != null);
+ if (res == null) break;
+ if (VERBOSE && variation == 0)
+ System.out.println("from "+mem.getDeclaringClass().getSimpleName());
+ MethodHandle mh = res.mh;
+ Throwable ex1 = res.ex;
+ if (VERBOSE) System.out.println(" "+variation+": "+res+" << "+(mh != null ? mh : ex1));
+ if (expectEx1 && ex1 != null)
+ continue; // this is OK; we expected that lookup to fail
+ if (expectEx1)
+ throw new AssertionError("unexpected lookup for negative test");
+ if (ex1 != null && !expectEx1) {
+ if (failureMode != NO_FAIL)
+ throw new AssertionError("unexpected lookup failure for negative test", ex1);
+ throw ex1;
+ }
+ MethodHandleInfo info;
+ try {
+ info = revLookup.revealDirect(mh);
+ if (expectEx2) throw new AssertionError("unexpected revelation for negative test");
+ } catch (Throwable ex2) {
+ if (VERBOSE) System.out.println(" "+variation+": "+res+" => "+mh.getClass().getName()+" => (EX2)"+ex2);
+ if (expectEx2)
+ continue; // this is OK; we expected the reflect to fail
+ if (failureMode != NO_FAIL)
+ throw new AssertionError("unexpected revelation failure for negative test", ex2);
+ throw ex2;
+ }
+ assert(consistent(res, info));
+ Member mem2;
+ try {
+ mem2 = info.reflectAs(Member.class, refLookup);
+ if (expectEx3) throw new AssertionError("unexpected reflection for negative test");
+ assert(!(mem instanceof SignaturePolymorphicMethod));
+ } catch (IllegalArgumentException ex3) {
+ if (VERBOSE) System.out.println(" "+variation+": "+info+" => (EX3)"+ex3);
+ if (expectEx3)
+ continue; // this is OK; we expected the reflect to fail
+ if (mem instanceof SignaturePolymorphicMethod)
+ continue; // this is OK; we cannot reflect MH.invokeExact(a,b,c)
+ if (failureMode != NO_FAIL)
+ throw new AssertionError("unexpected reflection failure for negative test", ex3);
+ throw ex3;
+ }
+ assert(consistent(mem, mem2));
+ UnreflectResult res2 = unreflectMember(lookup, mem2, variation);
+ MethodHandle mh2 = res2.mh;
+ assert(consistent(mh, mh2));
+ MethodHandleInfo info2 = lookup.revealDirect(mh2);
+ assert(consistent(info, info2));
+ assert(consistent(res, info2));
+ Member mem3;
+ if (hasSM())
+ mem3 = info2.reflectAs(Member.class, lookup);
+ else
+ mem3 = MethodHandles.reflectAs(Member.class, mh2);
+ assert(consistent(mem2, mem3));
+ if (hasSM()) {
+ try {
+ MethodHandles.reflectAs(Member.class, mh2);
+ throw new AssertionError("failed to throw on "+mem3);
+ } catch (SecurityException ex3) {
+ // OK...
+ }
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/jtreg.security.policy Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,9 @@
+/*
+ * security policy used by the test process
+ * must allow file reads so that jtreg itself can run
+ */
+
+grant {
+ // standard test activation permissions
+ permission java.io.FilePermission "*", "read";
+};
--- a/jdk/test/java/lang/management/ThreadMXBean/LockedMonitors.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/lang/management/ThreadMXBean/LockedMonitors.java Sat Sep 14 20:43:34 2013 +0100
@@ -37,7 +37,7 @@
* @build Barrier
* @build LockingThread
* @build ThreadDump
- * @run main LockedMonitors
+ * @run main/othervm LockedMonitors
*/
import java.lang.management.*;
--- a/jdk/test/java/lang/management/ThreadMXBean/LockedSynchronizers.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/lang/management/ThreadMXBean/LockedSynchronizers.java Sat Sep 14 20:43:34 2013 +0100
@@ -33,7 +33,7 @@
* @build Barrier
* @build SynchronizerLockingThread
* @build ThreadDump
- * @run main LockedSynchronizers
+ * @run main/othervm LockedSynchronizers
*/
import java.lang.management.*;
--- a/jdk/test/java/lang/management/ThreadMXBean/Locks.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/lang/management/ThreadMXBean/Locks.java Sat Sep 14 20:43:34 2013 +0100
@@ -193,16 +193,18 @@
public CheckerThread() {
super("CheckerThread");
}
+
+ private void waitForState(Thread.State state) {
+ thrsync.waitForSignal();
+ while (waiter.getState() != state) {
+ goSleep(10);
+ }
+ }
+
public void run() {
synchronized (ready) {
// wait until WaitingThread about to wait for objC
- thrsync.waitForSignal();
-
- int retryCount = 0;
- while (waiter.getState() != Thread.State.WAITING
- && retryCount++ < 500) {
- goSleep(100);
- }
+ waitForState(Thread.State.WAITING);
checkBlockedObject(waiter, objC, null, Thread.State.WAITING);
synchronized (objC) {
@@ -211,16 +213,13 @@
// wait for waiter thread to about to enter
// synchronized object ready.
- thrsync.waitForSignal();
- // give chance for waiter thread to get blocked on
- // object ready.
- goSleep(50);
+ waitForState(Thread.State.BLOCKED);
checkBlockedObject(waiter, ready, this, Thread.State.BLOCKED);
}
// wait for signal from waiting thread that it is about
// wait for objC.
- thrsync.waitForSignal();
+ waitForState(Thread.State.WAITING);
synchronized(objC) {
checkBlockedObject(waiter, objC, Thread.currentThread(), Thread.State.WAITING);
objC.notify();
--- a/jdk/test/java/lang/management/ThreadMXBean/MyOwnSynchronizer.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/lang/management/ThreadMXBean/MyOwnSynchronizer.java Sat Sep 14 20:43:34 2013 +0100
@@ -30,7 +30,7 @@
*
* @build Barrier
* @build ThreadDump
- * @run main MyOwnSynchronizer
+ * @run main/othervm MyOwnSynchronizer
*/
import java.lang.management.*;
--- a/jdk/test/java/lang/management/ThreadMXBean/SharedSynchronizer.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/lang/management/ThreadMXBean/SharedSynchronizer.java Sat Sep 14 20:43:34 2013 +0100
@@ -28,7 +28,7 @@
* in shared mode which has no owner when a thread is parked.
* @author Mandy Chung
*
- * @run main SharedSynchronizer
+ * @run main/othervm SharedSynchronizer
*/
--- a/jdk/test/java/lang/management/ThreadMXBean/SynchronizationStatistics.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/lang/management/ThreadMXBean/SynchronizationStatistics.java Sat Sep 14 20:43:34 2013 +0100
@@ -30,7 +30,7 @@
*
* @ignore 6309226
* @build Semaphore
- * @run main SynchronizationStatistics
+ * @run main/othervm SynchronizationStatistics
*/
import java.lang.management.*;
--- a/jdk/test/java/lang/management/ThreadMXBean/ThreadExecutionSynchronizer.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/lang/management/ThreadMXBean/ThreadExecutionSynchronizer.java Sat Sep 14 20:43:34 2013 +0100
@@ -23,7 +23,7 @@
/*
*
- * @summary Thiseclass is used to synchronize execution off two threads.
+ * @summary This class is used to synchronize execution of two threads.
* @author Swamy Venkataramanappa
*/
@@ -31,8 +31,8 @@
public class ThreadExecutionSynchronizer {
- private boolean waiting;
- private Semaphore semaphore;
+ private volatile boolean waiting;
+ private final Semaphore semaphore;
public ThreadExecutionSynchronizer() {
semaphore = new Semaphore(1);
--- a/jdk/test/java/lang/reflect/Generics/Probe.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/lang/reflect/Generics/Probe.java Sat Sep 14 20:43:34 2013 +0100
@@ -50,9 +50,9 @@
"java.util.HashMap$EntryIterator",
"java.util.HashMap$KeyIterator",
"java.util.HashMap$ValueIterator",
- "java.util.LinkedHashMap$EntryIterator",
- "java.util.LinkedHashMap$KeyIterator",
- "java.util.LinkedHashMap$ValueIterator"})
+ "java.util.LinkedHashMap$LinkedEntryIterator",
+ "java.util.LinkedHashMap$LinkedKeyIterator",
+ "java.util.LinkedHashMap$LinkedValueIterator"})
public class Probe {
public static void main (String... args) throws Throwable {
Classes classesAnnotation = (Probe.class).getAnnotation(Classes.class);
--- a/jdk/test/java/net/CookieHandler/LocalHostCookie.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/net/CookieHandler/LocalHostCookie.java Sat Sep 14 20:43:34 2013 +0100
@@ -72,7 +72,9 @@
}
}
} finally {
- s.stopServer();
+ if (s != null) {
+ s.stopServer();
+ }
}
}
@@ -96,7 +98,9 @@
}
public void stopServer() {
- server.stop(0);
+ if (server != null) {
+ server.stop(0);
+ }
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/IDN/UseSTD3ASCIIRules.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8023881
+ * @summary IDN.USE_STD3_ASCII_RULES option is too strict to use Unicode
+ * in IDN.toASCII
+ */
+
+import java.net.*;
+
+public class UseSTD3ASCIIRules {
+
+ public static void main(String[] args) throws Exception {
+ // Per Section 4.1, RFC 3490, if the UseSTD3ASCIIRules flag is set,
+ // then perform these checks:
+ //
+ // (a) Verify the absence of non-LDH ASCII code points; that is, the
+ // absence of 0..2C, 2E..2F, 3A..40, 5B..60, and 7B..7F.
+ //
+ // (b) Verify the absence of leading and trailing hyphen-minus; that
+ // is, the absence of U+002D at the beginning and end of the
+ // sequence.
+ String[] illegalNames = {
+ "www.example.com-",
+ "-www.example.com",
+ "-www.example.com-",
+ "www.ex\u002Cmple.com",
+ "www.ex\u007Bmple.com",
+ "www.ex\u007Fmple.com"
+ };
+
+ String[] legalNames = {
+ "www.ex-ample.com",
+ "www.ex\u002Dmple.com", // www.ex-mple.com
+ "www.ex\u007Ample.com", // www.exzmple.com
+ "www.ex\u3042mple.com", // www.xn--exmple-j43e.com
+ "www.\u3042\u3044\u3046.com", // www.xn--l8jeg.com
+ "www.\u793A\u4F8B.com" // www.xn--fsq092h.com
+ };
+
+ for (String name : illegalNames) {
+ try {
+ System.out.println("Convering illegal IDN: " + name);
+ IDN.toASCII(name, IDN.USE_STD3_ASCII_RULES);
+ throw new Exception(
+ "Expected to get IllegalArgumentException for " + name);
+ } catch (IllegalArgumentException iae) {
+ // That's the right behavior.
+ }
+ }
+
+ for (String name : legalNames) {
+ System.out.println("Convering legal IDN: " + name);
+ System.out.println("\tThe ACE form is: " +
+ IDN.toASCII(name, IDN.USE_STD3_ASCII_RULES));
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/MulticastSocket/SetGetNetworkInterfaceTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+
+/*
+ * @test
+ * @bug 6458027
+ * @summary Disabling IPv6 on a specific network interface causes problems.
+ *
+ */
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.MulticastSocket;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Arrays;
+import java.util.Enumeration;
+
+
+public class SetGetNetworkInterfaceTest {
+
+ public static void main(String[] args) throws Exception {
+
+ boolean passed = true;
+ try {
+ MulticastSocket ms = new MulticastSocket();
+ Enumeration<NetworkInterface> networkInterfaces = NetworkInterface
+ .getNetworkInterfaces();
+ while (networkInterfaces.hasMoreElements()) {
+ NetworkInterface netIf = networkInterfaces.nextElement();
+ if (isNetworkInterfaceTestable(netIf)) {
+ printNetIfDetails(netIf);
+ ms.setNetworkInterface(netIf);
+ NetworkInterface msNetIf = ms.getNetworkInterface();
+ if (netIf.equals(msNetIf)) {
+ System.out.println(" OK");
+ } else {
+ System.out.println("FAILED!!!");
+ printNetIfDetails(msNetIf);
+ passed = false;
+ }
+ System.out.println("------------------");
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ passed = false;
+ }
+ if (!passed) {
+ throw new RuntimeException("Test Fail");
+ }
+ System.out.println("Test passed ");
+ }
+
+ private static boolean isNetworkInterfaceTestable(NetworkInterface netIf) throws Exception {
+ System.out.println("checking netif == " + netIf.getName());
+ return (netIf.isUp() && netIf.supportsMulticast() && isIpAddrAvailable(netIf));
+ }
+
+ private static boolean isIpAddrAvailable (NetworkInterface netIf) {
+ boolean ipAddrAvailable = false;
+ byte[] nullIpAddr = {'0', '0', '0', '0'};
+ byte[] testIpAddr = null;
+
+ Enumeration<InetAddress> ipAddresses = netIf.getInetAddresses();
+ while (ipAddresses.hasMoreElements()) {
+ InetAddress testAddr = ipAddresses.nextElement();
+ testIpAddr = testAddr.getAddress();
+ if ((testIpAddr != null) && (!Arrays.equals(testIpAddr, nullIpAddr))) {
+ ipAddrAvailable = true;
+ break;
+ } else {
+ System.out.println("ignore netif " + netIf.getName());
+ }
+ }
+ return ipAddrAvailable;
+ }
+
+ private static void printNetIfDetails(NetworkInterface ni)
+ throws SocketException {
+ System.out.println("Name " + ni.getName() + " index " + ni.getIndex());
+ Enumeration<InetAddress> en = ni.getInetAddresses();
+ while (en.hasMoreElements()) {
+ System.out.println(" InetAdress: " + en.nextElement());
+ }
+ System.out.println("HardwareAddress: " + createMacAddrString(ni));
+ System.out.println("loopback: " + ni.isLoopback() + "; pointToPoint: "
+ + ni.isPointToPoint() + "; virtual: " + ni.isVirtual()
+ + "; MTU: " + ni.getMTU());
+ }
+
+ private static String createMacAddrString(NetworkInterface netIf)
+ throws SocketException {
+ byte[] macAddr = netIf.getHardwareAddress();
+ StringBuilder sb = new StringBuilder();
+ if (macAddr != null) {
+ for (int i = 0; i < macAddr.length; i++) {
+ sb.append(String.format("%02X%s", macAddr[i],
+ (i < macAddr.length - 1) ? "-" : ""));
+ }
+ }
+ return sb.toString();
+ }
+}
--- a/jdk/test/java/net/NetworkInterface/Equals.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/net/NetworkInterface/Equals.java Sat Sep 14 20:43:34 2013 +0100
@@ -25,41 +25,83 @@
* @bug 7003398
* @run main/othervm Equals
*/
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.net.InetAddress;
import java.net.NetworkInterface;
-import java.net.InetAddress;
+import java.net.SocketException;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
public class Equals {
public static void main(String args[]) throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintStream bufferedOut = new PrintStream(baos);
- Enumeration nifs1 = NetworkInterface.getNetworkInterfaces();
+ Enumeration<NetworkInterface> nifs1 = NetworkInterface.getNetworkInterfaces();
HashMap<String,Integer> hashes = new HashMap<>();
HashMap<String,NetworkInterface> nicMap = new HashMap<>();
while (nifs1.hasMoreElements()) {
- NetworkInterface ni = (NetworkInterface)nifs1.nextElement();
+ NetworkInterface ni = nifs1.nextElement();
hashes.put(ni.getName(),ni.hashCode());
nicMap.put(ni.getName(),ni);
+ displayInterfaceInformation(ni, bufferedOut);
+ bufferedOut.flush();
}
System.setSecurityManager(new SecurityManager());
- Enumeration nifs2 = NetworkInterface.getNetworkInterfaces();
+ Enumeration<NetworkInterface> nifs2 = NetworkInterface.getNetworkInterfaces();
while (nifs2.hasMoreElements()) {
- NetworkInterface ni = (NetworkInterface)nifs2.nextElement();
+ NetworkInterface ni = nifs2.nextElement();
NetworkInterface niOrig = nicMap.get(ni.getName());
- int h = hashes.get(ni.getName());
- if (h != ni.hashCode()) {
- throw new RuntimeException ("Hashcodes different for " +
+ int h = ni.hashCode();
+ if (h != hashes.get(ni.getName())) {
+ System.out.printf("%nSystem information:%n");
+ System.out.printf("%s", baos.toString("UTF8"));
+ System.out.printf("%nni.hashCode() returned %d, expected %d, for:%n",
+ h, hashes.get(ni.getName()));
+ displayInterfaceInformation(ni, System.out);
+ throw new RuntimeException("Hashcodes different for " +
ni.getName());
}
if (!ni.equals(niOrig)) {
- throw new RuntimeException ("equality different for " +
+ System.out.printf("%nSystem information:%n");
+ System.out.printf("%s", baos.toString("UTF8"));
+ System.out.printf("%nExpected the following interfaces to be the same:%n");
+ displayInterfaceInformation(niOrig, System.out);
+ displayInterfaceInformation(ni, System.out);
+ throw new RuntimeException("equality different for " +
ni.getName());
}
}
}
+
+ static void displayInterfaceInformation(NetworkInterface netint,
+ PrintStream out) throws SocketException {
+ out.printf("Display name: %s%n", netint.getDisplayName());
+ out.printf("Name: %s%n", netint.getName());
+ Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();
+
+ for (InetAddress inetAddress : Collections.list(inetAddresses))
+ out.printf("InetAddress: %s%n", inetAddress);
+
+ out.printf("Up? %s%n", netint.isUp());
+ out.printf("Loopback? %s%n", netint.isLoopback());
+ out.printf("PointToPoint? %s%n", netint.isPointToPoint());
+ out.printf("Supports multicast? %s%n", netint.supportsMulticast());
+ out.printf("Virtual? %s%n", netint.isVirtual());
+ out.printf("Hardware address: %s%n",
+ Arrays.toString(netint.getHardwareAddress()));
+ out.printf("MTU: %s%n", netint.getMTU());
+ out.printf("Index: %s%n", netint.getIndex());
+ out.printf("%n");
+ }
}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/NetworkInterface/UniqueMacAddressesTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.List;
+
+
+/*
+ * @test
+ * @bug 8021372
+ * @summary Tests that the MAC addresses returned by NetworkInterface.getNetworkInterfaces are unique for each adapter.
+ *
+ */
+public class UniqueMacAddressesTest {
+
+ public static void main(String[] args) throws Exception {
+ new UniqueMacAddressesTest().execute();
+ System.out.println("UniqueMacAddressesTest: OK");
+ }
+
+ public UniqueMacAddressesTest() {
+ System.out.println("UniqueMacAddressesTest: start ");
+ }
+
+ public void execute() throws Exception {
+ Enumeration<NetworkInterface> networkInterfaces;
+ boolean areMacAddressesUnique = false;
+ List<NetworkInterface> networkInterfaceList = new ArrayList<NetworkInterface>();
+ networkInterfaces = NetworkInterface.getNetworkInterfaces();
+
+ // build a list of NetworkInterface objects to test MAC address
+ // uniqueness
+ createNetworkInterfaceList(networkInterfaces, networkInterfaceList);
+ areMacAddressesUnique = checkMacAddressesAreUnique(networkInterfaceList);
+ if (!areMacAddressesUnique) {
+ throw new RuntimeException("mac address uniqueness test failed");
+ }
+ }
+
+ private boolean checkMacAddressesAreUnique (
+ List<NetworkInterface> networkInterfaces) throws Exception {
+ boolean uniqueMacAddresses = true;
+ for (NetworkInterface networkInterface : networkInterfaces) {
+ for (NetworkInterface comparisonNetIf : networkInterfaces) {
+ System.out.println("Comparing netif "
+ + networkInterface.getName() + " and netif "
+ + comparisonNetIf.getName());
+ if (testMacAddressesEqual(networkInterface, comparisonNetIf)) {
+ uniqueMacAddresses = false;
+ break;
+ }
+ }
+ if (uniqueMacAddresses != true)
+ break;
+ }
+ return uniqueMacAddresses;
+ }
+
+ private boolean testMacAddressesEqual(NetworkInterface netIf1,
+ NetworkInterface netIf2) throws Exception {
+
+ byte[] rawMacAddress1 = null;
+ byte[] rawMacAddress2 = null;
+ boolean macAddressesEqual = false;
+ if (!netIf1.getName().equals(netIf2.getName())) {
+ System.out.println("compare hardware addresses "
+ + createMacAddressString(netIf1) + " and " + createMacAddressString(netIf2));
+ rawMacAddress1 = netIf1.getHardwareAddress();
+ rawMacAddress2 = netIf2.getHardwareAddress();
+ macAddressesEqual = Arrays.equals(rawMacAddress1, rawMacAddress2);
+ } else {
+ // same interface
+ macAddressesEqual = false;
+ }
+ return macAddressesEqual;
+ }
+
+ private String createMacAddressString (NetworkInterface netIf) throws Exception {
+ byte[] macAddr = netIf.getHardwareAddress();
+ StringBuilder sb = new StringBuilder();
+ if (macAddr != null) {
+ for (int i = 0; i < macAddr.length; i++) {
+ sb.append(String.format("%02X%s", macAddr[i],
+ (i < macAddr.length - 1) ? "-" : ""));
+ }
+ }
+ return sb.toString();
+ }
+
+ private void createNetworkInterfaceList(Enumeration<NetworkInterface> nis,
+ List<NetworkInterface> networkInterfaceList) throws Exception {
+ byte[] macAddr = null;
+ NetworkInterface netIf = null;
+ while (nis.hasMoreElements()) {
+ netIf = (NetworkInterface) nis.nextElement();
+ if (netIf.isUp()) {
+ macAddr = netIf.getHardwareAddress();
+ if (macAddr != null) {
+ System.out.println("Adding NetworkInterface "
+ + netIf.getName() + " with mac address "
+ + createMacAddressString(netIf));
+ networkInterfaceList.add(netIf);
+ }
+ }
+ }
+ }
+}
--- a/jdk/test/java/nio/file/Files/StreamTest.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/nio/file/Files/StreamTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -43,14 +43,13 @@
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
-import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.BiPredicate;
-import java.util.stream.CloseableStream;
+import java.util.stream.Stream;
import java.util.stream.Collectors;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
@@ -138,14 +137,14 @@
}
public void testBasic() {
- try (CloseableStream<Path> s = Files.list(testFolder)) {
- Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
+ try (Stream<Path> s = Files.list(testFolder)) {
+ Object[] actual = s.sorted().toArray();
assertEquals(actual, level1);
} catch (IOException ioe) {
fail("Unexpected IOException");
}
- try (CloseableStream<Path> s = Files.list(testFolder.resolve("empty"))) {
+ try (Stream<Path> s = Files.list(testFolder.resolve("empty"))) {
int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
assertEquals(count, 0, "Expect empty stream.");
} catch (IOException ioe) {
@@ -154,8 +153,8 @@
}
public void testWalk() {
- try (CloseableStream<Path> s = Files.walk(testFolder)) {
- Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
+ try (Stream<Path> s = Files.walk(testFolder)) {
+ Object[] actual = s.sorted().toArray();
assertEquals(actual, all);
} catch (IOException ioe) {
fail("Unexpected IOException");
@@ -163,9 +162,9 @@
}
public void testWalkOneLevel() {
- try (CloseableStream<Path> s = Files.walk(testFolder, 1)) {
+ try (Stream<Path> s = Files.walk(testFolder, 1)) {
Object[] actual = s.filter(path -> ! path.equals(testFolder))
- .sorted(Comparator.naturalOrder())
+ .sorted()
.toArray();
assertEquals(actual, level1);
} catch (IOException ioe) {
@@ -176,8 +175,8 @@
public void testWalkFollowLink() {
// If link is not supported, the directory structure won't have link.
// We still want to test the behavior with FOLLOW_LINKS option.
- try (CloseableStream<Path> s = Files.walk(testFolder, FileVisitOption.FOLLOW_LINKS)) {
- Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
+ try (Stream<Path> s = Files.walk(testFolder, FileVisitOption.FOLLOW_LINKS)) {
+ Object[] actual = s.sorted().toArray();
assertEquals(actual, all_folowLinks);
} catch (IOException ioe) {
fail("Unexpected IOException");
@@ -185,7 +184,7 @@
}
private void validateFileSystemLoopException(Path start, Path... causes) {
- try (CloseableStream<Path> s = Files.walk(start, FileVisitOption.FOLLOW_LINKS)) {
+ try (Stream<Path> s = Files.walk(start, FileVisitOption.FOLLOW_LINKS)) {
try {
int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
fail("Should got FileSystemLoopException, but got " + count + "elements.");
@@ -282,28 +281,28 @@
public void testFind() throws IOException {
PathBiPredicate pred = new PathBiPredicate((path, attrs) -> true);
- try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
+ try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
Set<Path> result = s.collect(Collectors.toCollection(TreeSet::new));
assertEquals(pred.visited(), all);
assertEquals(result.toArray(new Path[0]), pred.visited());
}
pred = new PathBiPredicate((path, attrs) -> attrs.isSymbolicLink());
- try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
+ try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
s.forEach(path -> assertTrue(Files.isSymbolicLink(path)));
assertEquals(pred.visited(), all);
}
pred = new PathBiPredicate((path, attrs) ->
path.getFileName().toString().startsWith("e"));
- try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
+ try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
s.forEach(path -> assertEquals(path.getFileName().toString(), "empty"));
assertEquals(pred.visited(), all);
}
pred = new PathBiPredicate((path, attrs) ->
path.getFileName().toString().startsWith("l") && attrs.isRegularFile());
- try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
+ try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
s.forEach(path -> fail("Expect empty stream"));
assertEquals(pred.visited(), all);
}
@@ -317,14 +316,14 @@
try {
// zero lines
assertTrue(Files.size(tmpfile) == 0, "File should be empty");
- try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
+ try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
assertEquals(s.mapToInt(l -> 1).reduce(0, Integer::sum), 0, "No line expected");
}
// one line
byte[] hi = { (byte)'h', (byte)'i' };
Files.write(tmpfile, hi);
- try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
+ try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
List<String> lines = s.collect(Collectors.toList());
assertTrue(lines.size() == 1, "One line expected");
assertTrue(lines.get(0).equals("hi"), "'Hi' expected");
@@ -334,7 +333,7 @@
List<String> expected = Arrays.asList("hi", "there");
Files.write(tmpfile, expected, US_ASCII);
assertTrue(Files.size(tmpfile) > 0, "File is empty");
- try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
+ try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
List<String> lines = s.collect(Collectors.toList());
assertTrue(lines.equals(expected), "Unexpected lines");
}
@@ -342,7 +341,7 @@
// MalformedInputException
byte[] bad = { (byte)0xff, (byte)0xff };
Files.write(tmpfile, bad);
- try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
+ try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
try {
List<String> lines = s.collect(Collectors.toList());
throw new RuntimeException("UncheckedIOException expected");
@@ -378,7 +377,7 @@
fsp.setFaultyMode(false);
Path fakeRoot = fs.getRoot();
try {
- try (CloseableStream<Path> s = Files.list(fakeRoot)) {
+ try (Stream<Path> s = Files.list(fakeRoot)) {
s.forEach(path -> assertEquals(path.getFileName().toString(), "DirectoryIteratorException"));
}
} catch (UncheckedIOException uioe) {
@@ -398,7 +397,7 @@
}
try {
- try (CloseableStream<Path> s = Files.list(fakeRoot)) {
+ try (Stream<Path> s = Files.list(fakeRoot)) {
s.forEach(path -> fail("should not get here"));
}
} catch (UncheckedIOException uioe) {
@@ -427,12 +426,12 @@
try {
fsp.setFaultyMode(false);
Path fakeRoot = fs.getRoot();
- try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
+ try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
// only one file
s.forEach(path -> assertEquals(path.getFileName().toString(), "IOException"));
}
- try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
+ try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
String[] result = s.map(path -> path.getFileName().toString())
.toArray(String[]::new);
// ordered as depth-first
@@ -440,13 +439,13 @@
}
fsp.setFaultyMode(true);
- try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
+ try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
s.forEach(path -> fail("should have caused exception"));
} catch (UncheckedIOException uioe) {
assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
}
- try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
+ try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
String[] result = s.map(path -> path.getFileName().toString())
.toArray(String[]::new);
fail("should not reach here due to IOException");
@@ -454,7 +453,7 @@
assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
}
- try (CloseableStream<Path> s = Files.walk(
+ try (Stream<Path> s = Files.walk(
fakeRoot.resolve("empty").resolve("IOException")))
{
String[] result = s.map(path -> path.getFileName().toString())
@@ -502,20 +501,20 @@
fsp.setFaultyMode(false);
Path fakeRoot = fs.getRoot();
// validate setting
- try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
+ try (Stream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
String[] result = s.map(path -> path.getFileName().toString())
.toArray(String[]::new);
assertEqualsNoOrder(result, new String[] { "SecurityException", "sample" });
}
- try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
+ try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
String[] result = s.map(path -> path.getFileName().toString())
.toArray(String[]::new);
assertEqualsNoOrder(result, new String[] { "dir2", "SecurityException", "fileInSE", "file" });
}
if (supportsLinks) {
- try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir"))) {
+ try (Stream<Path> s = Files.list(fakeRoot.resolve("dir"))) {
String[] result = s.map(path -> path.getFileName().toString())
.toArray(String[]::new);
assertEqualsNoOrder(result, new String[] { "d1", "f1", "lnDir2", "SecurityException", "lnDirSE", "lnFileSE" });
@@ -525,13 +524,13 @@
// execute test
fsp.setFaultyMode(true);
// ignore file cause SecurityException
- try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
+ try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
String[] result = s.map(path -> path.getFileName().toString())
.toArray(String[]::new);
assertEqualsNoOrder(result, new String[] { "empty", "sample" });
}
// skip folder cause SecurityException
- try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
+ try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
String[] result = s.map(path -> path.getFileName().toString())
.toArray(String[]::new);
assertEqualsNoOrder(result, new String[] { "dir2", "file" });
@@ -539,14 +538,14 @@
if (supportsLinks) {
// not following links
- try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir"))) {
+ try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir"))) {
String[] result = s.map(path -> path.getFileName().toString())
.toArray(String[]::new);
assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "lnDirSE", "lnFileSE" });
}
// following links
- try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir"), FileVisitOption.FOLLOW_LINKS)) {
+ try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir"), FileVisitOption.FOLLOW_LINKS)) {
String[] result = s.map(path -> path.getFileName().toString())
.toArray(String[]::new);
// ?? Should fileInSE show up?
@@ -556,19 +555,19 @@
}
// list instead of walk
- try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
+ try (Stream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
String[] result = s.map(path -> path.getFileName().toString())
.toArray(String[]::new);
assertEqualsNoOrder(result, new String[] { "sample" });
}
- try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
+ try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
String[] result = s.map(path -> path.getFileName().toString())
.toArray(String[]::new);
assertEqualsNoOrder(result, new String[] { "file" });
}
// root cause SecurityException should be reported
- try (CloseableStream<Path> s = Files.walk(
+ try (Stream<Path> s = Files.walk(
fakeRoot.resolve("dir2").resolve("SecurityException")))
{
String[] result = s.map(path -> path.getFileName().toString())
@@ -579,7 +578,7 @@
}
// Walk a file cause SecurityException, we should get SE
- try (CloseableStream<Path> s = Files.walk(
+ try (Stream<Path> s = Files.walk(
fakeRoot.resolve("dir").resolve("SecurityException")))
{
String[] result = s.map(path -> path.getFileName().toString())
@@ -590,7 +589,7 @@
}
// List a file cause SecurityException, we should get SE as cannot read attribute
- try (CloseableStream<Path> s = Files.list(
+ try (Stream<Path> s = Files.list(
fakeRoot.resolve("dir2").resolve("SecurityException")))
{
String[] result = s.map(path -> path.getFileName().toString())
@@ -600,7 +599,7 @@
assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
}
- try (CloseableStream<Path> s = Files.list(
+ try (Stream<Path> s = Files.list(
fakeRoot.resolve("dir").resolve("SecurityException")))
{
String[] result = s.map(path -> path.getFileName().toString())
@@ -627,7 +626,7 @@
}
public void testConstructException() {
- try (CloseableStream<String> s = Files.lines(testFolder.resolve("notExist"), Charset.forName("UTF-8"))) {
+ try (Stream<String> s = Files.lines(testFolder.resolve("notExist"), Charset.forName("UTF-8"))) {
s.forEach(l -> fail("File is not even exist!"));
} catch (IOException ioe) {
assertTrue(ioe instanceof NoSuchFileException);
@@ -635,24 +634,26 @@
}
public void testClosedStream() throws IOException {
- try (CloseableStream<Path> s = Files.list(testFolder)) {
+ try (Stream<Path> s = Files.list(testFolder)) {
s.close();
- Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
- assertTrue(actual.length <= level1.length);
- }
-
- try (CloseableStream<Path> s = Files.walk(testFolder)) {
- s.close();
- Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
+ Object[] actual = s.sorted().toArray();
fail("Operate on closed stream should throw IllegalStateException");
} catch (IllegalStateException ex) {
// expected
}
- try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE,
+ try (Stream<Path> s = Files.walk(testFolder)) {
+ s.close();
+ Object[] actual = s.sorted().toArray();
+ fail("Operate on closed stream should throw IllegalStateException");
+ } catch (IllegalStateException ex) {
+ // expected
+ }
+
+ try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE,
(p, attr) -> true)) {
s.close();
- Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
+ Object[] actual = s.sorted().toArray();
fail("Operate on closed stream should throw IllegalStateException");
} catch (IllegalStateException ex) {
// expected
--- a/jdk/test/java/nio/file/WatchService/SensitivityModifier.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/nio/file/WatchService/SensitivityModifier.java Sat Sep 14 20:43:34 2013 +0100
@@ -100,7 +100,7 @@
}
key.reset();
key = watcher.poll(1, TimeUnit.SECONDS);
- } while (key != null && !eventReceived);
+ } while (key != null);
// we should have received at least one ENTRY_MODIFY event
if (eventReceived) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/security/cert/PKIXRevocationChecker/OcspUnauthorized.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8023362
+ * @summary Make sure Ocsp UNAUTHORIZED response is treated as failure when
+ * SOFT_FAIL option is set
+ */
+
+import java.io.ByteArrayInputStream;
+import java.security.cert.*;
+import java.security.cert.PKIXRevocationChecker.Option;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.EnumSet;
+
+public class OcspUnauthorized {
+
+ private final static String OCSP_RESPONSE = "MAMKAQY=";
+
+ private final static String EE_CERT =
+ "MIICADCCAWmgAwIBAgIEOvxUmjANBgkqhkiG9w0BAQQFADAqMQswCQYDVQQGEwJ1czE" +
+ "MMAoGA1UEChMDc3VuMQ0wCwYDVQQLEwRsYWJzMB4XDTAxMDUxNDIwNDQyMVoXDTI4MD" +
+ "kyOTIwNDQyMVowOTELMAkGA1UEBhMCdXMxDDAKBgNVBAoTA3N1bjENMAsGA1UECxMEb" +
+ "GFiczENMAsGA1UECxMEaXNyZzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4MmP" +
+ "GDriFJ+OhDlTuLpHzPy0nawDKyIYUJPZmU9M/pCAUbZewAOyAXGPYVU1og2ZiO9tWBi" +
+ "ZBeJGoFHEkkhfeqSVb2PsRckiXvPZ3AiSVmdX0uD/a963abmhRMYB1gDO2+jBe3F/DU" +
+ "pHwpyThchy8tYUMh7Gr7+m/8FwZbdbSpMCAwEAAaMkMCIwDwYDVR0PAQH/BAUDAwekA" +
+ "DAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBAUAA4GBAME3fmXvES0FVDXSD1iC" +
+ "TJLf86kUy3H+uMG7h5pOQmcfF1o9PVWlNByVf4r2b4GRgftPQ3Ao0SAvq1aSkW7YpkN" +
+ "pcartYqNk2E5brPajOC0v+Pkxf/g/pkRTT6Zp+9erGQF4Ta62q0iwOyc3FovSbh0Ph2" +
+ "WidZRP4qUG5I6JmGkI";
+
+ private final static String TRUST_ANCHOR =
+ "MIICIzCCAYygAwIBAgIEOvxT7DANBgkqhkiG9w0BAQQFADAbMQswCQYDVQQGEwJ1czE" +
+ "MMAoGA1UEChMDc3VuMB4XDTAxMDUxNDIxMDQyOVoXDTI4MDkyOTIxMDQyOVowKjELMA" +
+ "kGA1UEBhMCdXMxDDAKBgNVBAoTA3N1bjENMAsGA1UECxMEbGFiczCBnzANBgkqhkiG9" +
+ "w0BAQEFAAOBjQAwgYkCgYEA0/16V87rhznCM0y7IqyGcfQBentG+PglA+1hiqCuQY/A" +
+ "jFiDKr5N+LpcfU28P41E4M+DSDrMIEe4JchRcXeJY6aIVhpOveVV9mgtBaEKlsScrIJ" +
+ "zmVqM07PG9JENg2FibECnB5TNUSfVbFKfvtAqaZ7Pc971oZVoIePBWnfKV9kCAwEAAa" +
+ "NlMGMwPwYDVR0eAQH/BDUwM6AxMC+kKjELMAkGA1UEBhMCdXMxDDAKBgNVBAoTA3N1b" +
+ "jENMAsGA1UECxMEbGFic4ABAzAPBgNVHQ8BAf8EBQMDB6QAMA8GA1UdEwEB/wQFMAMB" +
+ "Af8wDQYJKoZIhvcNAQEEBQADgYEAfJ5HWd7K5PmX0+Vbsux4SYhoaejDwwgS43BRNa+" +
+ "AmFq9LIZ+ZcjBMVte8Y3sJF+nz9+1qBaUhNhbaECCqsgmWSwvI+0kUzJXL89k9AdQ8m" +
+ "AYf6CB6+kaZQBgrdSdqSGz3tCVa2MIK8wmb0ROM40oJ7vt3qSwgFi3UTltxkFfwQ0=";
+
+ private static CertificateFactory cf;
+ private static Base64.Decoder base64Decoder = Base64.getDecoder();
+
+ public static void main(String[] args) throws Exception {
+ cf = CertificateFactory.getInstance("X.509");
+ X509Certificate taCert = getX509Cert(TRUST_ANCHOR);
+ X509Certificate eeCert = getX509Cert(EE_CERT);
+ CertPath cp = cf.generateCertPath(Collections.singletonList(eeCert));
+
+ CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
+ PKIXRevocationChecker prc =
+ (PKIXRevocationChecker)cpv.getRevocationChecker();
+ prc.setOptions(EnumSet.of(Option.SOFT_FAIL, Option.NO_FALLBACK));
+ byte[] response = base64Decoder.decode(OCSP_RESPONSE);
+
+ prc.setOcspResponses(Collections.singletonMap(eeCert, response));
+
+ TrustAnchor ta = new TrustAnchor(taCert, null);
+ PKIXParameters params = new PKIXParameters(Collections.singleton(ta));
+
+ params.addCertPathChecker(prc);
+
+ try {
+ cpv.validate(cp, params);
+ throw new Exception("FAILED: expected CertPathValidatorException");
+ } catch (CertPathValidatorException cpve) {
+ cpve.printStackTrace();
+ }
+ }
+
+ private static X509Certificate getX509Cert(String enc) throws Exception {
+ byte[] bytes = base64Decoder.decode(enc);
+ ByteArrayInputStream is = new ByteArrayInputStream(bytes);
+ return (X509Certificate)cf.generateCertificate(is);
+ }
+}
--- a/jdk/test/java/time/tck/java/time/TCKLocalTime.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/time/tck/java/time/TCKLocalTime.java Sat Sep 14 20:43:34 2013 +0100
@@ -283,17 +283,6 @@
}
//-----------------------------------------------------------------------
- // now()
- //-----------------------------------------------------------------------
- @Test
- public void now() {
- LocalTime expected = LocalTime.now(Clock.systemDefaultZone());
- LocalTime test = LocalTime.now();
- long diff = Math.abs(test.toNanoOfDay() - expected.toNanoOfDay());
- assertTrue(diff < 100000000); // less than 0.1 secs
- }
-
- //-----------------------------------------------------------------------
// now(ZoneId)
//-----------------------------------------------------------------------
@Test(expectedExceptions=NullPointerException.class)
--- a/jdk/test/java/time/tck/java/time/chrono/TCKChronologySerialization.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/time/tck/java/time/chrono/TCKChronologySerialization.java Sat Sep 14 20:43:34 2013 +0100
@@ -97,7 +97,9 @@
ObjectOutputStream out = new ObjectOutputStream(baos);
out.writeObject(chrono);
out.close();
- ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+
+ byte[] bytes = baos.toByteArray();
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream in = new ObjectInputStream(bais);
@SuppressWarnings("unchecked")
--- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeTextPrinting.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeTextPrinting.java Sat Sep 14 20:43:34 2013 +0100
@@ -157,23 +157,6 @@
//-----------------------------------------------------------------------
@Test
- public void test_print_appendText2arg_french_long() throws Exception {
- DateTimeFormatter f = builder.appendText(MONTH_OF_YEAR, TextStyle.FULL).toFormatter(Locale.FRENCH);
- LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0);
- String text = f.format(dt);
- assertEquals(text, "janvier");
- }
-
- @Test
- public void test_print_appendText2arg_french_short() throws Exception {
- DateTimeFormatter f = builder.appendText(MONTH_OF_YEAR, TextStyle.SHORT).toFormatter(Locale.FRENCH);
- LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0);
- String text = f.format(dt);
- assertEquals(text, "janv.");
- }
-
- //-----------------------------------------------------------------------
- @Test
public void test_appendTextMap() throws Exception {
Map<Long, String> map = new HashMap<Long, String>();
map.put(1L, "JNY");
--- a/jdk/test/java/time/test/java/time/TestLocalTime.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/time/test/java/time/TestLocalTime.java Sat Sep 14 20:43:34 2013 +0100
@@ -61,7 +61,9 @@
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+import java.time.Clock;
import java.time.LocalTime;
import org.testng.annotations.Test;
@@ -71,6 +73,9 @@
*/
@Test
public class TestLocalTime extends AbstractTest {
+ static final long NANOS_PER_SECOND = 1_000_000_000L;
+ static final long NANOS_PER_MINUTE = 60 * NANOS_PER_SECOND;
+ static final long NANOS_PER_DAY = 24 * 60 * NANOS_PER_MINUTE;
//-----------------------------------------------------------------------
@Test
@@ -176,4 +181,31 @@
}
}
+ //-----------------------------------------------------------------------
+ // now()
+ //-----------------------------------------------------------------------
+ @Test
+ @SuppressWarnings("unused")
+ public void now() {
+ // Warmup the TimeZone data so the following test does not include
+ // one-time initialization
+ LocalTime.now(Clock.systemDefaultZone());
+
+ long diff = Integer.MAX_VALUE;
+ for (int i = 0; i < 2; i++) {
+ LocalTime expected = LocalTime.now(Clock.systemDefaultZone());
+ LocalTime test = LocalTime.now();
+ diff = test.toNanoOfDay() - expected.toNanoOfDay();
+ // Normalize for wrap-around midnight
+ diff = Math.floorMod(NANOS_PER_DAY + diff, NANOS_PER_DAY);
+ if (diff < 100000000) {
+ break;
+ }
+ // A second iteration may be needed if the clock changed
+ // due to a DST change between the two calls to now.
+ }
+ assertTrue(diff < 100000000, // less than 0.1 sec
+ "LocalTime.now vs LocalTime.now(Clock.systemDefaultZone()) not close");
+ }
+
}
--- a/jdk/test/java/util/Arrays/SetAllTest.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/Arrays/SetAllTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -167,13 +167,13 @@
public void testStringSetNulls() {
String[] ar = new String[2];
try {
- Arrays.setAll(null, i -> "X");
+ Arrays.setAll(null, (IntFunction<String>) i -> "X");
fail("Arrays.setAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
- Arrays.parallelSetAll(null, i -> "X");
+ Arrays.parallelSetAll(null, (IntFunction<String>) i -> "X");
fail("Arrays.parallelSetAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
--- a/jdk/test/java/util/Collection/CollectionDefaults.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/Collection/CollectionDefaults.java Sat Sep 14 20:43:34 2013 +0100
@@ -21,15 +21,19 @@
* questions.
*/
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
+import java.util.SortedSet;
+
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@@ -38,43 +42,68 @@
import java.util.TreeMap;
import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListMap;
import java.util.function.Predicate;
+import java.util.function.Supplier;
/**
* @test
+ * @summary Unit tests for extension methods on Collection
* @library testlibrary
- * @build CollectionAsserts CollectionSupplier
+ * @build CollectionAsserts CollectionSupplier ExtendsAbstractSet ExtendsAbstractCollection
* @run testng CollectionDefaults
- * @summary Unit tests for extension methods on Collection
*/
public class CollectionDefaults {
public static final Predicate<Integer> pEven = x -> 0 == x % 2;
public static final Predicate<Integer> pOdd = x -> 1 == x % 2;
- private static final String[] SET_CLASSES = {
- "java.util.HashSet",
- "java.util.LinkedHashSet",
- "java.util.TreeSet"
+ @SuppressWarnings("unchecked")
+ private static final Supplier<?>[] TEST_CLASSES = {
+ // Collection
+ ExtendsAbstractCollection<Integer>::new,
+
+ // Lists
+ java.util.ArrayList<Integer>::new,
+ java.util.LinkedList<Integer>::new,
+ java.util.Vector<Integer>::new,
+ java.util.concurrent.CopyOnWriteArrayList<Integer>::new,
+ ExtendsAbstractList<Integer>::new,
+
+ // Sets
+ java.util.HashSet<Integer>::new,
+ java.util.LinkedHashSet<Integer>::new,
+ java.util.TreeSet<Integer>::new,
+ java.util.concurrent.ConcurrentSkipListSet<Integer>::new,
+ java.util.concurrent.CopyOnWriteArraySet<Integer>::new,
+ ExtendsAbstractSet<Integer>::new
};
private static final int SIZE = 100;
@DataProvider(name="setProvider", parallel=true)
- public static Object[][] setCases() {
+ public static Iterator<Object[]> setCases() {
final List<Object[]> cases = new LinkedList<>();
cases.add(new Object[] { new HashSet<>() });
cases.add(new Object[] { new LinkedHashSet<>() });
cases.add(new Object[] { new TreeSet<>() });
+ cases.add(new Object[] { new java.util.concurrent.ConcurrentSkipListSet<>() });
+ cases.add(new Object[] { new java.util.concurrent.CopyOnWriteArraySet<>() });
+
+ cases.add(new Object[] { new ExtendsAbstractSet<>() });
cases.add(new Object[] { Collections.newSetFromMap(new HashMap<>()) });
cases.add(new Object[] { Collections.newSetFromMap(new LinkedHashMap()) });
cases.add(new Object[] { Collections.newSetFromMap(new TreeMap<>()) });
+ cases.add(new Object[] { Collections.newSetFromMap(new ConcurrentHashMap<>()) });
+ cases.add(new Object[] { Collections.newSetFromMap(new ConcurrentSkipListMap<>()) });
- cases.add(new Object[] { new HashSet(){{add(42);}} });
- cases.add(new Object[] { new LinkedHashSet(){{add(42);}} });
- cases.add(new Object[] { new TreeSet(){{add(42);}} });
- return cases.toArray(new Object[0][cases.size()]);
+ cases.add(new Object[] { new HashSet<Integer>(){{add(42);}} });
+ cases.add(new Object[] { new ExtendsAbstractSet<Integer>(){{add(42);}} });
+ cases.add(new Object[] { new LinkedHashSet<Integer>(){{add(42);}} });
+ cases.add(new Object[] { new TreeSet<Integer>(){{add(42);}} });
+ return cases.iterator();
}
@Test(dataProvider = "setProvider")
@@ -82,57 +111,66 @@
try {
set.forEach(null);
fail("expected NPE not thrown");
- } catch (NullPointerException npe) {}
+ } catch (NullPointerException expected) {
+ ; // expected
+ }
try {
set.removeIf(null);
fail("expected NPE not thrown");
- } catch (NullPointerException npe) {}
+ } catch (NullPointerException expected) {
+ ; // expected
+ }
}
@Test
public void testForEach() throws Exception {
- final CollectionSupplier supplier = new CollectionSupplier(SET_CLASSES, SIZE);
- for (final CollectionSupplier.TestCase test : supplier.get()) {
- final Set<Integer> original = ((Set<Integer>) test.original);
- final Set<Integer> set = ((Set<Integer>) test.collection);
+ final CollectionSupplier<Collection<Integer>> supplier = new CollectionSupplier((Supplier<Collection<Integer>>[]) TEST_CLASSES, SIZE);
+
+ for (final CollectionSupplier.TestCase<Collection<Integer>> test : supplier.get()) {
+ final Collection<Integer> original = test.expected;
+ final Collection<Integer> set = test.collection;
try {
set.forEach(null);
fail("expected NPE not thrown");
- } catch (NullPointerException npe) {}
- if (test.className.equals("java.util.HashSet")) {
- CollectionAsserts.assertContentsUnordered(set, original);
+ } catch (NullPointerException expected) {
+ ; // expected
+ }
+ if (set instanceof Set && !((set instanceof SortedSet) || (set instanceof LinkedHashSet))) {
+ CollectionAsserts.assertContentsUnordered(set, original, test.toString());
} else {
- CollectionAsserts.assertContents(set, original);
+ CollectionAsserts.assertContents(set, original, test.toString());
}
final List<Integer> actual = new LinkedList<>();
set.forEach(actual::add);
- if (test.className.equals("java.util.HashSet")) {
- CollectionAsserts.assertContentsUnordered(actual, set);
- CollectionAsserts.assertContentsUnordered(actual, original);
+ if (set instanceof Set && !((set instanceof SortedSet) || (set instanceof LinkedHashSet))) {
+ CollectionAsserts.assertContentsUnordered(actual, set, test.toString());
+ CollectionAsserts.assertContentsUnordered(actual, original, test.toString());
} else {
- CollectionAsserts.assertContents(actual, set);
- CollectionAsserts.assertContents(actual, original);
+ CollectionAsserts.assertContents(actual, set, test.toString());
+ CollectionAsserts.assertContents(actual, original, test.toString());
}
}
}
@Test
public void testRemoveIf() throws Exception {
- final CollectionSupplier supplier = new CollectionSupplier(SET_CLASSES, SIZE);
- for (final CollectionSupplier.TestCase test : supplier.get()) {
- final Set<Integer> original = ((Set<Integer>) test.original);
- final Set<Integer> set = ((Set<Integer>) test.collection);
+ final CollectionSupplier<Collection<Integer>> supplier = new CollectionSupplier((Supplier<Collection<Integer>>[]) TEST_CLASSES, SIZE);
+ for (final CollectionSupplier.TestCase<Collection<Integer>> test : supplier.get()) {
+ final Collection<Integer> original = test.expected;
+ final Collection<Integer> set = test.collection;
try {
set.removeIf(null);
fail("expected NPE not thrown");
- } catch (NullPointerException npe) {}
- if (test.className.equals("java.util.HashSet")) {
- CollectionAsserts.assertContentsUnordered(set, original);
+ } catch (NullPointerException expected) {
+ ; // expected
+ }
+ if (set instanceof Set && !((set instanceof SortedSet) || (set instanceof LinkedHashSet))) {
+ CollectionAsserts.assertContentsUnordered(set, original, test.toString());
} else {
- CollectionAsserts.assertContents(set, original);
+ CollectionAsserts.assertContents(set, original, test.toString());
}
set.removeIf(pEven);
--- a/jdk/test/java/util/Collection/ListDefaults.java Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,536 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.LinkedList;
-import java.util.Stack;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.Vector;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
-
-import java.lang.reflect.Constructor;
-import java.util.ConcurrentModificationException;
-import java.util.function.Predicate;
-
-/**
- * @test
- * @bug 8023367
- * @library testlibrary
- * @build CollectionAsserts CollectionSupplier
- * @run testng ListDefaults
- * @summary Unit tests for extension methods on List
- */
-public class ListDefaults {
-
- private static final String[] LIST_CLASSES = {
- "java.util.ArrayList",
- "java.util.LinkedList",
- "java.util.Vector",
- "java.util.concurrent.CopyOnWriteArrayList"
- };
-
- private static final String[] LIST_CME_CLASSES = {
- "java.util.ArrayList",
- "java.util.Vector"
- };
-
- private static final Predicate<Integer> pEven = x -> 0 == x % 2;
- private static final Predicate<Integer> pOdd = x -> 1 == x % 2;
-
- private static final Comparator<Integer> BIT_COUNT_COMPARATOR =
- (x, y) -> Integer.bitCount(x) - Integer.bitCount(y);
-
- private static final Comparator<AtomicInteger> ATOMIC_INTEGER_COMPARATOR =
- (x, y) -> x.intValue() - y.intValue();
-
- private static final int SIZE = 100;
- private static final int SUBLIST_FROM = 20;
- private static final int SUBLIST_TO = SIZE - 5;
- private static final int SUBLIST_SIZE = SUBLIST_TO - SUBLIST_FROM;
-
- private static interface Callback {
- void call(List<Integer> list);
- }
-
- // call the callback for each recursive subList
- private void trimmedSubList(final List<Integer> list, final Callback callback) {
- int size = list.size();
- if (size > 1) {
- // trim 1 element from both ends
- final List<Integer> subList = list.subList(1, size - 1);
- callback.call(subList);
- trimmedSubList(subList, callback);
- }
- }
-
- @DataProvider(name="listProvider", parallel=true)
- public static Object[][] listCases() {
- final List<Object[]> cases = new LinkedList<>();
- cases.add(new Object[] { Collections.emptyList() });
- cases.add(new Object[] { new ArrayList<>() });
- cases.add(new Object[] { new LinkedList<>() });
- cases.add(new Object[] { new Vector<>() });
- cases.add(new Object[] { new Stack<>() });
- cases.add(new Object[] { new CopyOnWriteArrayList<>() });
-
- cases.add(new Object[] { new ArrayList(){{add(42);}} });
- cases.add(new Object[] { new LinkedList(){{add(42);}} });
- cases.add(new Object[] { new Vector(){{add(42);}} });
- cases.add(new Object[] { new Stack(){{add(42);}} });
- cases.add(new Object[] { new CopyOnWriteArrayList(){{add(42);}} });
- return cases.toArray(new Object[0][cases.size()]);
- }
-
- @Test(dataProvider = "listProvider")
- public void testProvidedWithNull(final List<Integer> list) throws Exception {
- try {
- list.forEach(null);
- fail("expected NPE not thrown");
- } catch (NullPointerException npe) {}
- try {
- list.replaceAll(null);
- fail("expected NPE not thrown");
- } catch (NullPointerException npe) {}
- try {
- list.removeIf(null);
- fail("expected NPE not thrown");
- } catch (NullPointerException npe) {}
- try {
- list.sort(null);
- } catch (Throwable t) {
- fail("Exception not expected: " + t);
- }
- }
-
- @Test
- public void testForEach() throws Exception {
- final CollectionSupplier supplier = new CollectionSupplier(LIST_CLASSES, SIZE);
- for (final CollectionSupplier.TestCase test : supplier.get()) {
- final List<Integer> original = ((List<Integer>) test.original);
- final List<Integer> list = ((List<Integer>) test.collection);
- }
- for (final CollectionSupplier.TestCase test : supplier.get()) {
- final List<Integer> original = ((List<Integer>) test.original);
- final List<Integer> list = ((List<Integer>) test.collection);
-
- try {
- list.forEach(null);
- fail("expected NPE not thrown");
- } catch (NullPointerException npe) {}
- CollectionAsserts.assertContents(list, original);
-
- final List<Integer> actual = new LinkedList<>();
- list.forEach(actual::add);
- CollectionAsserts.assertContents(actual, list);
- CollectionAsserts.assertContents(actual, original);
-
- if (original.size() > SUBLIST_SIZE) {
- final List<Integer> subList = original.subList(SUBLIST_FROM, SUBLIST_TO);
- final List<Integer> actualSubList = new LinkedList<>();
- subList.forEach(actualSubList::add);
- assertEquals(actualSubList.size(), SUBLIST_SIZE);
- for (int i = 0; i < SUBLIST_SIZE; i++) {
- assertEquals(actualSubList.get(i), original.get(i + SUBLIST_FROM));
- }
- }
-
- trimmedSubList(list, new Callback() {
- @Override
- public void call(final List<Integer> list) {
- final List<Integer> actual = new LinkedList<>();
- list.forEach(actual::add);
- CollectionAsserts.assertContents(actual, list);
- }
- });
- }
- }
-
- @Test
- public void testRemoveIf() throws Exception {
- final CollectionSupplier supplier = new CollectionSupplier(LIST_CLASSES, SIZE);
-
- for (final CollectionSupplier.TestCase test : supplier.get()) {
- final List<Integer> original = ((List<Integer>) test.original);
- final List<Integer> list = ((List<Integer>) test.collection);
-
- try {
- list.removeIf(null);
- fail("expected NPE not thrown");
- } catch (NullPointerException npe) {}
- CollectionAsserts.assertContents(list, original);
-
- final AtomicInteger offset = new AtomicInteger(1);
- while (list.size() > 0) {
- removeFirst(original, list, offset);
- }
- }
-
- for (final CollectionSupplier.TestCase test : supplier.get()) {
- final List<Integer> original = ((List<Integer>) test.original);
- final List<Integer> list = ((List<Integer>) test.collection);
- list.removeIf(pOdd);
- for (int i : list) {
- assertTrue((i % 2) == 0);
- }
- for (int i : original) {
- if (i % 2 == 0) {
- assertTrue(list.contains(i));
- }
- }
- list.removeIf(pEven);
- assertTrue(list.isEmpty());
- }
-
- for (final CollectionSupplier.TestCase test : supplier.get()) {
- final List<Integer> original = ((List<Integer>) test.original);
- final List<Integer> list = ((List<Integer>) test.collection);
- final List<Integer> listCopy = new ArrayList<>(list);
- if (original.size() > SUBLIST_SIZE) {
- final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
- final List<Integer> subListCopy = new ArrayList<>(subList);
- listCopy.removeAll(subList);
- subList.removeIf(pOdd);
- for (int i : subList) {
- assertTrue((i % 2) == 0);
- }
- for (int i : subListCopy) {
- if (i % 2 == 0) {
- assertTrue(subList.contains(i));
- } else {
- assertFalse(subList.contains(i));
- }
- }
- subList.removeIf(pEven);
- assertTrue(subList.isEmpty());
- // elements outside the view should remain
- CollectionAsserts.assertContents(list, listCopy);
- }
- }
-
- for (final CollectionSupplier.TestCase test : supplier.get()) {
- final List<Integer> list = ((List<Integer>) test.collection);
- trimmedSubList(list, new Callback() {
- @Override
- public void call(final List<Integer> list) {
- final List<Integer> copy = new ArrayList<>(list);
- list.removeIf(pOdd);
- for (int i : list) {
- assertTrue((i % 2) == 0);
- }
- for (int i : copy) {
- if (i % 2 == 0) {
- assertTrue(list.contains(i));
- } else {
- assertFalse(list.contains(i));
- }
- }
- }
- });
- }
- }
-
- // remove the first element
- private void removeFirst(final List<Integer> original, final List<Integer> list, final AtomicInteger offset) {
- final AtomicBoolean first = new AtomicBoolean(true);
- list.removeIf(x -> first.getAndSet(false));
- CollectionAsserts.assertContents(original.subList(offset.getAndIncrement(), original.size()), list);
- }
-
- @Test
- public void testReplaceAll() throws Exception {
- final int scale = 3;
- final CollectionSupplier supplier = new CollectionSupplier(LIST_CLASSES, SIZE);
- for (final CollectionSupplier.TestCase test : supplier.get()) {
- final List<Integer> original = ((List<Integer>) test.original);
- final List<Integer> list = ((List<Integer>) test.collection);
-
- try {
- list.replaceAll(null);
- fail("expected NPE not thrown");
- } catch (NullPointerException npe) {}
- CollectionAsserts.assertContents(list, original);
-
- list.replaceAll(x -> scale * x);
- for (int i=0; i < original.size(); i++) {
- assertTrue(list.get(i) == (scale * original.get(i)), "mismatch at index " + i);
- }
-
- if (original.size() > SUBLIST_SIZE) {
- final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
- subList.replaceAll(x -> x + 1);
- // verify elements in view [from, to) were replaced
- for (int i = 0; i < SUBLIST_SIZE; i++) {
- assertTrue(subList.get(i) == ((scale * original.get(i + SUBLIST_FROM)) + 1),
- "mismatch at sublist index " + i);
- }
- // verify that elements [0, from) remain unmodified
- for (int i = 0; i < SUBLIST_FROM; i++) {
- assertTrue(list.get(i) == (scale * original.get(i)),
- "mismatch at original index " + i);
- }
- // verify that elements [to, size) remain unmodified
- for (int i = SUBLIST_TO; i < list.size(); i++) {
- assertTrue(list.get(i) == (scale * original.get(i)),
- "mismatch at original index " + i);
- }
- }
- }
-
- for (final CollectionSupplier.TestCase test : supplier.get()) {
- final List<Integer> list = ((List<Integer>) test.collection);
- trimmedSubList(list, new Callback() {
- @Override
- public void call(final List<Integer> list) {
- final List<Integer> copy = new ArrayList<>(list);
- final int offset = 5;
- list.replaceAll(x -> offset + x);
- for (int i=0; i < copy.size(); i++) {
- assertTrue(list.get(i) == (offset + copy.get(i)), "mismatch at index " + i);
- }
- }
- });
- }
- }
-
- @Test
- public void testSort() throws Exception {
- final CollectionSupplier supplier = new CollectionSupplier(LIST_CLASSES, SIZE);
- for (final CollectionSupplier.TestCase test : supplier.get()) {
- final List<Integer> original = ((List<Integer>) test.original);
- final List<Integer> list = ((List<Integer>) test.collection);
- CollectionSupplier.shuffle(list);
- list.sort(Integer::compare);
- CollectionAsserts.assertSorted(list, Integer::compare);
- if (test.name.startsWith("reverse")) {
- Collections.reverse(list);
- }
- CollectionAsserts.assertContents(list, original);
-
- CollectionSupplier.shuffle(list);
- list.sort(null);
- CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder());
- if (test.name.startsWith("reverse")) {
- Collections.reverse(list);
- }
- CollectionAsserts.assertContents(list, original);
-
- CollectionSupplier.shuffle(list);
- list.sort(Comparator.<Integer>naturalOrder());
- CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder());
- if (test.name.startsWith("reverse")) {
- Collections.reverse(list);
- }
- CollectionAsserts.assertContents(list, original);
-
- CollectionSupplier.shuffle(list);
- list.sort(Comparator.<Integer>reverseOrder());
- CollectionAsserts.assertSorted(list, Comparator.<Integer>reverseOrder());
- if (!test.name.startsWith("reverse")) {
- Collections.reverse(list);
- }
- CollectionAsserts.assertContents(list, original);
-
- CollectionSupplier.shuffle(list);
- list.sort(BIT_COUNT_COMPARATOR);
- CollectionAsserts.assertSorted(list, BIT_COUNT_COMPARATOR);
- // check sort by verifying that bitCount increases and never drops
- int minBitCount = 0;
- int bitCount = 0;
- for (final Integer i : list) {
- bitCount = Integer.bitCount(i);
- assertTrue(bitCount >= minBitCount);
- minBitCount = bitCount;
- }
-
- @SuppressWarnings("unchecked")
- final Class<? extends List<AtomicInteger>> type =
- (Class<? extends List<AtomicInteger>>) Class.forName(test.className);
- final Constructor<? extends List<AtomicInteger>> defaultConstructor = type.getConstructor();
- final List<AtomicInteger> incomparables = (List<AtomicInteger>) defaultConstructor.newInstance();
-
- for (int i=0; i < test.original.size(); i++) {
- incomparables.add(new AtomicInteger(i));
- }
- CollectionSupplier.shuffle(incomparables);
- incomparables.sort(ATOMIC_INTEGER_COMPARATOR);
- for (int i=0; i < test.original.size(); i++) {
- assertEquals(i, incomparables.get(i).intValue());
- }
-
- if (original.size() > SUBLIST_SIZE) {
- final List<Integer> copy = new ArrayList<>(list);
- final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
- CollectionSupplier.shuffle(subList);
- subList.sort(Comparator.<Integer>naturalOrder());
- CollectionAsserts.assertSorted(subList, Comparator.<Integer>naturalOrder());
- // verify that elements [0, from) remain unmodified
- for (int i = 0; i < SUBLIST_FROM; i++) {
- assertTrue(list.get(i) == copy.get(i),
- "mismatch at index " + i);
- }
- // verify that elements [to, size) remain unmodified
- for (int i = SUBLIST_TO; i < list.size(); i++) {
- assertTrue(list.get(i) == copy.get(i),
- "mismatch at index " + i);
- }
- }
- }
-
- for (final CollectionSupplier.TestCase test : supplier.get()) {
- final List<Integer> list = ((List<Integer>) test.collection);
- trimmedSubList(list, new Callback() {
- @Override
- public void call(final List<Integer> list) {
- final List<Integer> copy = new ArrayList<>(list);
- CollectionSupplier.shuffle(list);
- list.sort(Comparator.<Integer>naturalOrder());
- CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder());
- }
- });
- }
- }
-
- @Test
- public void testForEachThrowsCME() throws Exception {
- final CollectionSupplier supplier = new CollectionSupplier(LIST_CME_CLASSES, SIZE);
- for (final CollectionSupplier.TestCase test : supplier.get()) {
- final List<Integer> list = ((List<Integer>) test.collection);
- if (list.size() <= 1) {
- continue;
- }
- boolean gotException = false;
- try {
- // bad predicate that modifies its list, should throw CME
- list.forEach((x) -> {list.add(x);});
- } catch (ConcurrentModificationException cme) {
- gotException = true;
- }
- if (!gotException) {
- fail("expected CME was not thrown from " + test);
- }
- }
- }
-
- @Test
- public void testRemoveIfThrowsCME() throws Exception {
- final CollectionSupplier supplier = new CollectionSupplier(LIST_CME_CLASSES, SIZE);
- for (final CollectionSupplier.TestCase test : supplier.get()) {
- final List<Integer> list = ((List<Integer>) test.collection);
- if (list.size() <= 1) {
- continue;
- }
- boolean gotException = false;
- try {
- // bad predicate that modifies its list, should throw CME
- list.removeIf((x) -> {return list.add(x);});
- } catch (ConcurrentModificationException cme) {
- gotException = true;
- }
- if (!gotException) {
- fail("expected CME was not thrown from " + test);
- }
- }
- }
-
- @Test
- public void testReplaceAllThrowsCME() throws Exception {
- final CollectionSupplier supplier = new CollectionSupplier(LIST_CME_CLASSES, SIZE);
- for (final CollectionSupplier.TestCase test : supplier.get()) {
- final List<Integer> list = ((List<Integer>) test.collection);
- if (list.size() <= 1) {
- continue;
- }
- boolean gotException = false;
- try {
- // bad predicate that modifies its list, should throw CME
- list.replaceAll(x -> {int n = 3 * x; list.add(n); return n;});
- } catch (ConcurrentModificationException cme) {
- gotException = true;
- }
- if (!gotException) {
- fail("expected CME was not thrown from " + test);
- }
- }
- }
-
- @Test
- public void testSortThrowsCME() throws Exception {
- final CollectionSupplier supplier = new CollectionSupplier(LIST_CME_CLASSES, SIZE);
- for (final CollectionSupplier.TestCase test : supplier.get()) {
- final List<Integer> list = ((List<Integer>) test.collection);
- if (list.size() <= 1) {
- continue;
- }
- boolean gotException = false;
- try {
- // bad predicate that modifies its list, should throw CME
- list.sort((x, y) -> {list.add(x); return x - y;});
- } catch (ConcurrentModificationException cme) {
- gotException = true;
- }
- if (!gotException) {
- fail("expected CME was not thrown from " + test);
- }
- }
- }
-
- private static final List<Integer> SLICED_EXPECTED = Arrays.asList(0, 1, 2, 3, 5, 6, 7, 8, 9);
- private static final List<Integer> SLICED_EXPECTED2 = Arrays.asList(0, 1, 2, 5, 6, 7, 8, 9);
-
- @DataProvider(name="shortIntListProvider", parallel=true)
- public static Object[][] intListCases() {
- final Integer[] DATA = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- final List<Object[]> cases = new LinkedList<>();
- cases.add(new Object[] { new ArrayList<>(Arrays.asList(DATA)) });
- cases.add(new Object[] { new LinkedList<>(Arrays.asList(DATA)) });
- cases.add(new Object[] { new Vector<>(Arrays.asList(DATA)) });
- cases.add(new Object[] { new CopyOnWriteArrayList<>(Arrays.asList(DATA)) });
- return cases.toArray(new Object[0][cases.size()]);
- }
-
- @Test(dataProvider = "shortIntListProvider")
- public void testRemoveIfFromSlice(final List<Integer> list) throws Exception {
- final List<Integer> sublist = list.subList(3, 6);
- assertTrue(sublist.removeIf(x -> x == 4));
- CollectionAsserts.assertContents(list, SLICED_EXPECTED);
-
- final List<Integer> sublist2 = list.subList(2, 5);
- assertTrue(sublist2.removeIf(x -> x == 3));
- CollectionAsserts.assertContents(list, SLICED_EXPECTED2);
- }
-}
--- a/jdk/test/java/util/Collection/MOAT.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/Collection/MOAT.java Sat Sep 14 20:43:34 2013 +0100
@@ -400,8 +400,6 @@
// If add(null) succeeds, contains(null) & remove(null) should succeed
//----------------------------------------------------------------
private static void testNullElement(Collection<Integer> c) {
- // !!!! 5018849: (coll) TreeSet.contains(null) does not agree with Javadoc
- if (c instanceof TreeSet) return;
try {
check(c.add(null));
--- a/jdk/test/java/util/Collection/testlibrary/CollectionAsserts.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/Collection/testlibrary/CollectionAsserts.java Sat Sep 14 20:43:34 2013 +0100
@@ -41,6 +41,10 @@
*/
public class CollectionAsserts {
+ private CollectionAsserts() {
+ // no instances
+ }
+
public static void assertCountSum(Iterable<? super Integer> it, int count, int sum) {
assertCountSum(it.iterator(), count, sum);
}
@@ -117,10 +121,18 @@
}
public static<T> void assertContents(Iterable<T> actual, Iterable<T> expected) {
- assertContents(actual.iterator(), expected.iterator());
+ assertContents(actual, expected, null);
+ }
+
+ public static<T> void assertContents(Iterable<T> actual, Iterable<T> expected, String msg) {
+ assertContents(actual.iterator(), expected.iterator(), msg);
}
public static<T> void assertContents(Iterator<T> actual, Iterator<T> expected) {
+ assertContents(actual, expected, null);
+ }
+
+ public static<T> void assertContents(Iterator<T> actual, Iterator<T> expected, String msg) {
List<T> history = new ArrayList<>();
while (expected.hasNext()) {
@@ -128,20 +140,23 @@
List<T> expectedData = new ArrayList<>(history);
while (expected.hasNext())
expectedData.add(expected.next());
- fail(String.format("Premature end of data; expected=%s, found=%s", expectedData, history));
+ fail(String.format("%s Premature end of data; expected=%s, found=%s",
+ (msg == null ? "" : msg), expectedData, history));
}
T a = actual.next();
T e = expected.next();
history.add(a);
if (!Objects.equals(a, e))
- fail(String.format("Data mismatch; preceding=%s, nextExpected=%s, nextFound=%s", history, e, a));
+ fail(String.format("%s Data mismatch; preceding=%s, nextExpected=%s, nextFound=%s",
+ (msg == null ? "" : msg), history, e, a));
}
if (actual.hasNext()) {
List<T> rest = new ArrayList<>();
while (actual.hasNext())
rest.add(actual.next());
- fail(String.format("Unexpected data %s after %s", rest, history));
+ fail(String.format("%s Unexpected data %s after %s",
+ (msg == null ? "" : msg), rest, history));
}
}
@@ -151,30 +166,21 @@
assertContents(actual, Arrays.asList(expected).iterator());
}
- public static <T> boolean equalsContentsUnordered(Iterable<T> a, Iterable<T> b) {
- Set<T> sa = new HashSet<>();
- for (T t : a) {
- sa.add(t);
- }
+ public static<T extends Comparable<? super T>> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected) {
+ assertContentsUnordered(actual, expected, null);
+ }
- Set<T> sb = new HashSet<>();
- for (T t : b) {
- sb.add(t);
+ public static<T extends Comparable<? super T>> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected, String msg) {
+ List<T> allExpected = new ArrayList<>();
+ for (T t : expected) {
+ allExpected.add(t);
}
- return Objects.equals(sa, sb);
- }
+ for (T t : actual) {
+ assertTrue(allExpected.remove(t), msg + " element '" + String.valueOf(t) + "' not found");
+ }
- public static<T extends Comparable<? super T>> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected) {
- ArrayList<T> one = new ArrayList<>();
- for (T t : actual)
- one.add(t);
- ArrayList<T> two = new ArrayList<>();
- for (T t : expected)
- two.add(t);
- Collections.sort(one);
- Collections.sort(two);
- assertContents(one, two);
+ assertTrue(allExpected.isEmpty(), msg + "expected contained additional elements");
}
static <T> void assertSplitContents(Iterable<Iterable<T>> splits, Iterable<T> list) {
--- a/jdk/test/java/util/Collection/testlibrary/CollectionSupplier.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/Collection/testlibrary/CollectionSupplier.java Sat Sep 14 20:43:34 2013 +0100
@@ -29,13 +29,11 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
-import java.util.Set;
import org.testng.TestException;
import static org.testng.Assert.assertTrue;
-import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.Collections;
import java.util.function.Supplier;
@@ -44,15 +42,15 @@
* @library
* @summary A Supplier of test cases for Collection tests
*/
-public final class CollectionSupplier implements Supplier<Iterable<CollectionSupplier.TestCase>> {
+public final class CollectionSupplier<C extends Collection<Integer>> implements Supplier<Iterable<CollectionSupplier.TestCase<C>>> {
- private final String[] classNames;
+ private final Supplier<C>[] classes;
private final int size;
/**
* A Collection test case.
*/
- public static final class TestCase {
+ public static final class TestCase<C extends Collection<Integer>> {
/**
* The name of the test case.
@@ -60,57 +58,45 @@
public final String name;
/**
- * Class name of the instantiated Collection.
- */
- public final String className;
-
- /**
* Unmodifiable reference collection, useful for comparisons.
*/
- public final Collection<Integer> original;
+ public final List<Integer> expected;
/**
* A modifiable test collection.
*/
- public final Collection<Integer> collection;
+ public final C collection;
/**
* Create a Collection test case.
+ *
* @param name name of the test case
- * @param className class name of the instantiated collection
- * @param original reference collection
+ * @param expected reference collection
* @param collection the modifiable test collection
*/
- public TestCase(String name, String className,
- Collection<Integer> original, Collection<Integer> collection) {
+ public TestCase(String name, C collection) {
this.name = name;
- this.className = className;
- this.original =
- List.class.isAssignableFrom(original.getClass()) ?
- Collections.unmodifiableList((List<Integer>) original) :
- Set.class.isAssignableFrom(original.getClass()) ?
- Collections.unmodifiableSet((Set<Integer>) original) :
- Collections.unmodifiableCollection(original);
+ this.expected = Collections.unmodifiableList(
+ Arrays.asList(collection.toArray(new Integer[0])));
this.collection = collection;
}
@Override
public String toString() {
- return name + " " + className +
- "\n original: " + original +
- "\n target: " + collection;
+ return name + " " + collection.getClass().toString();
}
}
/**
* Shuffle a list using a PRNG with known seed for repeatability
+ *
* @param list the list to be shuffled
*/
public static <E> void shuffle(final List<E> list) {
// PRNG with known seed for repeatable tests
final Random prng = new Random(13);
final int size = list.size();
- for (int i=0; i < size; i++) {
+ for (int i = 0; i < size; i++) {
// random index in interval [i, size)
final int j = i + prng.nextInt(size - i);
// swap elements at indices i & j
@@ -127,178 +113,133 @@
* @param classNames class names that implement {@code Collection}
* @param size the desired size of each collection
*/
- public CollectionSupplier(String[] classNames, int size) {
- this.classNames = Arrays.copyOf(classNames, classNames.length);
+ public CollectionSupplier(Supplier<C>[] classes, int size) {
+ this.classes = Arrays.copyOf(classes, classes.length);
this.size = size;
}
@Override
- public Iterable<TestCase> get() {
- try {
- return getThrows();
- } catch (Exception e) {
- throw new TestException(e);
- }
- }
+ public Iterable<TestCase<C>> get() {
+ final Collection<TestCase<C>> cases = new LinkedList<>();
+ for (final Supplier<C> type : classes) {
+ try {
+ final Collection<Integer> empty = type.get();
+ cases.add(new TestCase("empty", empty));
- private Iterable<TestCase> getThrows() throws Exception {
- final Collection<TestCase> collections = new LinkedList<>();
- for (final String className : classNames) {
- @SuppressWarnings("unchecked")
- final Class<? extends Collection<Integer>> type =
- (Class<? extends Collection<Integer>>) Class.forName(className);
- final Constructor<? extends Collection<Integer>>
- defaultConstructor = type.getConstructor();
- final Constructor<? extends Collection<Integer>>
- copyConstructor = type.getConstructor(Collection.class);
+ final Collection<Integer> single = type.get();
+ single.add(42);
+ cases.add(new TestCase("single", single));
- final Collection<Integer> empty = defaultConstructor.newInstance();
- collections.add(new TestCase("empty",
- className,
- copyConstructor.newInstance(empty),
- empty));
+ final Collection<Integer> regular = type.get();
+ for (int i = 0; i < size; i++) {
+ regular.add(i);
+ }
+ cases.add(new TestCase("regular", regular));
- final Collection<Integer> single = defaultConstructor.newInstance();
- single.add(42);
- collections.add(new TestCase("single",
- className,
- copyConstructor.newInstance(single),
- single));
-
- final Collection<Integer> regular = defaultConstructor.newInstance();
- for (int i=0; i < size; i++) {
- regular.add(i);
- }
- collections.add(new TestCase("regular",
- className,
- copyConstructor.newInstance(regular),
- regular));
+ final Collection<Integer> reverse = type.get();
+ for (int i = size; i >= 0; i--) {
+ reverse.add(i);
+ }
+ cases.add(new TestCase("reverse", reverse));
- final Collection<Integer> reverse = defaultConstructor.newInstance();
- for (int i=size; i >= 0; i--) {
- reverse.add(i);
- }
- collections.add(new TestCase("reverse",
- className,
- copyConstructor.newInstance(reverse),
- reverse));
+ final Collection<Integer> odds = type.get();
+ for (int i = 0; i < size; i++) {
+ odds.add((i * 2) + 1);
+ }
+ cases.add(new TestCase("odds", odds));
- final Collection<Integer> odds = defaultConstructor.newInstance();
- for (int i=0; i < size; i++) {
- odds.add((i * 2) + 1);
- }
- collections.add(new TestCase("odds",
- className,
- copyConstructor.newInstance(odds),
- odds));
+ final Collection<Integer> evens = type.get();
+ for (int i = 0; i < size; i++) {
+ evens.add(i * 2);
+ }
+ cases.add(new TestCase("evens", evens));
- final Collection<Integer> evens = defaultConstructor.newInstance();
- for (int i=0; i < size; i++) {
- evens.add(i * 2);
- }
- collections.add(new TestCase("evens",
- className,
- copyConstructor.newInstance(evens),
- evens));
-
- final Collection<Integer> fibonacci = defaultConstructor.newInstance();
- int prev2 = 0;
- int prev1 = 1;
- for (int i=0; i < size; i++) {
- final int n = prev1 + prev2;
- if (n < 0) { // stop on overflow
- break;
+ final Collection<Integer> fibonacci = type.get();
+ int prev2 = 0;
+ int prev1 = 1;
+ for (int i = 0; i < size; i++) {
+ final int n = prev1 + prev2;
+ if (n < 0) { // stop on overflow
+ break;
+ }
+ fibonacci.add(n);
+ prev2 = prev1;
+ prev1 = n;
}
- fibonacci.add(n);
- prev2 = prev1;
- prev1 = n;
- }
- collections.add(new TestCase("fibonacci",
- className,
- copyConstructor.newInstance(fibonacci),
- fibonacci));
+ cases.add(new TestCase("fibonacci", fibonacci));
// variants where the size of the backing storage != reported size
- // created by removing half of the elements
+ // created by removing half of the elements
+ final Collection<Integer> emptyWithSlack = type.get();
+ emptyWithSlack.add(42);
+ assertTrue(emptyWithSlack.remove(42));
+ cases.add(new TestCase("emptyWithSlack", emptyWithSlack));
- final Collection<Integer> emptyWithSlack = defaultConstructor.newInstance();
- emptyWithSlack.add(42);
- assertTrue(emptyWithSlack.remove(42));
- collections.add(new TestCase("emptyWithSlack",
- className,
- copyConstructor.newInstance(emptyWithSlack),
- emptyWithSlack));
-
- final Collection<Integer> singleWithSlack = defaultConstructor.newInstance();
- singleWithSlack.add(42);
- singleWithSlack.add(43);
- assertTrue(singleWithSlack.remove(43));
- collections.add(new TestCase("singleWithSlack",
- className,
- copyConstructor.newInstance(singleWithSlack),
- singleWithSlack));
+ final Collection<Integer> singleWithSlack = type.get();
+ singleWithSlack.add(42);
+ singleWithSlack.add(43);
+ assertTrue(singleWithSlack.remove(43));
+ cases.add(new TestCase("singleWithSlack", singleWithSlack));
- final Collection<Integer> regularWithSlack = defaultConstructor.newInstance();
- for (int i=0; i < (2 * size); i++) {
- regularWithSlack.add(i);
- }
- assertTrue(regularWithSlack.removeIf((x) -> {return x >= size;}));
- collections.add(new TestCase("regularWithSlack",
- className,
- copyConstructor.newInstance(regularWithSlack),
- regularWithSlack));
+ final Collection<Integer> regularWithSlack = type.get();
+ for (int i = 0; i < (2 * size); i++) {
+ regularWithSlack.add(i);
+ }
+ assertTrue(regularWithSlack.removeIf((x) -> {
+ return x >= size;
+ }));
+ cases.add(new TestCase("regularWithSlack", regularWithSlack));
- final Collection<Integer> reverseWithSlack = defaultConstructor.newInstance();
- for (int i=2 * size; i >= 0; i--) {
- reverseWithSlack.add(i);
- }
- assertTrue(reverseWithSlack.removeIf((x) -> {return x < size;}));
- collections.add(new TestCase("reverseWithSlack",
- className,
- copyConstructor.newInstance(reverseWithSlack),
- reverseWithSlack));
+ final Collection<Integer> reverseWithSlack = type.get();
+ for (int i = 2 * size; i >= 0; i--) {
+ reverseWithSlack.add(i);
+ }
+ assertTrue(reverseWithSlack.removeIf((x) -> {
+ return x < size;
+ }));
+ cases.add(new TestCase("reverseWithSlack", reverseWithSlack));
- final Collection<Integer> oddsWithSlack = defaultConstructor.newInstance();
- for (int i = 0; i < 2 * size; i++) {
- oddsWithSlack.add((i * 2) + 1);
- }
- assertTrue(oddsWithSlack.removeIf((x) -> {return x >= size;}));
- collections.add(new TestCase("oddsWithSlack",
- className,
- copyConstructor.newInstance(oddsWithSlack),
- oddsWithSlack));
+ final Collection<Integer> oddsWithSlack = type.get();
+ for (int i = 0; i < 2 * size; i++) {
+ oddsWithSlack.add((i * 2) + 1);
+ }
+ assertTrue(oddsWithSlack.removeIf((x) -> {
+ return x >= size;
+ }));
+ cases.add(new TestCase("oddsWithSlack", oddsWithSlack));
+
+ final Collection<Integer> evensWithSlack = type.get();
+ for (int i = 0; i < 2 * size; i++) {
+ evensWithSlack.add(i * 2);
+ }
+ assertTrue(evensWithSlack.removeIf((x) -> {
+ return x >= size;
+ }));
+ cases.add(new TestCase("evensWithSlack", evensWithSlack));
- final Collection<Integer> evensWithSlack = defaultConstructor.newInstance();
- for (int i = 0; i < 2 * size; i++) {
- evensWithSlack.add(i * 2);
+ final Collection<Integer> fibonacciWithSlack = type.get();
+ prev2 = 0;
+ prev1 = 1;
+ for (int i = 0; i < size; i++) {
+ final int n = prev1 + prev2;
+ if (n < 0) { // stop on overflow
+ break;
+ }
+ fibonacciWithSlack.add(n);
+ prev2 = prev1;
+ prev1 = n;
+ }
+ assertTrue(fibonacciWithSlack.removeIf((x) -> {
+ return x < 20;
+ }));
+ cases.add(new TestCase("fibonacciWithSlack",
+ fibonacciWithSlack));
+ } catch (Exception failed) {
+ throw new TestException(failed);
}
- assertTrue(evensWithSlack.removeIf((x) -> {return x >= size;}));
- collections.add(new TestCase("evensWithSlack",
- className,
- copyConstructor.newInstance(evensWithSlack),
- evensWithSlack));
-
- final Collection<Integer> fibonacciWithSlack = defaultConstructor.newInstance();
- prev2 = 0;
- prev1 = 1;
- for (int i=0; i < size; i++) {
- final int n = prev1 + prev2;
- if (n < 0) { // stop on overflow
- break;
- }
- fibonacciWithSlack.add(n);
- prev2 = prev1;
- prev1 = n;
- }
- assertTrue(fibonacciWithSlack.removeIf((x) -> {return x < 20;}));
- collections.add(new TestCase("fibonacciWithSlack",
- className,
- copyConstructor.newInstance(fibonacciWithSlack),
- fibonacciWithSlack));
-
}
- return collections;
+ return cases;
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Collection/testlibrary/ExtendsAbstractCollection.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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.AbstractCollection;
+import java.util.HashSet;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.function.Supplier;
+
+/**
+ * @library
+ *
+ * A simple mutable collection implementation that provides only default
+ * implementations of all methods. ie. none of the Collection interface default
+ * methods have overridden implementations.
+ *
+ * @param <E> type of collection elements
+ */
+public class ExtendsAbstractCollection<E> extends AbstractCollection<E> {
+
+ protected final Collection<E> coll;
+
+ public ExtendsAbstractCollection() {
+ this(ArrayList<E>::new);
+ }
+
+ public ExtendsAbstractCollection(Collection<E> source) {
+ this();
+ coll.addAll(source);
+ }
+
+ protected ExtendsAbstractCollection(Supplier<Collection<E>> backer) {
+ this.coll = backer.get();
+ }
+
+ public boolean add(E element) {
+ return coll.add(element);
+ }
+
+ public boolean remove(Object element) {
+ return coll.remove(element);
+ }
+
+ public Iterator<E> iterator() {
+ return new Iterator<E>() {
+ Iterator<E> source = coll.iterator();
+
+ public boolean hasNext() {
+ return source.hasNext();
+ }
+
+ public E next() {
+ return source.next();
+ }
+
+ public void remove() {
+ source.remove();
+ }
+ };
+ }
+
+ public int size() {
+ return coll.size();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Collection/testlibrary/ExtendsAbstractList.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.util.ArrayList;
+import java.util.AbstractList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Supplier;
+
+/**
+ * @library
+ *
+ * A simple mutable list implementation that provides only default
+ * implementations of all methods. ie. none of the List interface default
+ * methods have overridden implementations.
+ *
+ * @param <E> type of list elements
+ */
+public class ExtendsAbstractList<E> extends AbstractList<E> {
+
+ protected final List<E> list;
+
+ public ExtendsAbstractList() {
+ this(ArrayList<E>::new);
+ }
+
+ protected ExtendsAbstractList(Supplier<List<E>> supplier) {
+ this.list = supplier.get();
+ }
+
+ public ExtendsAbstractList(Collection<E> source) {
+ this();
+ addAll(source);
+ }
+
+ public boolean add(E element) {
+ return list.add(element);
+ }
+
+ public E get(int index) {
+ return list.get(index);
+ }
+
+ public boolean remove(Object element) {
+ return list.remove(element);
+ }
+
+ public E set(int index, E element) {
+ return list.set(index, element);
+ }
+
+ public void add(int index, E element) {
+ list.add(index, element);
+ }
+
+ public E remove(int index) {
+ return list.remove(index);
+ }
+
+ public Iterator<E> iterator() {
+ return new Iterator<E>() {
+ Iterator<E> source = list.iterator();
+
+ public boolean hasNext() {
+ return source.hasNext();
+ }
+
+ public E next() {
+ return source.next();
+ }
+
+ public void remove() {
+ source.remove();
+ }
+ };
+ }
+
+ public int size() {
+ return list.size();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Collection/testlibrary/ExtendsAbstractSet.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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.HashSet;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.function.Supplier;
+
+/**
+ * @library
+ *
+ * A simple mutable set implementation that provides only default
+ * implementations of all methods. ie. none of the Set interface default methods
+ * have overridden implementations.
+ *
+ * @param <E> type of set members
+ */
+public class ExtendsAbstractSet<E> extends AbstractSet<E> {
+
+ protected final Set<E> set;
+
+ public ExtendsAbstractSet() {
+ this(HashSet<E>::new);
+ }
+
+ public ExtendsAbstractSet(Collection<E> source) {
+ this();
+ addAll(source);
+ }
+
+ protected ExtendsAbstractSet(Supplier<Set<E>> backer) {
+ this.set = backer.get();
+ }
+
+ public boolean add(E element) {
+ return set.add(element);
+ }
+
+ public boolean remove(Object element) {
+ return set.remove(element);
+ }
+
+ public Iterator<E> iterator() {
+ return new Iterator<E>() {
+ Iterator<E> source = set.iterator();
+
+ public boolean hasNext() {
+ return source.hasNext();
+ }
+
+ public E next() {
+ return source.next();
+ }
+
+ public void remove() {
+ source.remove();
+ }
+ };
+ }
+
+ public int size() {
+ return set.size();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Collections/SingletonIterator.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @run testng SingletonIterator
+ */
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.fail;
+
+@Test(groups = "unit")
+public class SingletonIterator {
+ public void testForEachRemaining() {
+ Iterator<String> it = Collections.singleton("TheOne").iterator();
+ AtomicInteger cnt = new AtomicInteger(0);
+
+ it.forEachRemaining(s -> {
+ assertEquals("TheOne", s);
+ cnt.incrementAndGet();
+ });
+
+ assertEquals(cnt.get(), 1);
+ assertFalse(it.hasNext());
+
+ try {
+ String str = it.next();
+ fail("Should throw NoSuchElementException at end");
+ } catch (NoSuchElementException ex) {
+ // ignore;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/List/ListDefaults.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,535 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Stack;
+import java.util.Vector;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.lang.reflect.Constructor;
+import java.util.ConcurrentModificationException;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * @test
+ * @summary Unit tests for extension methods on List
+ * @bug 8023367
+ * @library ../Collection/testlibrary
+ * @build CollectionAsserts CollectionSupplier ExtendsAbstractList
+ * @run testng ListDefaults
+ */
+public class ListDefaults {
+
+ private static final Supplier<?>[] LIST_CLASSES = {
+ java.util.ArrayList::new,
+ java.util.LinkedList::new,
+ java.util.Vector::new,
+ java.util.concurrent.CopyOnWriteArrayList::new,
+ ExtendsAbstractList::new
+ };
+
+ private static final Supplier<?>[] LIST_CME_CLASSES = {
+ java.util.ArrayList::new,
+ java.util.Vector::new
+ };
+
+ private static final Predicate<Integer> pEven = x -> 0 == x % 2;
+ private static final Predicate<Integer> pOdd = x -> 1 == x % 2;
+
+ private static final Comparator<Integer> BIT_COUNT_COMPARATOR =
+ (x, y) -> Integer.bitCount(x) - Integer.bitCount(y);
+
+ private static final Comparator<AtomicInteger> ATOMIC_INTEGER_COMPARATOR =
+ (x, y) -> x.intValue() - y.intValue();
+
+ private static final int SIZE = 100;
+ private static final int SUBLIST_FROM = 20;
+ private static final int SUBLIST_TO = SIZE - 5;
+ private static final int SUBLIST_SIZE = SUBLIST_TO - SUBLIST_FROM;
+
+ private static interface Callback {
+ void call(List<Integer> list);
+ }
+
+ // call the callback for each recursive subList
+ private void trimmedSubList(final List<Integer> list, final Callback callback) {
+ int size = list.size();
+ if (size > 1) {
+ // trim 1 element from both ends
+ final List<Integer> subList = list.subList(1, size - 1);
+ callback.call(subList);
+ trimmedSubList(subList, callback);
+ }
+ }
+
+ @DataProvider(name="listProvider", parallel=true)
+ public static Object[][] listCases() {
+ final List<Object[]> cases = new LinkedList<>();
+ cases.add(new Object[] { Collections.emptyList() });
+ cases.add(new Object[] { new ArrayList<>() });
+ cases.add(new Object[] { new LinkedList<>() });
+ cases.add(new Object[] { new Vector<>() });
+ cases.add(new Object[] { new Stack<>() });
+ cases.add(new Object[] { new CopyOnWriteArrayList<>() });
+
+ cases.add(new Object[] { new ArrayList(){{add(42);}} });
+ cases.add(new Object[] { new LinkedList(){{add(42);}} });
+ cases.add(new Object[] { new Vector(){{add(42);}} });
+ cases.add(new Object[] { new Stack(){{add(42);}} });
+ cases.add(new Object[] { new CopyOnWriteArrayList(){{add(42);}} });
+ return cases.toArray(new Object[0][cases.size()]);
+ }
+
+ @Test(dataProvider = "listProvider")
+ public void testProvidedWithNull(final List<Integer> list) throws Exception {
+ try {
+ list.forEach(null);
+ fail("expected NPE not thrown");
+ } catch (NullPointerException npe) {}
+ try {
+ list.replaceAll(null);
+ fail("expected NPE not thrown");
+ } catch (NullPointerException npe) {}
+ try {
+ list.removeIf(null);
+ fail("expected NPE not thrown");
+ } catch (NullPointerException npe) {}
+ try {
+ list.sort(null);
+ } catch (Throwable t) {
+ fail("Exception not expected: " + t);
+ }
+ }
+
+ @Test
+ public void testForEach() throws Exception {
+ final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CLASSES, SIZE);
+ for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+ final List<Integer> original = ((List<Integer>) test.expected);
+ final List<Integer> list = ((List<Integer>) test.collection);
+
+ try {
+ list.forEach(null);
+ fail("expected NPE not thrown");
+ } catch (NullPointerException npe) {}
+ CollectionAsserts.assertContents(list, original);
+
+ final List<Integer> actual = new LinkedList<>();
+ list.forEach(actual::add);
+ CollectionAsserts.assertContents(actual, list);
+ CollectionAsserts.assertContents(actual, original);
+
+ if (original.size() > SUBLIST_SIZE) {
+ final List<Integer> subList = original.subList(SUBLIST_FROM, SUBLIST_TO);
+ final List<Integer> actualSubList = new LinkedList<>();
+ subList.forEach(actualSubList::add);
+ assertEquals(actualSubList.size(), SUBLIST_SIZE);
+ for (int i = 0; i < SUBLIST_SIZE; i++) {
+ assertEquals(actualSubList.get(i), original.get(i + SUBLIST_FROM));
+ }
+ }
+
+ trimmedSubList(list, new Callback() {
+ @Override
+ public void call(final List<Integer> list) {
+ final List<Integer> actual = new LinkedList<>();
+ list.forEach(actual::add);
+ CollectionAsserts.assertContents(actual, list);
+ }
+ });
+ }
+ }
+
+ @Test
+ public void testRemoveIf() throws Exception {
+ final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CLASSES, SIZE);
+ for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+ final List<Integer> original = ((List<Integer>) test.expected);
+ final List<Integer> list = ((List<Integer>) test.collection);
+
+ try {
+ list.removeIf(null);
+ fail("expected NPE not thrown");
+ } catch (NullPointerException npe) {}
+ CollectionAsserts.assertContents(list, original);
+
+ final AtomicInteger offset = new AtomicInteger(1);
+ while (list.size() > 0) {
+ removeFirst(original, list, offset);
+ }
+ }
+
+ for (final CollectionSupplier.TestCase test : supplier.get()) {
+ final List<Integer> original = ((List<Integer>) test.expected);
+ final List<Integer> list = ((List<Integer>) test.collection);
+ list.removeIf(pOdd);
+ for (int i : list) {
+ assertTrue((i % 2) == 0);
+ }
+ for (int i : original) {
+ if (i % 2 == 0) {
+ assertTrue(list.contains(i));
+ }
+ }
+ list.removeIf(pEven);
+ assertTrue(list.isEmpty());
+ }
+
+ for (final CollectionSupplier.TestCase test : supplier.get()) {
+ final List<Integer> original = ((List<Integer>) test.expected);
+ final List<Integer> list = ((List<Integer>) test.collection);
+ final List<Integer> listCopy = new ArrayList<>(list);
+ if (original.size() > SUBLIST_SIZE) {
+ final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
+ final List<Integer> subListCopy = new ArrayList<>(subList);
+ listCopy.removeAll(subList);
+ subList.removeIf(pOdd);
+ for (int i : subList) {
+ assertTrue((i % 2) == 0);
+ }
+ for (int i : subListCopy) {
+ if (i % 2 == 0) {
+ assertTrue(subList.contains(i));
+ } else {
+ assertFalse(subList.contains(i));
+ }
+ }
+ subList.removeIf(pEven);
+ assertTrue(subList.isEmpty());
+ // elements outside the view should remain
+ CollectionAsserts.assertContents(list, listCopy);
+ }
+ }
+
+ for (final CollectionSupplier.TestCase test : supplier.get()) {
+ final List<Integer> list = ((List<Integer>) test.collection);
+ trimmedSubList(list, new Callback() {
+ @Override
+ public void call(final List<Integer> list) {
+ final List<Integer> copy = new ArrayList<>(list);
+ list.removeIf(pOdd);
+ for (int i : list) {
+ assertTrue((i % 2) == 0);
+ }
+ for (int i : copy) {
+ if (i % 2 == 0) {
+ assertTrue(list.contains(i));
+ } else {
+ assertFalse(list.contains(i));
+ }
+ }
+ }
+ });
+ }
+ }
+
+ // remove the first element
+ private void removeFirst(final List<Integer> original, final List<Integer> list, final AtomicInteger offset) {
+ final AtomicBoolean first = new AtomicBoolean(true);
+ list.removeIf(x -> first.getAndSet(false));
+ CollectionAsserts.assertContents(original.subList(offset.getAndIncrement(), original.size()), list);
+ }
+
+ @Test
+ public void testReplaceAll() throws Exception {
+ final int scale = 3;
+ final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CLASSES, SIZE);
+ for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+ final List<Integer> original = ((List<Integer>) test.expected);
+ final List<Integer> list = ((List<Integer>) test.collection);
+
+ try {
+ list.replaceAll(null);
+ fail("expected NPE not thrown");
+ } catch (NullPointerException npe) {}
+ CollectionAsserts.assertContents(list, original);
+
+ list.replaceAll(x -> scale * x);
+ for (int i=0; i < original.size(); i++) {
+ assertTrue(list.get(i) == (scale * original.get(i)), "mismatch at index " + i);
+ }
+
+ if (original.size() > SUBLIST_SIZE) {
+ final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
+ subList.replaceAll(x -> x + 1);
+ // verify elements in view [from, to) were replaced
+ for (int i = 0; i < SUBLIST_SIZE; i++) {
+ assertTrue(subList.get(i) == ((scale * original.get(i + SUBLIST_FROM)) + 1),
+ "mismatch at sublist index " + i);
+ }
+ // verify that elements [0, from) remain unmodified
+ for (int i = 0; i < SUBLIST_FROM; i++) {
+ assertTrue(list.get(i) == (scale * original.get(i)),
+ "mismatch at original index " + i);
+ }
+ // verify that elements [to, size) remain unmodified
+ for (int i = SUBLIST_TO; i < list.size(); i++) {
+ assertTrue(list.get(i) == (scale * original.get(i)),
+ "mismatch at original index " + i);
+ }
+ }
+ }
+
+ for (final CollectionSupplier.TestCase test : supplier.get()) {
+ final List<Integer> list = ((List<Integer>) test.collection);
+ trimmedSubList(list, new Callback() {
+ @Override
+ public void call(final List<Integer> list) {
+ final List<Integer> copy = new ArrayList<>(list);
+ final int offset = 5;
+ list.replaceAll(x -> offset + x);
+ for (int i=0; i < copy.size(); i++) {
+ assertTrue(list.get(i) == (offset + copy.get(i)), "mismatch at index " + i);
+ }
+ }
+ });
+ }
+ }
+
+ @Test
+ public void testSort() throws Exception {
+ final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CLASSES, SIZE);
+ for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+ final List<Integer> original = ((List<Integer>) test.expected);
+ final List<Integer> list = ((List<Integer>) test.collection);
+ CollectionSupplier.shuffle(list);
+ list.sort(Integer::compare);
+ CollectionAsserts.assertSorted(list, Integer::compare);
+ if (test.name.startsWith("reverse")) {
+ Collections.reverse(list);
+ }
+ CollectionAsserts.assertContents(list, original);
+
+ CollectionSupplier.shuffle(list);
+ list.sort(null);
+ CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder());
+ if (test.name.startsWith("reverse")) {
+ Collections.reverse(list);
+ }
+ CollectionAsserts.assertContents(list, original);
+
+ CollectionSupplier.shuffle(list);
+ list.sort(Comparator.<Integer>naturalOrder());
+ CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder());
+ if (test.name.startsWith("reverse")) {
+ Collections.reverse(list);
+ }
+ CollectionAsserts.assertContents(list, original);
+
+ CollectionSupplier.shuffle(list);
+ list.sort(Comparator.<Integer>reverseOrder());
+ CollectionAsserts.assertSorted(list, Comparator.<Integer>reverseOrder());
+ if (!test.name.startsWith("reverse")) {
+ Collections.reverse(list);
+ }
+ CollectionAsserts.assertContents(list, original);
+
+ CollectionSupplier.shuffle(list);
+ list.sort(BIT_COUNT_COMPARATOR);
+ CollectionAsserts.assertSorted(list, BIT_COUNT_COMPARATOR);
+ // check sort by verifying that bitCount increases and never drops
+ int minBitCount = 0;
+ int bitCount = 0;
+ for (final Integer i : list) {
+ bitCount = Integer.bitCount(i);
+ assertTrue(bitCount >= minBitCount);
+ minBitCount = bitCount;
+ }
+
+ @SuppressWarnings("unchecked")
+ final Constructor<? extends List<?>> defaultConstructor = ((Class<? extends List<?>>)test.collection.getClass()).getConstructor();
+ final List<AtomicInteger> incomparables = (List<AtomicInteger>) defaultConstructor.newInstance();
+
+ for (int i=0; i < test.expected.size(); i++) {
+ incomparables.add(new AtomicInteger(i));
+ }
+ CollectionSupplier.shuffle(incomparables);
+ incomparables.sort(ATOMIC_INTEGER_COMPARATOR);
+ for (int i=0; i < test.expected.size(); i++) {
+ assertEquals(i, incomparables.get(i).intValue());
+ }
+
+ if (original.size() > SUBLIST_SIZE) {
+ final List<Integer> copy = new ArrayList<>(list);
+ final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
+ CollectionSupplier.shuffle(subList);
+ subList.sort(Comparator.<Integer>naturalOrder());
+ CollectionAsserts.assertSorted(subList, Comparator.<Integer>naturalOrder());
+ // verify that elements [0, from) remain unmodified
+ for (int i = 0; i < SUBLIST_FROM; i++) {
+ assertTrue(list.get(i) == copy.get(i),
+ "mismatch at index " + i);
+ }
+ // verify that elements [to, size) remain unmodified
+ for (int i = SUBLIST_TO; i < list.size(); i++) {
+ assertTrue(list.get(i) == copy.get(i),
+ "mismatch at index " + i);
+ }
+ }
+ }
+
+ for (final CollectionSupplier.TestCase test : supplier.get()) {
+ final List<Integer> list = ((List<Integer>) test.collection);
+ trimmedSubList(list, new Callback() {
+ @Override
+ public void call(final List<Integer> list) {
+ final List<Integer> copy = new ArrayList<>(list);
+ CollectionSupplier.shuffle(list);
+ list.sort(Comparator.<Integer>naturalOrder());
+ CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder());
+ }
+ });
+ }
+ }
+
+ @Test
+ public void testForEachThrowsCME() throws Exception {
+ final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CME_CLASSES, SIZE);
+ for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+ final List<Integer> list = ((List<Integer>) test.collection);
+
+ if (list.size() <= 1) {
+ continue;
+ }
+ boolean gotException = false;
+ try {
+ // bad predicate that modifies its list, should throw CME
+ list.forEach((x) -> {list.add(x);});
+ } catch (ConcurrentModificationException cme) {
+ gotException = true;
+ }
+ if (!gotException) {
+ fail("expected CME was not thrown from " + test);
+ }
+ }
+ }
+
+ @Test
+ public void testRemoveIfThrowsCME() throws Exception {
+ final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CME_CLASSES, SIZE);
+ for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+ final List<Integer> original = ((List<Integer>) test.expected);
+ final List<Integer> list = ((List<Integer>) test.collection);
+
+ if (list.size() <= 1) {
+ continue;
+ }
+ boolean gotException = false;
+ try {
+ // bad predicate that modifies its list, should throw CME
+ list.removeIf((x) -> {return list.add(x);});
+ } catch (ConcurrentModificationException cme) {
+ gotException = true;
+ }
+ if (!gotException) {
+ fail("expected CME was not thrown from " + test);
+ }
+ }
+ }
+
+ @Test
+ public void testReplaceAllThrowsCME() throws Exception {
+ final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CME_CLASSES, SIZE);
+ for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+ final List<Integer> list = ((List<Integer>) test.collection);
+
+ if (list.size() <= 1) {
+ continue;
+ }
+ boolean gotException = false;
+ try {
+ // bad predicate that modifies its list, should throw CME
+ list.replaceAll(x -> {int n = 3 * x; list.add(n); return n;});
+ } catch (ConcurrentModificationException cme) {
+ gotException = true;
+ }
+ if (!gotException) {
+ fail("expected CME was not thrown from " + test);
+ }
+ }
+ }
+
+ @Test
+ public void testSortThrowsCME() throws Exception {
+ final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CME_CLASSES, SIZE);
+ for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+ final List<Integer> list = ((List<Integer>) test.collection);
+
+ if (list.size() <= 1) {
+ continue;
+ }
+ boolean gotException = false;
+ try {
+ // bad predicate that modifies its list, should throw CME
+ list.sort((x, y) -> {list.add(x); return x - y;});
+ } catch (ConcurrentModificationException cme) {
+ gotException = true;
+ }
+ if (!gotException) {
+ fail("expected CME was not thrown from " + test);
+ }
+ }
+ }
+
+ private static final List<Integer> SLICED_EXPECTED = Arrays.asList(0, 1, 2, 3, 5, 6, 7, 8, 9);
+ private static final List<Integer> SLICED_EXPECTED2 = Arrays.asList(0, 1, 2, 5, 6, 7, 8, 9);
+
+ @DataProvider(name="shortIntListProvider", parallel=true)
+ public static Object[][] intListCases() {
+ final Integer[] DATA = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ final List<Object[]> cases = new LinkedList<>();
+ cases.add(new Object[] { new ArrayList<>(Arrays.asList(DATA)) });
+ cases.add(new Object[] { new LinkedList<>(Arrays.asList(DATA)) });
+ cases.add(new Object[] { new Vector<>(Arrays.asList(DATA)) });
+ cases.add(new Object[] { new CopyOnWriteArrayList<>(Arrays.asList(DATA)) });
+ cases.add(new Object[] { new ExtendsAbstractList<>(Arrays.asList(DATA)) });
+ return cases.toArray(new Object[0][cases.size()]);
+ }
+
+ @Test(dataProvider = "shortIntListProvider")
+ public void testRemoveIfFromSlice(final List<Integer> list) throws Exception {
+ final List<Integer> sublist = list.subList(3, 6);
+ assertTrue(sublist.removeIf(x -> x == 4));
+ CollectionAsserts.assertContents(list, SLICED_EXPECTED);
+
+ final List<Integer> sublist2 = list.subList(2, 5);
+ assertTrue(sublist2.removeIf(x -> x == 3));
+ CollectionAsserts.assertContents(list, SLICED_EXPECTED2);
+ }
+}
--- a/jdk/test/java/util/Map/CheckRandomHashSeed.java Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +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.
- */
-
-/**
- * @test
- * @bug 8005698
- * @summary Check operation of jdk.map.useRandomSeed property
- * @run main CheckRandomHashSeed
- * @run main/othervm -Djdk.map.useRandomSeed=false CheckRandomHashSeed
- * @run main/othervm -Djdk.map.useRandomSeed=bogus CheckRandomHashSeed
- * @run main/othervm -Djdk.map.useRandomSeed=true CheckRandomHashSeed true
- * @author Brent Christian
- */
-import java.lang.reflect.Field;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Hashtable;
-import java.util.WeakHashMap;
-
-public class CheckRandomHashSeed {
- private final static String PROP_NAME = "jdk.map.useRandomSeed";
- static boolean expectRandom = false;
-
- public static void main(String[] args) {
- if (args.length > 0 && args[0].equals("true")) {
- expectRandom = true;
- }
- String hashSeedProp = System.getProperty(PROP_NAME);
- boolean propSet = (null != hashSeedProp)
- ? Boolean.parseBoolean(hashSeedProp) : false;
- if (expectRandom != propSet) {
- throw new Error("Error in test setup: " + (expectRandom ? "" : "not " ) + "expecting random hashSeed, but " + PROP_NAME + " is " + (propSet ? "" : "not ") + "enabled");
- }
-
- testMap(new HashMap());
- testMap(new LinkedHashMap());
- testMap(new WeakHashMap());
- testMap(new Hashtable());
- }
-
- private static void testMap(Map map) {
- int hashSeed = getHashSeed(map);
- boolean hashSeedIsZero = (hashSeed == 0);
-
- if (expectRandom != hashSeedIsZero) {
- System.out.println("Test passed for " + map.getClass().getSimpleName() + " - expectRandom: " + expectRandom + ", hashSeed: " + hashSeed);
- } else {
- throw new Error ("Test FAILED for " + map.getClass().getSimpleName() + " - expectRandom: " + expectRandom + ", hashSeed: " + hashSeed);
- }
- }
-
- private static int getHashSeed(Map map) {
- try {
- if (map instanceof HashMap || map instanceof LinkedHashMap) {
- map.put("Key", "Value");
- Field hashSeedField = HashMap.class.getDeclaredField("hashSeed");
- hashSeedField.setAccessible(true);
- int hashSeed = hashSeedField.getInt(map);
- return hashSeed;
- } else {
- map.put("Key", "Value");
- Field hashSeedField = map.getClass().getDeclaredField("hashSeed");
- hashSeedField.setAccessible(true);
- int hashSeed = hashSeedField.getInt(map);
- return hashSeed;
- }
- } catch(Exception e) {
- e.printStackTrace();
- throw new Error(e);
- }
- }
-}
--- a/jdk/test/java/util/Map/Collisions.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/Map/Collisions.java Sat Sep 14 20:43:34 2013 +0100
@@ -25,8 +25,6 @@
* @test
* @bug 7126277
* @run main Collisions -shortrun
- * @run main/othervm -Djdk.map.althashing.threshold=0 Collisions -shortrun
- * @run main/othervm -Djdk.map.useRandomSeed=true Collisions -shortrun
* @summary Ensure Maps behave well with lots of hashCode() collisions.
* @author Mike Duigou
*/
--- a/jdk/test/java/util/Map/Defaults.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/Map/Defaults.java Sat Sep 14 20:43:34 2013 +0100
@@ -155,7 +155,7 @@
assertThrows(
() -> { map.replaceAll((k,v) -> null); },
NullPointerException.class,
- description);
+ description + " should not allow replacement with null value");
}
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
@@ -194,6 +194,15 @@
assertSame(map.get(null), EXTRA_VALUE);
}
+ @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
+ public void testReplaceKVNoNulls(String description, Map<IntegerEnum, String> map) {
+ assertTrue(map.containsKey(FIRST_KEY), "expected key missing");
+ assertSame(map.get(FIRST_KEY), FIRST_VALUE, "found wrong value");
+ assertThrows( () -> {map.replace(FIRST_KEY, null);}, NullPointerException.class, description + ": should throw NPE");
+ assertSame(map.replace(FIRST_KEY, EXTRA_VALUE), FIRST_VALUE, description + ": replaced wrong value");
+ assertSame(map.get(FIRST_KEY), EXTRA_VALUE, "found wrong value");
+ }
+
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
public void testReplaceKV(String description, Map<IntegerEnum, String> map) {
assertTrue(map.containsKey(KEYS[1]));
@@ -224,6 +233,16 @@
assertSame(map.get(null), EXTRA_VALUE);
}
+ @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
+ public void testReplaceKVVNoNulls(String description, Map<IntegerEnum, String> map) {
+ assertTrue(map.containsKey(FIRST_KEY), "expected key missing");
+ assertSame(map.get(FIRST_KEY), FIRST_VALUE, "found wrong value");
+ assertThrows( () -> {map.replace(FIRST_KEY, FIRST_VALUE, null);}, NullPointerException.class, description + ": should throw NPE");
+ assertThrows( () -> {if (!map.replace(FIRST_KEY, null, EXTRA_VALUE)) throw new NullPointerException("default returns false rather than throwing");}, NullPointerException.class, description + ": should throw NPE");
+ assertTrue(map.replace(FIRST_KEY, FIRST_VALUE, EXTRA_VALUE), description + ": replaced wrong value");
+ assertSame(map.get(FIRST_KEY), EXTRA_VALUE, "found wrong value");
+ }
+
@Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
public void testReplaceKVV(String description, Map<IntegerEnum, String> map) {
assertTrue(map.containsKey(KEYS[1]));
@@ -470,6 +489,9 @@
VALUES[each] = String.valueOf(each);
}
}
+
+ private static final IntegerEnum FIRST_KEY = KEYS[0];
+ private static final String FIRST_VALUE = VALUES[0];
private static final IntegerEnum EXTRA_KEY = IntegerEnum.EXTRA_KEY;
private static final String EXTRA_VALUE = String.valueOf(TEST_SIZE);
@@ -583,6 +605,8 @@
return Arrays.asList(
// null key hostile
new Object[]{"EnumMap", makeMap(() -> new EnumMap(IntegerEnum.class), false, nulls)},
+ new Object[]{"TreeMap", makeMap(TreeMap::new, false, nulls)},
+ new Object[]{"ExtendsAbstractMap(TreeMap)", makeMap(() -> {return new ExtendsAbstractMap(new TreeMap());}, false, nulls)},
new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(makeMap(() -> new EnumMap(IntegerEnum.class), false, nulls))}
);
}
@@ -591,10 +615,11 @@
return Arrays.asList(
// null key and value hostile
new Object[]{"Hashtable", makeMap(Hashtable::new, false, false)},
- new Object[]{"TreeMap", makeMap(TreeMap::new, false, false)},
new Object[]{"ConcurrentHashMap", makeMap(ConcurrentHashMap::new, false, false)},
new Object[]{"ConcurrentSkipListMap", makeMap(ConcurrentSkipListMap::new, false, false)},
+ new Object[]{"Collections.synchronizedMap(ConcurrentHashMap)", Collections.synchronizedMap(makeMap(ConcurrentHashMap::new, false, false))},
new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(makeMap(ConcurrentHashMap::new, false, false), IntegerEnum.class, String.class)},
+ new Object[]{"ExtendsAbstractMap(ConcurrentHashMap)", makeMap(() -> {return new ExtendsAbstractMap(new ConcurrentHashMap());}, false, false)},
new Object[]{"ImplementsConcurrentMap", makeMap(ImplementsConcurrentMap::new, false, false)}
);
}
@@ -641,18 +666,17 @@
}
public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable, String message) {
- Throwable result;
+ Throwable thrown;
try {
thrower.run();
- result = null;
+ thrown = null;
} catch (Throwable caught) {
- result = caught;
+ thrown = caught;
}
- assertInstance(result, throwable,
- (null != message)
- ? message
- : "Failed to throw " + throwable.getCanonicalName());
+ assertInstance(thrown, throwable,
+ ((null != message) ? message : "") +
+ " Failed to throw " + throwable.getCanonicalName());
}
public static <T extends Throwable> void assertThrows(Class<T> throwable, String message, Thrower<T>... throwers) {
@@ -661,11 +685,11 @@
}
}
- public static <T> void assertInstance(T actual, Class<? extends T> expected) {
+ public static void assertInstance(Object actual, Class<?> expected) {
assertInstance(expected.isInstance(actual), null);
}
- public static <T> void assertInstance(T actual, Class<? extends T> expected, String message) {
+ public static void assertInstance(Object actual, Class<?> expected, String message) {
assertTrue(expected.isInstance(actual), message);
}
--- a/jdk/test/java/util/Map/InPlaceOpsCollisions.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/Map/InPlaceOpsCollisions.java Sat Sep 14 20:43:34 2013 +0100
@@ -25,7 +25,6 @@
* @test
* @bug 8005698
* @run main InPlaceOpsCollisions -shortrun
- * @run main/othervm -Djdk.map.randomseed=true InPlaceOpsCollisions -shortrun
* @summary Ensure overrides of in-place operations in Maps behave well with lots of collisions.
* @author Brent Christian
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Map/MapBinToFromTreeTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,240 @@
+/*
+ * 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.
+ */
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static org.testng.Assert.assertEquals;
+
+/*
+ * @test
+ * @bug 8023463
+ * @summary Test the case where a bin is treeified and vice verser
+ * @run testng MapBinToFromTreeTest
+ */
+
+@Test
+public class MapBinToFromTreeTest {
+
+ // Initial capacity of map
+ // Should be >= the map capacity for treeifiying, see HashMap/ConcurrentMap.MIN_TREEIFY_CAPACITY
+ static final int INITIAL_CAPACITY = 64;
+
+ // Maximum size of map
+ // Should be > the treeify threshold, see HashMap/ConcurrentMap.TREEIFY_THRESHOLD
+ // Should be > INITIAL_CAPACITY to ensure resize occurs
+ static final int SIZE = 256;
+
+ // Load factor of map
+ // A value 1.0 will ensure that a new threshold == capacity
+ static final float LOAD_FACTOR = 1.0f;
+
+ @DataProvider(name = "maps")
+ static Object[][] mapProvider() {
+ return new Object[][] {
+ // Pass in the class name as a description for test reporting
+ // purposes
+ { HashMap.class.getName(), new HashMap(INITIAL_CAPACITY, LOAD_FACTOR) },
+ { LinkedHashMap.class.getName(), new LinkedHashMap(INITIAL_CAPACITY, LOAD_FACTOR) },
+ { ConcurrentHashMap.class.getName(), new ConcurrentHashMap(INITIAL_CAPACITY, LOAD_FACTOR) },
+ };
+ }
+
+ @Test(dataProvider = "maps")
+ public void testPutThenGet(String d, Map<HashCodeInteger, Integer> m) {
+ put(SIZE, m, (i, s) -> {
+ for (int j = 0; j < s; j++) {
+ assertEquals(m.get(new HashCodeInteger(j)).intValue(), j,
+ String.format("Map.get(%d)", j));
+ }
+ });
+ }
+
+ @Test(dataProvider = "maps")
+ public void testPutThenTraverse(String d, Map<HashCodeInteger, Integer> m) {
+ Collector<Integer, ?, ? extends Collection<Integer>> c = getCollector(m);
+
+ put(SIZE, m, (i, s) -> {
+ // Note that it is OK to collect to a Set (HashSet) as long as
+ // integer values are used since these tests only check for
+ // collisions and other tests will verify more general functionality
+ Collection<Integer> actual = m.keySet().stream().map(e -> e.value).collect(c);
+ Collection<Integer> expected = IntStream.range(0, s).boxed().collect(c);
+ assertEquals(actual, expected, "Map.keySet()");
+ });
+ }
+
+ @Test(dataProvider = "maps")
+ public void testRemoveThenGet(String d, Map<HashCodeInteger, Integer> m) {
+ put(SIZE, m, (i, s) -> { });
+
+ remove(m, (i, s) -> {
+ for (int j = i + 1; j < SIZE; j++) {
+ assertEquals(m.get(new HashCodeInteger(j)).intValue(), j,
+ String.format("Map.get(%d)", j));
+ }
+ });
+ }
+
+ @Test(dataProvider = "maps")
+ public void testRemoveThenTraverse(String d, Map<HashCodeInteger, Integer> m) {
+ put(SIZE, m, (i, s) -> { });
+
+ Collector<Integer, ?, ? extends Collection<Integer>> c = getCollector(m);
+
+ remove(m, (i, s) -> {
+ Collection<Integer> actual = m.keySet().stream().map(e -> e.value).collect(c);
+ Collection<Integer> expected = IntStream.range(i + 1, SIZE).boxed().collect(c);
+ assertEquals(actual, expected, "Map.keySet()");
+ });
+ }
+
+ @Test(dataProvider = "maps")
+ public void testUntreeifyOnResizeWithGet(String d, Map<HashCodeInteger, Integer> m) {
+ // Fill the map with 64 entries grouped into 4 buckets
+ put(INITIAL_CAPACITY, m, (i, s) -> { });
+
+ for (int i = INITIAL_CAPACITY; i < SIZE; i++) {
+ // Add further entries in the 0'th bucket so as not to disturb
+ // other buckets, entries of which may be distributed and/or
+ // the bucket untreeified on resize
+ m.put(new HashCodeInteger(i, 0), i);
+
+ for (int j = 0; j < INITIAL_CAPACITY; j++) {
+ assertEquals(m.get(new HashCodeInteger(j)).intValue(), j,
+ String.format("Map.get(%d) < INITIAL_CAPACITY", j));
+ }
+ for (int j = INITIAL_CAPACITY; j <= i; j++) {
+ assertEquals(m.get(new HashCodeInteger(j, 0)).intValue(), j,
+ String.format("Map.get(%d) >= INITIAL_CAPACITY", j));
+ }
+ }
+ }
+
+ @Test(dataProvider = "maps")
+ public void testUntreeifyOnResizeWithTraverse(String d, Map<HashCodeInteger, Integer> m) {
+ // Fill the map with 64 entries grouped into 4 buckets
+ put(INITIAL_CAPACITY, m, (i, s) -> { });
+
+ Collector<Integer, ?, ? extends Collection<Integer>> c = getCollector(m);
+
+ for (int i = INITIAL_CAPACITY; i < SIZE; i++) {
+ // Add further entries in the 0'th bucket so as not to disturb
+ // other buckets, entries of which may be distributed and/or
+ // the bucket untreeified on resize
+ m.put(new HashCodeInteger(i, 0), i);
+
+ Collection<Integer> actual = m.keySet().stream().map(e -> e.value).collect(c);
+ Collection<Integer> expected = IntStream.rangeClosed(0, i).boxed().collect(c);
+ assertEquals(actual, expected, "Key set");
+ }
+ }
+
+ Collector<Integer, ?, ? extends Collection<Integer>> getCollector(Map<?, ?> m) {
+ Collector<Integer, ?, ? extends Collection<Integer>> collector = m instanceof LinkedHashMap
+ ? Collectors.toList()
+ : Collectors.toSet();
+ return collector;
+ }
+
+ void put(int size, Map<HashCodeInteger, Integer> m, BiConsumer<Integer, Integer> c) {
+ for (int i = 0; i < size; i++) {
+ m.put(new HashCodeInteger(i), i);
+
+ c.accept(i, m.size());
+ }
+ }
+
+ void remove(Map<HashCodeInteger, Integer> m, BiConsumer<Integer, Integer> c) {
+ int size = m.size();
+ // Remove all elements thus ensuring at some point trees will be
+ // converting back to bins
+ for (int i = 0; i < size; i++) {
+ m.remove(new HashCodeInteger(i));
+
+ c.accept(i, m.size());
+ }
+ }
+
+ final static class HashCodeInteger implements Comparable<HashCodeInteger> {
+ final int value;
+
+ final int hashcode;
+
+ HashCodeInteger(int value) {
+ this(value, hash(value));
+ }
+
+ HashCodeInteger(int value, int hashcode) {
+ this.value = value;
+ this.hashcode = hashcode;
+ }
+
+ static int hash(int i) {
+ // Assuming 64 entries with keys from 0 to 63 then a map:
+ // - of capacity 64 will have 4 buckets with 16 entries per-bucket
+ // - of capacity 128 will have 8 buckets with 8 entries per-bucket
+ // - of capacity 256 will have 16 buckets with 4 entries per-bucket
+ //
+ // Re-sizing will result in re-distribution, doubling the buckets
+ // and reducing the entries by half. This will result in
+ // untreeifying when the number of entries is less than untreeify
+ // threshold (see HashMap/ConcurrentMap.UNTREEIFY_THRESHOLD)
+ return (i % 4) + (i / 4) * INITIAL_CAPACITY;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof HashCodeInteger) {
+ HashCodeInteger other = (HashCodeInteger) obj;
+ return other.value == value;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return hashcode;
+ }
+
+ @Override
+ public int compareTo(HashCodeInteger o) {
+ return value - o.value;
+ }
+
+ @Override
+ public String toString() {
+ return Integer.toString(value);
+ }
+ }
+}
--- a/jdk/test/java/util/Map/TreeBinSplitBackToEntries.java Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,255 +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.
- */
-
-import java.util.*;
-import java.lang.reflect.Field;
-
-/*
- * @test
- * @bug 8005698
- * @summary Test the case where TreeBin.splitTreeBin() converts a bin back to an Entry list
- * @run main TreeBinSplitBackToEntries unused
- * @author Brent Christian
- */
-
-public class TreeBinSplitBackToEntries {
- private static int EXPECTED_TREE_THRESHOLD = 16;
-
- // Easiest if this covers one bit higher then 'bit' in splitTreeBin() on the
- // call where the TreeBin is converted back to an Entry list
- private static int HASHMASK = 0x7F;
- private static boolean verbose = false;
- private static boolean fastFail = false;
- private static boolean failed = false;
-
- static void printlnIfVerbose(String msg) {
- if (verbose) {System.out.println(msg); }
- }
-
- public static void main(String[] args) {
- for (String arg : args) {
- switch(arg) {
- case "-verbose":
- verbose = true;
- break;
- case "-fastfail":
- fastFail = true;
- break;
- }
- }
- checkTreeThreshold();
- testMapHiTree();
- testMapLoTree();
- if (failed) {
- System.out.println("Test Failed");
- System.exit(1);
- } else {
- System.out.println("Test Passed");
- }
- }
-
- public static void checkTreeThreshold() {
- int threshold = -1;
- try {
- Class treeBinClass = Class.forName("java.util.HashMap$TreeBin");
- Field treeThreshold = treeBinClass.getDeclaredField("TREE_THRESHOLD");
- treeThreshold.setAccessible(true);
- threshold = treeThreshold.getInt(treeBinClass);
- } catch (ClassNotFoundException|NoSuchFieldException|IllegalAccessException e) {
- e.printStackTrace();
- throw new Error("Problem accessing TreeBin.TREE_THRESHOLD", e);
- }
- check("Expected TREE_THRESHOLD: " + EXPECTED_TREE_THRESHOLD +", found: " + threshold,
- threshold == EXPECTED_TREE_THRESHOLD);
- printlnIfVerbose("TREE_THRESHOLD: " + threshold);
- }
-
- public static void testMapHiTree() {
- Object[][] mapKeys = makeHiTreeTestData();
- testMapsForKeys(mapKeys, "hiTree");
- }
-
- public static void testMapLoTree() {
- Object[][] mapKeys = makeLoTreeTestData();
-
- testMapsForKeys(mapKeys, "loTree");
- }
-
- public static void testMapsForKeys(Object[][] mapKeys, String desc) {
- // loop through data sets
- for (Object[] keys_desc : mapKeys) {
- Map<Object, Object>[] maps = (Map<Object, Object>[]) new Map[]{
- new HashMap<>(4, 0.8f),
- new LinkedHashMap<>(4, 0.8f),
- };
- // for each map type.
- for (Map<Object, Object> map : maps) {
- Object[] keys = (Object[]) keys_desc[1];
- System.out.println(desc + ": testPutThenGet() for " + map.getClass());
- testPutThenGet(map, keys);
- }
- }
- }
-
- private static <T> void testPutThenGet(Map<T, T> map, T[] keys) {
- for (T key : keys) {
- printlnIfVerbose("put()ing 0x" + Integer.toHexString(Integer.parseInt(key.toString())) + ", hashCode=" + Integer.toHexString(key.hashCode()));
- map.put(key, key);
- }
- for (T key : keys) {
- check("key: 0x" + Integer.toHexString(Integer.parseInt(key.toString())) + " not found in resulting " + map.getClass().getSimpleName(), map.get(key) != null);
- }
- }
-
- /* Data to force a non-empty loTree in TreeBin.splitTreeBin() to be converted back
- * into an Entry list
- */
- private static Object[][] makeLoTreeTestData() {
- HashableInteger COLLIDING_OBJECTS[] = new HashableInteger[] {
- new HashableInteger( 0x23, HASHMASK),
- new HashableInteger( 0x123, HASHMASK),
- new HashableInteger( 0x323, HASHMASK),
- new HashableInteger( 0x523, HASHMASK),
-
- new HashableInteger( 0x723, HASHMASK),
- new HashableInteger( 0x923, HASHMASK),
- new HashableInteger( 0xB23, HASHMASK),
- new HashableInteger( 0xD23, HASHMASK),
-
- new HashableInteger( 0xF23, HASHMASK),
- new HashableInteger( 0xF123, HASHMASK),
- new HashableInteger( 0x1023, HASHMASK),
- new HashableInteger( 0x1123, HASHMASK),
-
- new HashableInteger( 0x1323, HASHMASK),
- new HashableInteger( 0x1523, HASHMASK),
- new HashableInteger( 0x1723, HASHMASK),
- new HashableInteger( 0x1923, HASHMASK),
-
- new HashableInteger( 0x1B23, HASHMASK),
- new HashableInteger( 0x1D23, HASHMASK),
- new HashableInteger( 0x3123, HASHMASK),
- new HashableInteger( 0x3323, HASHMASK),
- new HashableInteger( 0x3523, HASHMASK),
-
- new HashableInteger( 0x3723, HASHMASK),
- new HashableInteger( 0x1001, HASHMASK),
- new HashableInteger( 0x4001, HASHMASK),
- new HashableInteger( 0x1, HASHMASK),
- };
- return new Object[][] {
- new Object[]{"Colliding Objects", COLLIDING_OBJECTS},
- };
- }
-
- /* Data to force the hiTree in TreeBin.splitTreeBin() to be converted back
- * into an Entry list
- */
- private static Object[][] makeHiTreeTestData() {
- HashableInteger COLLIDING_OBJECTS[] = new HashableInteger[] {
- new HashableInteger( 0x1, HASHMASK),
- new HashableInteger( 0x101, HASHMASK),
- new HashableInteger( 0x301, HASHMASK),
- new HashableInteger( 0x501, HASHMASK),
- new HashableInteger( 0x701, HASHMASK),
-
- new HashableInteger( 0x1001, HASHMASK),
- new HashableInteger( 0x1101, HASHMASK),
- new HashableInteger( 0x1301, HASHMASK),
-
- new HashableInteger( 0x1501, HASHMASK),
- new HashableInteger( 0x1701, HASHMASK),
- new HashableInteger( 0x4001, HASHMASK),
- new HashableInteger( 0x4101, HASHMASK),
- new HashableInteger( 0x4301, HASHMASK),
-
- new HashableInteger( 0x4501, HASHMASK),
- new HashableInteger( 0x4701, HASHMASK),
- new HashableInteger( 0x8001, HASHMASK),
- new HashableInteger( 0x8101, HASHMASK),
-
-
- new HashableInteger( 0x8301, HASHMASK),
- new HashableInteger( 0x8501, HASHMASK),
- new HashableInteger( 0x8701, HASHMASK),
- new HashableInteger( 0x9001, HASHMASK),
-
- new HashableInteger( 0x23, HASHMASK),
- new HashableInteger( 0x123, HASHMASK),
- new HashableInteger( 0x323, HASHMASK),
- new HashableInteger( 0x523, HASHMASK),
- };
- return new Object[][] {
- new Object[]{"Colliding Objects", COLLIDING_OBJECTS},
- };
- }
-
- static void check(String desc, boolean cond) {
- if (!cond) {
- fail(desc);
- }
- }
-
- static void fail(String msg) {
- failed = true;
- (new Error("Failure: " + msg)).printStackTrace(System.err);
- if (fastFail) {
- System.exit(1);
- }
- }
-
- final static class HashableInteger implements Comparable<HashableInteger> {
- final int value;
- final int hashmask; //yes duplication
-
- HashableInteger(int value, int hashmask) {
- this.value = value;
- this.hashmask = hashmask;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof HashableInteger) {
- HashableInteger other = (HashableInteger) obj;
- return other.value == value;
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- // This version ANDs the mask
- return value & hashmask;
- }
-
- @Override
- public int compareTo(HashableInteger o) {
- return value - o.value;
- }
-
- @Override
- public String toString() {
- return Integer.toString(value);
- }
- }
-}
--- a/jdk/test/java/util/Spliterator/SpliteratorCharacteristics.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/Spliterator/SpliteratorCharacteristics.java Sat Sep 14 20:43:34 2013 +0100
@@ -23,7 +23,7 @@
/**
* @test
- * @bug 8020156 8020009 8022326
+ * @bug 8020156 8020009 8022326 8012913
* @run testng SpliteratorCharacteristics
*/
@@ -32,6 +32,10 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
@@ -47,7 +51,27 @@
@Test
public class SpliteratorCharacteristics {
- // TreeMap
+ public void testHashMap() {
+ assertMapCharacteristics(new HashMap<>(),
+ Spliterator.SIZED | Spliterator.DISTINCT);
+ }
+
+ public void testHashSet() {
+ assertSetCharacteristics(new HashSet<>(),
+ Spliterator.SIZED | Spliterator.DISTINCT);
+ }
+
+ public void testLinkedHashMap() {
+ assertMapCharacteristics(new LinkedHashMap<>(),
+ Spliterator.SIZED | Spliterator.DISTINCT |
+ Spliterator.ORDERED);
+ }
+
+ public void testLinkedHashSet() {
+ assertSetCharacteristics(new LinkedHashSet<>(),
+ Spliterator.SIZED | Spliterator.DISTINCT |
+ Spliterator.ORDERED);
+ }
public void testTreeMap() {
assertSortedMapCharacteristics(new TreeMap<>(),
@@ -61,9 +85,6 @@
Spliterator.SORTED | Spliterator.ORDERED);
}
-
- // TreeSet
-
public void testTreeSet() {
assertSortedSetCharacteristics(new TreeSet<>(),
Spliterator.SIZED | Spliterator.DISTINCT |
@@ -76,9 +97,6 @@
Spliterator.SORTED | Spliterator.ORDERED);
}
-
- // ConcurrentSkipListMap
-
public void testConcurrentSkipListMap() {
assertSortedMapCharacteristics(new ConcurrentSkipListMap<>(),
Spliterator.CONCURRENT | Spliterator.NONNULL |
@@ -93,9 +111,6 @@
Spliterator.ORDERED);
}
-
- // ConcurrentSkipListSet
-
public void testConcurrentSkipListSet() {
assertSortedSetCharacteristics(new ConcurrentSkipListSet<>(),
Spliterator.CONCURRENT | Spliterator.NONNULL |
@@ -113,35 +128,58 @@
//
- void assertSortedMapCharacteristics(SortedMap<Integer, String> m, int keyCharacteristics) {
+
+ void assertMapCharacteristics(Map<Integer, String> m, int keyCharacteristics) {
+ assertMapCharacteristics(m, keyCharacteristics, 0);
+ }
+
+ void assertMapCharacteristics(Map<Integer, String> m, int keyCharacteristics, int notValueCharacteristics) {
initMap(m);
- boolean hasComparator = m.comparator() != null;
+ assertCharacteristics(m.keySet(), keyCharacteristics);
+
+ assertCharacteristics(m.values(),
+ keyCharacteristics & ~(Spliterator.DISTINCT | notValueCharacteristics));
+
+ assertCharacteristics(m.entrySet(), keyCharacteristics);
+
+ if ((keyCharacteristics & Spliterator.SORTED) == 0) {
+ assertISEComparator(m.keySet());
+ assertISEComparator(m.values());
+ assertISEComparator(m.entrySet());
+ }
+ }
+
+ void assertSetCharacteristics(Set<Integer> s, int keyCharacteristics) {
+ initSet(s);
+
+ assertCharacteristics(s, keyCharacteristics);
+
+ if ((keyCharacteristics & Spliterator.SORTED) == 0) {
+ assertISEComparator(s);
+ }
+ }
+
+ void assertSortedMapCharacteristics(SortedMap<Integer, String> m, int keyCharacteristics) {
+ assertMapCharacteristics(m, keyCharacteristics, Spliterator.SORTED);
Set<Integer> keys = m.keySet();
- assertCharacteristics(keys, keyCharacteristics);
- if (hasComparator) {
+ if (m.comparator() != null) {
assertNotNullComparator(keys);
}
else {
assertNullComparator(keys);
}
- assertCharacteristics(m.values(),
- keyCharacteristics & ~(Spliterator.DISTINCT | Spliterator.SORTED));
assertISEComparator(m.values());
- assertCharacteristics(m.entrySet(), keyCharacteristics);
assertNotNullComparator(m.entrySet());
}
void assertSortedSetCharacteristics(SortedSet<Integer> s, int keyCharacteristics) {
- initSet(s);
+ assertSetCharacteristics(s, keyCharacteristics);
- boolean hasComparator = s.comparator() != null;
-
- assertCharacteristics(s, keyCharacteristics);
- if (hasComparator) {
+ if (s.comparator() != null) {
assertNotNullComparator(s);
}
else {
@@ -161,27 +199,18 @@
}
void assertCharacteristics(Collection<?> c, int expectedCharacteristics) {
- assertCharacteristics(c.spliterator(), expectedCharacteristics);
- }
-
- void assertCharacteristics(Spliterator<?> s, int expectedCharacteristics) {
- assertTrue(s.hasCharacteristics(expectedCharacteristics));
+ assertTrue(c.spliterator().hasCharacteristics(expectedCharacteristics),
+ "Spliterator characteristics");
}
void assertNullComparator(Collection<?> c) {
- assertNullComparator(c.spliterator());
- }
-
- void assertNullComparator(Spliterator<?> s) {
- assertNull(s.getComparator());
+ assertNull(c.spliterator().getComparator(),
+ "Comparator of Spliterator of Collection");
}
void assertNotNullComparator(Collection<?> c) {
- assertNotNullComparator(c.spliterator());
- }
-
- void assertNotNullComparator(Spliterator<?> s) {
- assertNotNull(s.getComparator());
+ assertNotNull(c.spliterator().getComparator(),
+ "Comparator of Spliterator of Collection");
}
void assertISEComparator(Collection<?> c) {
@@ -196,6 +225,6 @@
catch (IllegalStateException e) {
caught = true;
}
- assertTrue(caught);
+ assertTrue(caught, "Throwing IllegalStateException");
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/ConcurrentHashMap/ToArray.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2004, 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.
+ */
+
+/*
+ * @test
+ * @bug 4486658 8010293
+ * @summary thread safety of toArray methods of subCollections
+ * @author Martin Buchholz
+ */
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.IntStream;
+
+public class ToArray {
+
+ public static void main(String[] args) throws Throwable {
+ // Execute a number of times to increase the probability of
+ // failure if there is an issue
+ for (int i = 0; i < 16; i++) {
+ executeTest();
+ }
+ }
+
+ static void executeTest() throws Throwable {
+ final Throwable throwable[] = new Throwable[1];
+ final ConcurrentHashMap<Integer, Integer> m = new ConcurrentHashMap<>();
+
+ // Number of workers equal to the number of processors
+ // Each worker will put globally unique keys into the map
+ final int nWorkers = Runtime.getRuntime().availableProcessors();
+ final int sizePerWorker = 1024;
+ final int maxSize = nWorkers * sizePerWorker;
+
+ // The foreman keeps checking that the size of the arrays
+ // obtained from the key and value sets is never less than the
+ // previously observed size and is never greater than the maximum size
+ // NOTE: these size constraints are not specific to toArray and are
+ // applicable to any form of traversal of the collection views
+ CompletableFuture<?> foreman = CompletableFuture.runAsync(new Runnable() {
+ private int prevSize = 0;
+
+ private boolean checkProgress(Object[] a) {
+ int size = a.length;
+ if (size < prevSize) throw new RuntimeException("WRONG WAY");
+ if (size > maxSize) throw new RuntimeException("OVERSHOOT");
+ if (size == maxSize) return true;
+ prevSize = size;
+ return false;
+ }
+
+ @Override
+ public void run() {
+ try {
+ Integer[] empty = new Integer[0];
+ while (true) {
+ if (checkProgress(m.values().toArray())) return;
+ if (checkProgress(m.keySet().toArray())) return;
+ if (checkProgress(m.values().toArray(empty))) return;
+ if (checkProgress(m.keySet().toArray(empty))) return;
+ }
+ }
+ catch (Throwable t) {
+ throwable[0] = t;
+ }
+ }
+ });
+
+ // Create workers
+ // Each worker will put globally unique keys into the map
+ CompletableFuture<?>[] workers = IntStream.range(0, nWorkers).
+ mapToObj(w -> CompletableFuture.runAsync(() -> {
+ for (int i = 0, o = w * sizePerWorker; i < sizePerWorker; i++)
+ m.put(o + i, i);
+ })).
+ toArray(CompletableFuture<?>[]::new);
+
+ // Wait for workers and then foreman to complete
+ CompletableFuture.allOf(workers).join();
+ foreman.join();
+
+ if (throwable[0] != null)
+ throw throwable[0];
+ }
+}
--- a/jdk/test/java/util/concurrent/ConcurrentHashMap/toArray.java Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 4486658
- * @summary thread safety of toArray methods of subCollections
- * @author Martin Buchholz
- */
-
-import java.util.*;
-import java.util.concurrent.*;
-
-public class toArray {
-
- public static void main(String[] args) throws Throwable {
- final Throwable throwable[] = new Throwable[1];
- final int maxSize = 1000;
- final ConcurrentHashMap<Integer, Integer> m
- = new ConcurrentHashMap<Integer, Integer>();
-
- final Thread t1 = new Thread() { public void run() {
- for (int i = 0; i < maxSize; i++)
- m.put(i,i);}};
-
- final Thread t2 = new Thread() {
- public Throwable exception = null;
- private int prevSize = 0;
-
- private boolean checkProgress(Object[] a) {
- int size = a.length;
- if (size < prevSize) throw new RuntimeException("WRONG WAY");
- if (size > maxSize) throw new RuntimeException("OVERSHOOT");
- if (size == maxSize) return true;
- prevSize = size;
- return false;
- }
-
- public void run() {
- try {
- Integer[] empty = new Integer[0];
- while (true) {
- if (checkProgress(m.values().toArray())) return;
- if (checkProgress(m.keySet().toArray())) return;
- if (checkProgress(m.values().toArray(empty))) return;
- if (checkProgress(m.keySet().toArray(empty))) return;
- }
- } catch (Throwable t) {
- throwable[0] = t;
- }}};
-
- t2.start();
- t1.start();
-
- t1.join();
- t2.join();
-
- if (throwable[0] != null)
- throw throwable[0];
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/function/BiFunction/BiFunctionTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8024500
+ * @run testng BiFunctionTest
+ */
+
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+@Test(groups = "unit")
+public class BiFunctionTest {
+ static class Quote {
+ double unit_price;
+
+ Quote(double price) {
+ unit_price = price;
+ }
+ };
+
+ static class Order {
+ int quantity;
+
+ Order(int quantity) {
+ this.quantity = quantity;
+ }
+ };
+
+ BiFunction<Quote, Order, Double> estimate = (quote, order) -> {
+ if (quote.unit_price < 0) {
+ throw new IllegalArgumentException("quote");
+ }
+
+ if (order.quantity < 0) {
+ throw new IllegalArgumentException("order");
+ }
+
+ return quote.unit_price * order.quantity;
+ };
+
+ Function<Double, Long> creditcheck = total -> {
+ if (total > 100.00) {
+ throw new RuntimeException("overlimit");
+ }
+ return total.longValue();
+ };
+
+ public void testAndThen() {
+ try {
+ BiFunction<Quote, Order, Long> checkout = estimate.andThen(null);
+ fail("Null argument should throw NPE");
+ } catch (NullPointerException npe) {
+ // ignore
+ }
+
+ BiFunction<Quote, Order, Long> checkout = estimate.andThen(creditcheck);
+ try {
+ checkout.apply(new Quote(20.0), new Order(-1));
+ fail("First function delivers exception");
+ } catch (IllegalArgumentException e) {
+ assertEquals(e.getMessage(), "order");
+ }
+
+ try {
+ checkout.apply(new Quote(20.0), new Order(10));
+ fail("Second function delivers exception");
+ } catch (RuntimeException e) {
+ assertEquals(e.getMessage(), "overlimit");
+ }
+
+ assertEquals(49, checkout.apply(new Quote(24.99), new Order(2)).longValue());
+ assertEquals(50, checkout.apply(new Quote(25), new Order(2)).longValue());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/LocalizedLevelName.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+import java.util.*;
+import java.util.logging.*;
+
+/*
+ * @test
+ * @bug 8016127 8024131
+ * @summary test logging.properties localized
+ * @run main/othervm LocalizedLevelName
+ */
+
+public class LocalizedLevelName {
+ private static Object[] namesMap = {
+ "SEVERE", Locale.ENGLISH, "Severe", Level.SEVERE,
+ "WARNING", Locale.FRENCH, "Avertissement", Level.WARNING,
+ "INFO", Locale.ITALIAN, "Informazioni", Level.INFO,
+ "SEVERE", Locale.FRENCH, "Grave", Level.SEVERE,
+ "CONFIG", Locale.GERMAN, "Konfiguration", Level.CONFIG,
+ "ALL", Locale.ROOT, "All", Level.ALL,
+ "SEVERE", Locale.ROOT, "Severe", Level.SEVERE,
+ "WARNING", Locale.ROOT, "Warning", Level.WARNING,
+ "CONFIG", Locale.ROOT, "Config", Level.CONFIG,
+ "INFO", Locale.ROOT, "Info", Level.INFO,
+ "FINE", Locale.ROOT, "Fine", Level.FINE,
+ "FINER", Locale.ROOT, "Finer", Level.FINER,
+ "FINEST", Locale.ROOT, "Finest", Level.FINEST
+ };
+
+ public static void main(String args[]) throws Exception {
+ Locale defaultLocale = Locale.getDefault();
+ for (int i=0; i<namesMap.length; i += 4) {
+ final String key = (String) namesMap[i];
+ final Locale locale = (Locale) namesMap[i+1];
+ final String expectedTranslation = (String) namesMap[i+2];
+ final Level level = (Level) namesMap[i+3];
+
+ final String en = getLocalizedMessage(Locale.ENGLISH, key);
+ final String other = getLocalizedMessage(locale, key);
+
+ System.out.println(locale + ": " + key + "=" + expectedTranslation
+ + ", (Level." + level.getName() + ")");
+ System.out.println(" => localized(" + Locale.ENGLISH + ", "
+ + key + ")=" + en);
+ System.out.println(" => localized(" + locale + ", " + key
+ + ")=" + other);
+ if (!key.equals(en.toUpperCase(Locale.ROOT))) {
+ throw new RuntimeException("Expect " + key
+ + " equals upperCase(" + en + ")");
+ }
+ if (!Locale.ENGLISH.equals(locale) && !Locale.ROOT.equals(locale)
+ && key.equals(other.toUpperCase(Locale.ROOT))) {
+ throw new RuntimeException("Expect " + key
+ + " not equals upperCase(" + other +")");
+ }
+ if ((Locale.ENGLISH.equals(locale) || Locale.ROOT.equals(locale))
+ && !key.equals(other.toUpperCase(Locale.ROOT))) {
+ throw new RuntimeException("Expect " + key
+ + " equals upperCase(" + other +")");
+ }
+ if (!other.equals(expectedTranslation)) {
+ throw new RuntimeException("Expected \"" + expectedTranslation
+ + "\" for '" + locale + "' but got \"" + other + "\"");
+ }
+ Locale.setDefault(locale);
+ final String levelName = level.getLocalizedName();
+ System.out.println("Level.getLocalizedName() is: " + levelName);
+ if (!levelName.equals(other.toUpperCase(locale))) {
+ throw new RuntimeException("Expected \""
+ + other.toUpperCase(locale) + "\" for '"
+ + locale + "' but got \"" + levelName + "\"");
+ }
+ Locale.setDefault(defaultLocale);
+ }
+ }
+
+ private static final String RBNAME = "sun.util.logging.resources.logging";
+ private static String getLocalizedMessage(Locale locale, String key) {
+ ResourceBundle rb = ResourceBundle.getBundle(RBNAME, locale);
+ return rb.getString(key);
+ }
+}
--- a/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobal.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobal.java Sat Sep 14 20:43:34 2013 +0100
@@ -57,6 +57,12 @@
}
public static void main(String... args) {
+ final String manager = System.getProperty("java.util.logging.manager", null);
+
+ final String description = "TestGetGlobal"
+ + (System.getSecurityManager() == null ? " " :
+ " -Djava.security.manager ")
+ + (manager == null ? "" : "-Djava.util.logging.manager=" + manager);
Logger.global.info(messages[0]); // at this point LogManager is not
// initialized yet, so this message should not appear.
@@ -67,7 +73,9 @@
final List<String> expected = Arrays.asList(Arrays.copyOfRange(messages, 1, messages.length));
if (!testgetglobal.HandlerImpl.received.equals(expected)) {
- throw new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected);
+ System.err.println("Test case failed: " + description);
+ throw new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected
+ + "\n\t"+description);
}
}
}
--- a/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobalConcurrent.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobalConcurrent.java Sat Sep 14 20:43:34 2013 +0100
@@ -22,17 +22,18 @@
*/
import java.util.Arrays;
import java.util.List;
+import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @test
- * @bug 7184195
- * @summary checks that java.util.logging.Logger.getGlobal().info() logs without configuration
+ * @bug 7184195 8021003
+ * @summary Test that the global logger can log with no configuration when accessed from multiple threads.
* @build TestGetGlobalConcurrent testgetglobal.HandlerImpl testgetglobal.LogManagerImpl1 testgetglobal.LogManagerImpl2 testgetglobal.LogManagerImpl3 testgetglobal.BadLogManagerImpl testgetglobal.DummyLogManagerImpl
* @run main/othervm/timeout=10 TestGetGlobalConcurrent
* @run main/othervm/timeout=10/policy=policy -Djava.security.manager TestGetGlobalConcurrent
- * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl TestGetGlobalConcurrent
- * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl TestGetGlobalConcurrent
+ * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl1 TestGetGlobalConcurrent
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl1 TestGetGlobalConcurrent
* @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl2 TestGetGlobalConcurrent
* @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl2 TestGetGlobalConcurrent
* @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl3 TestGetGlobalConcurrent
@@ -69,7 +70,6 @@
// initialize the LogManager - and thus this message should appear.
Logger.global.info(messages[i+1]); // Now that the LogManager is
// initialized, this message should appear too.
-
final List<String> expected = Arrays.asList(Arrays.copyOfRange(messages, i, i+2));
if (!testgetglobal.HandlerImpl.received.containsAll(expected)) {
fail(new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected));
@@ -82,7 +82,6 @@
// initialize the LogManager - and thus this message should appear.
Logger.global.info(messages[i+1]); // Now that the LogManager is
// initialized, this message should appear too.
-
final List<String> expected = Arrays.asList(Arrays.copyOfRange(messages, i, i+2));
if (!testgetglobal.HandlerImpl.received.containsAll(expected)) {
fail(new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected));
@@ -96,7 +95,6 @@
// initialize the LogManager - and thus this message should appear.
Logger.global.info(messages[i+1]); // Now that the LogManager is
// initialized, this message should appear too.
-
final List<String> expected = Arrays.asList(Arrays.copyOfRange(messages, i, i+2));
if (!testgetglobal.HandlerImpl.received.containsAll(expected)) {
fail(new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected));
@@ -150,8 +148,17 @@
public void run() { test4(); }
}
+ static String description = "Unknown";
+
public static void main(String... args) throws Exception {
+ final String manager = System.getProperty("java.util.logging.manager", null);
+
+ description = "TestGetGlobalConcurrent"
+ + (System.getSecurityManager() == null ? " " :
+ " -Djava.security.manager ")
+ + (manager == null ? "" : "-Djava.util.logging.manager=" + manager);
+
final Thread t1 = new Thread(new WaitAndRun(new Run1()), "test1");
final Thread t2 = new Thread(new WaitAndRun(new Run2()), "test2");
final Thread t3 = new Thread(new WaitAndRun(new Run3()), "test3");
@@ -169,14 +176,13 @@
final List<String> expected = Arrays.asList(Arrays.copyOfRange(messages, 1, 3));
if (!testgetglobal.HandlerImpl.received.containsAll(expected)) {
- throw new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected);
+ fail(new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected));
}
-
t1.join(); t2.join(); t3.join(); t4.join();
if (failed != null) {
- throw new Error("Test failed.", failed);
+ throw new Error("Test failed: "+description, failed);
}
System.out.println("Test passed");
--- a/jdk/test/java/util/logging/Logger/getGlobal/policy Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/logging/Logger/getGlobal/policy Sat Sep 14 20:43:34 2013 +0100
@@ -1,6 +1,7 @@
grant {
permission java.util.PropertyPermission "java.util.logging.config.file", "write";
permission java.util.PropertyPermission "test.src", "read";
+ permission java.util.PropertyPermission "java.util.logging.manager", "read";
permission java.lang.RuntimePermission "setContextClassLoader";
permission java.lang.RuntimePermission "shutdownHooks";
permission java.util.logging.LoggingPermission "control";
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/Logger/isLoggable/TestIsLoggable.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,512 @@
+/*
+ * 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.
+ */
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+/**
+ * @test
+ * @bug 8024525
+ * @summary checks that isLoggable() can be overridden to control logging.
+ * @author danielfuchs
+ * @run main/othervm TestIsLoggable
+ */
+public class TestIsLoggable {
+
+ // This logger can be configured to override its default level
+ // for a particular set of thread ids
+ public static final class ThreadLogger extends Logger {
+
+ final Map<Long, Level> threadMap =
+ Collections.synchronizedMap(new HashMap<Long, Level>());
+
+ public ThreadLogger(String name) {
+ super(name, null);
+ }
+
+ @Override
+ public boolean isLoggable(Level level) {
+ final Level threadLevel = threadMap.get(Thread.currentThread().getId());
+ if (threadLevel == null) return super.isLoggable(level);
+ final int levelValue = threadLevel.intValue();
+ final int offValue = Level.OFF.intValue();
+ if (level.intValue() < levelValue || levelValue == offValue) {
+ return false;
+ }
+ return true;
+ }
+
+ }
+
+ public static final class TestHandler extends Handler {
+
+ final List<String> messages = new CopyOnWriteArrayList<>();
+
+ @Override
+ public void publish(LogRecord record) {
+ messages.add(record.getMessage());
+ }
+
+ @Override
+ public void flush() {
+ }
+
+ @Override
+ public void close() throws SecurityException {
+ messages.clear();
+ }
+
+ }
+
+ // Sorted list of standard levels
+ static final List<Level> LEVELS = Collections.unmodifiableList(
+ java.util.Arrays.asList(new Level[] {
+ Level.SEVERE, Level.WARNING, Level.INFO, Level.CONFIG,
+ Level.FINE, Level.FINER, Level.FINEST
+ }));
+
+ // Test cases:
+ // LEV_ test logger.severe(msg) .. logger.finest(msg)
+ // LOG_ logger.log(Level.SEVERE, msg) ... logger.log(Level.FINEST, msg)
+ // LOG1_ logger.log(Level.SEVERE, msg, param1) ...
+ // LOG2_ logger.log(Level.SEVERE, msg, params[]) ...
+ // LOG3_ logger.log(Level.SEVERE, msg, throwable) ...
+ // LOGP_ logger.logp(Level.SEVERE, class, method, msg) ...
+ // LOGP1_ logger.logp(Level.SEVERE, class, method, msg, param1) ...
+ // LOGP2_ logger.logp(Level.SEVERE, class, method, msg, params[]) ...
+ // LOGP3_ logger.logp(Level.SEVERE, class, method, msg, throwable) ...
+ public static enum LogTest {
+ LEV_SEVERE, LEV_WARNING, LEV_INFO, LEV_CONFIG, LEV_FINE, LEV_FINER, LEV_FINEST,
+ LOG_SEVERE, LOG_WARNING, LOG_INFO, LOG_CONFIG, LOG_FINE, LOG_FINER, LOG_FINEST,
+ LOG1_SEVERE, LOG1_WARNING, LOG1_INFO, LOG1_CONFIG, LOG1_FINE, LOG1_FINER, LOG1_FINEST,
+ LOG2_SEVERE, LOG2_WARNING, LOG2_INFO, LOG2_CONFIG, LOG2_FINE, LOG2_FINER, LOG2_FINEST,
+ LOG3_SEVERE, LOG3_WARNING, LOG3_INFO, LOG3_CONFIG, LOG3_FINE, LOG3_FINER, LOG3_FINEST,
+ LOGP_SEVERE, LOGP_WARNING, LOGP_INFO, LOGP_CONFIG, LOGP_FINE, LOGP_FINER, LOGP_FINEST,
+ LOGP1_SEVERE, LOGP1_WARNING, LOGP1_INFO, LOGP1_CONFIG, LOGP1_FINE, LOGP1_FINER, LOGP1_FINEST,
+ LOGP2_SEVERE, LOGP2_WARNING, LOGP2_INFO, LOGP2_CONFIG, LOGP2_FINE, LOGP2_FINER, LOGP2_FINEST,
+ LOGP3_SEVERE, LOGP3_WARNING, LOGP3_INFO, LOGP3_CONFIG, LOGP3_FINE, LOGP3_FINER, LOGP3_FINEST;
+
+ // call the method Logger.severe() ... Logger.finest() corresponding
+ // to the given level 'l' (severe() for SEVERE etc...)
+ public void loglevel(Level l, Logger logger, String message) {
+ LogTest test = LogTest.valueOf("LEV_"+l.getName());
+ switch(test) {
+ case LEV_SEVERE:
+ logger.severe(message);
+ break;
+ case LEV_WARNING:
+ logger.warning(message);
+ break;
+ case LEV_INFO:
+ logger.info(message);
+ break;
+ case LEV_CONFIG:
+ logger.config(message);
+ break;
+ case LEV_FINE:
+ logger.fine(message);
+ break;
+ case LEV_FINER:
+ logger.finer(message);
+ break;
+ case LEV_FINEST:
+ logger.finest(message);
+ break;
+ }
+ }
+
+ // The threshold at which the logger is expected to start logging.
+ // trick: we derive the threshold level from the testcase name...
+ public Level threshold() {
+ for (Level l : LEVELS ) {
+ if (this.toString().endsWith(l.getName())) {
+ return l;
+ }
+ }
+ return Level.OFF;
+ }
+
+ // Levels for which the logger is expected to log something.
+ public List<Level> loggable() {
+ return LEVELS.subList(0, LEVELS.indexOf(threshold())+1);
+ }
+
+ // Levels which will be blocked because they are weaker than the
+ // threshold()
+ public List<Level> weaker() {
+ return LEVELS.subList(LEVELS.indexOf(threshold())+1, LEVELS.size());
+ }
+
+ // Log a message at this testcase threshold, using this testcase method.
+ public void log(Logger logger, String message) {
+ log(threshold(), logger, message);
+ }
+
+ // Log a message at the given level, using this testcase method.
+ public void log(Level level, Logger logger, String message) {
+ if (this.toString().startsWith("LOG_")) {
+ logger.log(level, message);
+ } else if (this.toString().startsWith("LOG1_")) {
+ logger.log(level, message, "dummy param");
+ } else if (this.toString().startsWith("LOG2_")) {
+ logger.log(level, message, new Object[] {"dummy", "param"});
+ } else if (this.toString().startsWith("LOG3_")) {
+ logger.log(level, message, new Exception("dummy exception"));
+ } else if (this.toString().startsWith("LOGP_")) {
+ logger.logp(level, "TestCase", "log", message);
+ } else if (this.toString().startsWith("LOGP1_")) {
+ logger.logp(level, "TestCase", "log", message, "dummy param");
+ } else if (this.toString().startsWith("LOGP2_")) {
+ logger.logp(level, "TestCase", "log", message,
+ new Object[] {"dummy", "param"});
+ } else if (this.toString().startsWith("LOGP3_")) {
+ logger.logp(level, "TestCase", "log", message,
+ new Exception("dummy exception"));
+ } else if (this.toString().startsWith("LEV_")) {
+ loglevel(level, logger, message);
+ }
+ }
+
+ // String description of the logging method called.
+ public String method() {
+ if (this.toString().startsWith("LOG_")) {
+ return "Logger.log(Level." + threshold().getName() +", msg): ";
+ } else if (this.toString().startsWith("LOG1_")) {
+ return "Logger.log(Level." + threshold().getName() +", msg, param1): ";
+ } else if (this.toString().startsWith("LOG2_")) {
+ return "Logger.log(Level." + threshold().getName() +", msg, params[]): ";
+ } else if (this.toString().startsWith("LOG3_")) {
+ return "Logger.log(Level." + threshold().getName() +", msg, throwable): ";
+ } else if (this.toString().startsWith("LEV_")) {
+ return "Logger."+threshold().getName().toLowerCase(Locale.ROOT)+"(): ";
+ } else if (this.toString().startsWith("LOGP_")) {
+ return "Logger.logp(Level." + threshold().getName() +", msg): ";
+ } else if (this.toString().startsWith("LOGP1_")) {
+ return "Logger.logp(Level." + threshold().getName() +", msg, param1): ";
+ } else if (this.toString().startsWith("LOGP2_")) {
+ return "Logger.logp(Level." + threshold().getName() +", msg, params[]): ";
+ } else if (this.toString().startsWith("LOGP3_")) {
+ return "Logger.logp(Level." + threshold().getName() +", msg, throwable): ";
+ }
+ throw new RuntimeException("Unknown test case: "+this);
+ }
+ }
+
+ // The purpose of this test is to verify that the various log methods in
+ // Logger now call Logger.isLoggable().
+ // To do that - we're going to use a subclass of Logger, ThreadLogger, which
+ // only overrides isLoggable() - and compare the level it is given to a level
+ // it finds in a map indexed with the current thread id.
+ // We will register a TestHandler with our ThreadLogger which will store
+ // the messages in a messages map. This will allow us to verify whether the
+ // logging method we're testing has or hasn't logged.
+ //
+ // The TestCase enum above allows us to test a combination of every possible
+ // log method with every possible level inside a loop - with the
+ // exception of exiting/entering/throwing that we will be testing
+ // outside of that loop.
+ //
+ public static void main(String... args) {
+ LogManager manager = LogManager.getLogManager();
+ ThreadLogger logger = new ThreadLogger("foo.bar");
+ //manager.addLogger(logger);
+ TestHandler handler = new TestHandler();
+ logger.addHandler(handler);
+
+ //By default, logger's level is Level.INFO
+ final List<Level> loggable = LEVELS.subList(0, LEVELS.indexOf(Level.INFO)+1);
+
+ // Check our test implementation of logger.isLoggable();
+ //
+ // Since we haven't put anything in the threadMap, isLoggable() should
+ // return true for all levels stronger or equals to Level.INFO.
+ // here we're just checking that our implementation of
+ // ThreadLogger.isLoggable() returns what we want - we're just testing
+ // the test code...
+ for (Level level : LEVELS) {
+ if (logger.isLoggable(level) != loggable.contains(level)) {
+ throw new RuntimeException(level +
+ ": unexpected result for isLoggable(): expected " +
+ (loggable.contains(level)));
+ }
+ }
+
+ // Test that entering/exiting/throwing call isLoggable()
+
+ // Here we test the default behavior: this call shouldn't log anything
+ // because by default the logger level is Level.INFO and these
+ // methods log at Level.FINER.
+ // So by default - these methods don't log anything. We check it here.
+ logger.entering("blah", "blah");
+ logger.entering("blah", "blah", "blah");
+ logger.entering("blah", "blah", new Object[] {"blah"});
+ if (!handler.messages.isEmpty()) {
+ throw new RuntimeException("Expected empty, got "+handler.messages);
+ }
+
+ logger.exiting("blah", "blah");
+ logger.exiting("blah", "blah", "blah");
+ logger.exiting("blah", "blah", new Object[] {"blah"});
+ if (!handler.messages.isEmpty()) {
+ throw new RuntimeException("Expected empty, got "+handler.messages);
+ }
+
+ logger.throwing("blah", "blah", new Exception("blah"));
+ if (!handler.messages.isEmpty()) {
+ throw new RuntimeException("Expected empty, got "+handler.messages);
+ }
+
+ // Now we're going to put each level in turn in the threadMap.
+ // This means that isLoggable(Level.FINER) should now return true if the
+ // level in the map is not one of the level in the 'stronger' list below
+ // (here stronger=stronger than FINER)
+ final List<Level> stronger = LEVELS.subList(0, LEVELS.indexOf(Level.FINER));
+ for (Level l : LEVELS) {
+
+ logger.threadMap.put(Thread.currentThread().getId(), l);
+
+ // Check that our implementation of isLoggable(level) now returns true
+ // if 'level' is stronger or equals to 'l' - here we're just checking
+ // that our implementation of ThreadLogger.isLoggable() returns what
+ // we want - we're just testing the test code...
+ final List<Level> loggableLevels = LEVELS.subList(0, LEVELS.indexOf(l)+1);
+ for (Level level : LEVELS) {
+ if (logger.isLoggable(level) != loggableLevels.contains(level)) {
+ throw new RuntimeException(level +
+ ": unexpected result for isLoggable(): expected " +
+ (loggableLevels.contains(level)));
+ }
+ }
+
+ // These methods should now start to log when the level we put in
+ // the map is weaker or equals to Level.FINER.
+ // This validates that these methods now call ThreadLogger.isLoggable()
+ // since the default level for our logger is still Level.INFO.
+ // If the methods didn't call ThreadLogger.isLoggable() they wouldn't
+ // log anything, whatever we put in the threadMap...
+
+ logger.entering("blah", "blah");
+ logger.entering("blah", "blah", "blah");
+ logger.entering("blah", "blah", new Object[] {"blah"});
+ if (stronger.contains(l)) {
+ if (!handler.messages.isEmpty()) {
+ throw new RuntimeException(l +
+ ": Expected empty, got " + handler.messages);
+ }
+ } else {
+ if (handler.messages.size() != 3) {
+ throw new RuntimeException(l +
+ ": Expected size 3, got " + handler.messages);
+ }
+ }
+
+ logger.exiting("blah", "blah");
+ logger.exiting("blah", "blah", "blah");
+ logger.exiting("blah", "blah", new Object[] {"blah"});
+ if (stronger.contains(l)) {
+ if (!handler.messages.isEmpty()) {
+ throw new RuntimeException(l +
+ ": Expected empty, got " + handler.messages);
+ }
+ } else {
+ if (handler.messages.size() != 6) {
+ throw new RuntimeException(l +
+ ": Expected size 6, got " + handler.messages);
+ }
+ }
+
+ logger.throwing("blah", "blah", new Exception("blah"));
+ if (stronger.contains(l)) {
+ if (!handler.messages.isEmpty()) {
+ throw new RuntimeException(l +
+ ": Expected empty, got " + handler.messages);
+ }
+ } else {
+ if (handler.messages.size() != 7) {
+ throw new RuntimeException(l +
+ ": Expected size 7, got " + handler.messages);
+ }
+ }
+ if (!stronger.contains(l)) {
+ System.out.println(l + ": Logger.entering/exiting/throwing: " +
+ handler.messages);
+ }
+ handler.messages.clear();
+ }
+
+ // Cleanup so that we can start the next test with a clean plate...
+ handler.messages.clear();
+ logger.threadMap.clear();
+
+ // Test that each logging method calls isLoggable()
+ //
+ for (LogTest testCase : LogTest.values()) {
+ // Each test case is a combination of:
+ // 1. A level to put in the threadMap.
+ // 2. A log method to call
+ final String method = testCase.method();
+
+ // check our implementation of logger.isLoggable();
+ // by default the logger level is Level.INFO, so our implementation
+ // of isLoggable() should return true for all levels stronger or
+ // equal to INFO and false for the others.
+ // We check that here.
+ for (Level level : LEVELS) {
+ if (logger.isLoggable(level) != loggable.contains(level)) {
+ throw new RuntimeException(level +
+ ": unexpected result for isLoggable(): expected " +
+ (loggable.contains(level)));
+ }
+ }
+
+ // Check that by default the log method will not log for level
+ // weaker than Level.INFO.
+ for (Level l : LEVELS.subList(LEVELS.indexOf(Level.INFO) + 1, LEVELS.size())) {
+ final String test = method + l + ": ";
+ testCase.log(l, logger, "blah");
+ if (!handler.messages.isEmpty()) {
+ throw new RuntimeException(test +
+ "Expected empty, got " + handler.messages);
+ }
+ }
+
+ // Let's put Level.OFF in the threadMap. Nothing should be logged,
+ // whichever level is used...
+ logger.threadMap.put(Thread.currentThread().getId(), Level.OFF);
+
+ // Check that isLoggable() now always return false.
+ for (Level level : LEVELS) {
+ if (logger.isLoggable(level)) {
+ throw new RuntimeException(level +
+ ": unexpected result for isLoggable(): expected " +
+ false);
+ }
+ }
+
+ // Check that the log method of the test case won't log, whatever
+ // level we pass to it. This validates that level method calls
+ // isLoggable() - because otherwise it would log for levels stronger
+ // or equal to INFO.
+ for (Level l : LEVELS) {
+ final String test = "[threadMap=OFF] " + method + l + ": ";
+ testCase.log(l, logger, "blah");
+ if (!handler.messages.isEmpty()) {
+ throw new RuntimeException(test +
+ "Expected empty, got " + handler.messages);
+ }
+ }
+ System.out.println("[threadMap=OFF] " + method + "logged " + handler.messages);
+
+ // Now put the testcase's level in the threadMap.
+ logger.threadMap.put(Thread.currentThread().getId(), testCase.threshold());
+
+ // The levels for which logging should happen are those that are stronger
+ // or equals to the testcase's thresholds.
+ final List<Level> loggableLevels =
+ LEVELS.subList(0, LEVELS.indexOf(testCase.threshold())+1);
+
+ // Check that our implementation of isLoggable() is taking into account
+ // what we put in the map.
+ for (Level level : LEVELS) {
+ if (logger.isLoggable(level) != loggableLevels.contains(level)) {
+ throw new RuntimeException(level +
+ ": unexpected result for isLoggable(): expected " +
+ (loggableLevels.contains(level)));
+ }
+ }
+
+ // Now check that the log method is indeed calling our implementation
+ // of isLoggable(). We do this by first verifying that it won't log
+ // for levels weaker than what we put in the map.
+ //
+ for (Level l : testCase.weaker()) {
+ final String test = method + l + ": ";
+ testCase.log(l, logger, "blah");
+ if (!handler.messages.isEmpty()) {
+ throw new RuntimeException(test +
+ "Expected empty, got " + handler.messages);
+ }
+ }
+
+ // Then we check that it will log for the testcase threshold.
+ final String test2 = method + testCase.threshold() + ": ";
+ testCase.log(logger, testCase.threshold() + " blah");
+ if (handler.messages.isEmpty()) {
+ throw new RuntimeException(test2 +
+ "Expected 1 message, but list is empty");
+ }
+ if (!handler.messages.contains(testCase.threshold() + " blah")) {
+ throw new RuntimeException(test2 + " blah not found: "
+ + handler.messages);
+ }
+ handler.messages.clear();
+
+ // Now we check that it logs for all 'loggable' level (and doesn't
+ // log for the others).
+ for (Level l : LEVELS) {
+ final String test = method + l + ": ";
+ testCase.log(l, logger, l + ": blah");
+ if (testCase.loggable().contains(l)) {
+ if (!handler.messages.contains(l + ": blah")) {
+ throw new RuntimeException(test + "blah not found: " +
+ handler.messages);
+ }
+ } else {
+ if (handler.messages.contains(l + ": blah")) {
+ throw new RuntimeException(test + "blah found: " +
+ handler.messages);
+ }
+ }
+ }
+ if (handler.messages.size() != testCase.loggable().size()) {
+ throw new RuntimeException(method +
+ " Sizes don't match: expected " +
+ testCase.loggable().size() + " got " +
+ handler.messages);
+ }
+
+ // Some visual feedback on what happened.
+ System.out.println(method + "logged " + handler.messages);
+
+ // Cleanup for next step.
+ // Since we're iterating over all possible levels we can be
+ // sure that we haven't missed anything.
+ // For instance - it could be argued that logger.severe() will
+ // always log. But since we have 1 case where we put Level.OFF in
+ // the map and we have verified that severe() didn't log in that
+ // case, but that it logged in any other case, then we know
+ // beyond doubt that it called our implementation of isLoggable().
+ logger.threadMap.clear();
+ handler.messages.clear();
+ }
+
+ }
+}
--- a/jdk/test/java/util/logging/ParentLoggersTest.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/logging/ParentLoggersTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -29,7 +29,7 @@
* @author ss45998
*
* @build ParentLoggersTest
- * @run main/othervm ParentLoggersTest
+ * @run main ParentLoggersTest
*/
/*
--- a/jdk/test/java/util/logging/TestAppletLoggerContext.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/logging/TestAppletLoggerContext.java Sat Sep 14 20:43:34 2013 +0100
@@ -38,7 +38,7 @@
/*
* @test
- * @bug 8017174 8010727
+ * @bug 8017174 8010727 8019945
* @summary NPE when using Logger.getAnonymousLogger or
* LogManager.getLogManager().getLogger
*
@@ -110,28 +110,19 @@
}
TestExc exc;
- TestExc global = new TestExc();
@Override
- public Object getContext() { return active ? global : null; }
- @Override
- public Object getExecutionContext() { return active ? exc : null; }
+ public Object getAppletContext() { return active ? exc : null; }
@Override
- public Object get(Object o, Object o1) { return TestExc.exc(o).get(o1); }
- @Override
- public void put(Object o, Object o1, Object o2) { TestExc.exc(o).put(o1, o2); }
+ public Object get(Object o) { return exc.get(o); }
@Override
- public void remove(Object o, Object o1) { TestExc.exc(o).remove(o1); }
- @Override
- public Object get(Object o) { return global.get(o); }
+ public void put(Object o, Object o1) { exc.put(o, o1); }
@Override
- public void put(Object o, Object o1) { global.put(o, o1); }
- @Override
- public void remove(Object o) { global.remove(o); }
+ public void remove(Object o) { exc.remove(o); }
@Override
public boolean isDisposed() { return false; }
@Override
- public boolean isMainAppContext() { return exc == null; }
+ public boolean isMainAppContext() { return !active || exc == null; }
}
final static JavaAWTAccessStub javaAwtAccess = new JavaAWTAccessStub();
@@ -441,45 +432,36 @@
assertNull(manager.getLogger(""));
assertNull(manager.getLogger(""));
- Bridge.changeContext();
+ for (int j = 0; j<3; j++) {
+ Bridge.changeContext();
- // this is not a supported configuration:
- // We are in an applet context with several log managers.
- // We however need to check our assumptions...
+ // this is not a supported configuration:
+ // We are in an applet context with several log managers.
+ // We however need to check our assumptions...
- // Applet context => root logger and global logger are not null.
- // root == LogManager.getLogManager().rootLogger
- // global == Logger.global
+ // Applet context => root logger and global logger should also be null.
- Logger logger3 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
- Logger logger3b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
- assertNotNull(logger3);
- assertNotNull(logger3b);
- Logger expected = (System.getSecurityManager() != null
- ? Logger.getGlobal()
- : global);
- assertEquals(logger3, expected); // in applet context, we will not see
- // the LogManager's custom global logger added above...
- assertEquals(logger3b, expected); // in applet context, we will not see
- // the LogManager's custom global logger added above...
- Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
- manager.addLogger(global2); // adding a global logger will not work in applet context
- // we will always get back the global logger.
- // this could be considered as a bug...
- Logger logger4 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
- Logger logger4b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
- assertNotNull(logger4);
- assertNotNull(logger4b);
- assertEquals(logger4, expected); // adding a global logger will not work in applet context
- assertEquals(logger4b, expected); // adding a global logger will not work in applet context
+ Logger expected = (System.getSecurityManager() == null ? global : null);
+ Logger logger3 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+ Logger logger3b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+ assertEquals(expected, logger3);
+ assertEquals(expected, logger3b);
+ Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
+ manager.addLogger(global2);
+ Logger logger4 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+ Logger logger4b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+ assertNotNull(logger4);
+ assertNotNull(logger4b);
+ expected = (System.getSecurityManager() == null ? global : global2);;
+ assertEquals(logger4, expected);
+ assertEquals(logger4b, expected);
- Logger logger5 = manager.getLogger("");
- Logger logger5b = manager.getLogger("");
- Logger expectedRoot = (System.getSecurityManager() != null
- ? LogManager.getLogManager().getLogger("")
- : null);
- assertEquals(logger5, expectedRoot);
- assertEquals(logger5b, expectedRoot);
+ Logger logger5 = manager.getLogger("");
+ Logger logger5b = manager.getLogger("");
+ Logger expectedRoot = null;
+ assertEquals(logger5, expectedRoot);
+ assertEquals(logger5b, expectedRoot);
+ }
}
}
@@ -520,57 +502,53 @@
assertEquals(logger4, root);
assertEquals(logger4b, root);
- Bridge.changeContext();
+ for (int j = 0 ; j < 3 ; j++) {
+ Bridge.changeContext();
- // this is not a supported configuration:
- // We are in an applet context with several log managers.
- // We haowever need to check our assumptions...
+ // this is not a supported configuration:
+ // We are in an applet context with several log managers.
+ // We however need to check our assumptions...
- // Applet context => root logger and global logger are not null.
- // root == LogManager.getLogManager().rootLogger
- // global == Logger.global
+ // Applet context => root logger and global logger should also be null.
- Logger logger5 = manager.getLogger("");
- Logger logger5b = manager.getLogger("");
- Logger expectedRoot = (System.getSecurityManager() != null
- ? LogManager.getLogManager().getLogger("")
- : root);
+ Logger logger5 = manager.getLogger("");
+ Logger logger5b = manager.getLogger("");
+ Logger expectedRoot = (System.getSecurityManager() == null ? root : null);
+ assertEquals(logger5, expectedRoot);
+ assertEquals(logger5b, expectedRoot);
- assertNotNull(logger5);
- assertNotNull(logger5b);
- assertEquals(logger5, expectedRoot);
- assertEquals(logger5b, expectedRoot);
- if (System.getSecurityManager() != null) {
- assertNotEquals(logger5, root);
- assertNotEquals(logger5b, root);
- }
+ if (System.getSecurityManager() != null) {
+ assertNull(manager.getLogger(Logger.GLOBAL_LOGGER_NAME));
+ } else {
+ assertEquals(global, manager.getLogger(Logger.GLOBAL_LOGGER_NAME));
+ }
- Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
- manager.addLogger(global2); // adding a global logger will not work in applet context
- // we will always get back the global logger.
- // this could be considered as a bug...
- Logger logger6 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
- Logger logger6b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
- Logger expectedGlobal = (System.getSecurityManager() != null
- ? Logger.getGlobal()
- : global);
- assertNotNull(logger6);
- assertNotNull(logger6b);
- assertEquals(logger6, expectedGlobal); // adding a global logger will not work in applet context
- assertEquals(logger6b, expectedGlobal); // adding a global logger will not work in applet context
+ Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
+ manager.addLogger(global2);
+ Logger logger6 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+ Logger logger6b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+ Logger expectedGlobal = (System.getSecurityManager() == null ? global : global2);
- Logger root2 = new Bridge.CustomLogger("");
- manager.addLogger(root2); // adding a root logger will not work in applet context
- // we will always get back the default manager's root logger.
- // this could be considered as a bug...
- Logger logger7 = manager.getLogger("");
- Logger logger7b = manager.getLogger("");
- assertNotNull(logger7);
- assertNotNull(logger7b);
- assertEquals(logger7, expectedRoot); // adding a global logger will not work in applet context
- assertEquals(logger7b, expectedRoot); // adding a global logger will not work in applet context
- assertNotEquals(logger7, root2);
- assertNotEquals(logger7b, root2);
+ assertNotNull(logger6);
+ assertNotNull(logger6b);
+ assertEquals(logger6, expectedGlobal);
+ assertEquals(logger6b, expectedGlobal);
+ if (System.getSecurityManager() != null) {
+ assertNull(manager.getLogger(""));
+ } else {
+ assertEquals(root, manager.getLogger(""));
+ }
+
+ Logger root2 = new Bridge.CustomLogger("");
+ manager.addLogger(root2);
+ expectedRoot = (System.getSecurityManager() == null ? root : root2);
+ Logger logger7 = manager.getLogger("");
+ Logger logger7b = manager.getLogger("");
+ assertNotNull(logger7);
+ assertNotNull(logger7b);
+ assertEquals(logger7, expectedRoot);
+ assertEquals(logger7b, expectedRoot);
+ }
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/TestLoggingWithMainAppContext.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.logging.Logger;
+import javax.imageio.ImageIO;
+
+/**
+ * @test
+ * @bug 8019853 8023258
+ * @summary Test that the default user context is used when in the main
+ * application context. This test must not be run in same VM or agent
+ * VM mode: it would not test the intended behavior.
+ * @run main/othervm TestLoggingWithMainAppContext
+ */
+public class TestLoggingWithMainAppContext {
+
+ public static void main(String[] args) throws IOException {
+ System.out.println("Creating loggers.");
+
+ // These loggers will be created in the default user context.
+ final Logger foo1 = Logger.getLogger( "foo" );
+ final Logger bar1 = Logger.getLogger( "foo.bar" );
+ if (bar1.getParent() != foo1) {
+ throw new RuntimeException("Parent logger of bar1 "+bar1+" is not "+foo1);
+ }
+ System.out.println("bar1.getParent() is the same as foo1");
+
+ // Set a security manager
+ System.setSecurityManager(new SecurityManager());
+ System.out.println("Now running with security manager");
+
+ // Triggers the creation of the main AppContext
+ ByteArrayInputStream is = new ByteArrayInputStream(new byte[] { 0, 1 });
+ ImageIO.read(is); // triggers calls to system loggers & creation of main AppContext
+
+ // verify that we're still using the default user context
+ final Logger bar2 = Logger.getLogger( "foo.bar" );
+ if (bar1 != bar2) {
+ throw new RuntimeException("bar2 "+bar2+" is not the same as bar1 "+bar1);
+ }
+ System.out.println("bar2 is the same as bar1");
+ if (bar2.getParent() != foo1) {
+ throw new RuntimeException("Parent logger of bar2 "+bar2+" is not foo1 "+foo1);
+ }
+ System.out.println("bar2.getParent() is the same as foo1");
+ final Logger foo2 = Logger.getLogger("foo");
+ if (foo1 != foo2) {
+ throw new RuntimeException("foo2 "+foo2+" is not the same as foo1 "+foo1);
+ }
+ System.out.println("foo2 is the same as foo1");
+
+ System.out.println("Test passed.");
+ }
+}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestScenario.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestScenario.java Sat Sep 14 20:43:34 2013 +0100
@@ -40,7 +40,7 @@
@SuppressWarnings({"rawtypes", "unchecked"})
public enum DoubleStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
- STREAM_FOR_EACH(false) {
+ STREAM_FOR_EACH_WITH_CLOSE(false) {
<T, S_IN extends BaseStream<T, S_IN>>
void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
DoubleStream s = m.apply(data.stream());
@@ -48,6 +48,7 @@
s = s.sequential();
}
s.forEach(b);
+ s.close();
}
},
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/IntStreamTestScenario.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/stream/bootlib/java/util/stream/IntStreamTestScenario.java Sat Sep 14 20:43:34 2013 +0100
@@ -40,7 +40,7 @@
@SuppressWarnings({"rawtypes", "unchecked"})
public enum IntStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
- STREAM_FOR_EACH(false) {
+ STREAM_FOR_EACH_WITH_CLOSE(false) {
<T, S_IN extends BaseStream<T, S_IN>>
void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
IntStream s = m.apply(data.stream());
@@ -48,6 +48,7 @@
s = s.sequential();
}
s.forEach(b);
+ s.close();
}
},
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/LongStreamTestScenario.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/stream/bootlib/java/util/stream/LongStreamTestScenario.java Sat Sep 14 20:43:34 2013 +0100
@@ -40,7 +40,7 @@
@SuppressWarnings({"rawtypes", "unchecked"})
public enum LongStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
- STREAM_FOR_EACH(false) {
+ STREAM_FOR_EACH_WITH_CLOSE(false) {
<T, S_IN extends BaseStream<T, S_IN>>
void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
LongStream s = m.apply(data.stream());
@@ -48,6 +48,7 @@
s = s.sequential();
}
s.forEach(b);
+ s.close();
}
},
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/StreamTestScenario.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/java/util/stream/bootlib/java/util/stream/StreamTestScenario.java Sat Sep 14 20:43:34 2013 +0100
@@ -39,7 +39,7 @@
@SuppressWarnings({"rawtypes", "unchecked"})
public enum StreamTestScenario implements OpTestCase.BaseStreamTestScenario {
- STREAM_FOR_EACH(false) {
+ STREAM_FOR_EACH_WITH_CLOSE(false) {
<T, U, S_IN extends BaseStream<T, S_IN>>
void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
Stream<U> s = m.apply(data.stream());
@@ -47,6 +47,7 @@
s = s.sequential();
}
s.forEach(b);
+ s.close();
}
},
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamCloseTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,166 @@
+/*
+ * 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 org.openjdk.tests.java.util.stream;
+
+import java.util.Arrays;
+import java.util.stream.OpTestCase;
+import java.util.stream.Stream;
+
+import org.testng.annotations.Test;
+
+import static java.util.stream.LambdaTestHelpers.countTo;
+
+/**
+ * StreamCloseTest
+ *
+ * @author Brian Goetz
+ */
+@Test(groups = { "serialization-hostile" })
+public class StreamCloseTest extends OpTestCase {
+ public void testEmptyCloseHandler() {
+ try (Stream<Integer> ints = countTo(100).stream()) {
+ ints.forEach(i -> {});
+ }
+ }
+
+ public void testOneCloseHandler() {
+ final boolean[] holder = new boolean[1];
+ Runnable closer = () -> { holder[0] = true; };
+
+ try (Stream<Integer> ints = countTo(100).stream()) {
+ ints.onClose(closer);
+ ints.forEach(i -> {});
+ }
+ assertTrue(holder[0]);
+
+ Arrays.fill(holder, false);
+ try (Stream<Integer> ints = countTo(100).stream().onClose(closer)) {
+ ints.forEach(i -> {});
+ }
+ assertTrue(holder[0]);
+
+ Arrays.fill(holder, false);
+ try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(closer)) {
+ ints.forEach(i -> {});
+ }
+ assertTrue(holder[0]);
+
+ Arrays.fill(holder, false);
+ try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(closer).filter(e -> true)) {
+ ints.forEach(i -> {});
+ }
+ assertTrue(holder[0]);
+ }
+
+ public void testTwoCloseHandlers() {
+ final boolean[] holder = new boolean[2];
+ Runnable close1 = () -> { holder[0] = true; };
+ Runnable close2 = () -> { holder[1] = true; };
+
+ try (Stream<Integer> ints = countTo(100).stream()) {
+ ints.onClose(close1).onClose(close2);
+ ints.forEach(i -> {});
+ }
+ assertTrue(holder[0] && holder[1]);
+
+ Arrays.fill(holder, false);
+ try (Stream<Integer> ints = countTo(100).stream().onClose(close1).onClose(close2)) {
+ ints.forEach(i -> {});
+ }
+ assertTrue(holder[0] && holder[1]);
+
+ Arrays.fill(holder, false);
+ try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(close1).onClose(close2)) {
+ ints.forEach(i -> {});
+ }
+ assertTrue(holder[0] && holder[1]);
+
+ Arrays.fill(holder, false);
+ try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(close1).onClose(close2).filter(e -> true)) {
+ ints.forEach(i -> {});
+ }
+ assertTrue(holder[0] && holder[1]);
+ }
+
+ public void testCascadedExceptions() {
+ final boolean[] holder = new boolean[3];
+ boolean caught = false;
+ Runnable close1 = () -> { holder[0] = true; throw new RuntimeException("1"); };
+ Runnable close2 = () -> { holder[1] = true; throw new RuntimeException("2"); };
+ Runnable close3 = () -> { holder[2] = true; throw new RuntimeException("3"); };
+
+ try (Stream<Integer> ints = countTo(100).stream()) {
+ ints.onClose(close1).onClose(close2).onClose(close3);
+ ints.forEach(i -> {});
+ }
+ catch (RuntimeException e) {
+ assertCascaded(e, 3);
+ assertTrue(holder[0] && holder[1] && holder[2]);
+ caught = true;
+ }
+ assertTrue(caught);
+
+ Arrays.fill(holder, false);
+ caught = false;
+ try (Stream<Integer> ints = countTo(100).stream().onClose(close1).onClose(close2).onClose(close3)) {
+ ints.forEach(i -> {});
+ }
+ catch (RuntimeException e) {
+ assertCascaded(e, 3);
+ assertTrue(holder[0] && holder[1] && holder[2]);
+ caught = true;
+ }
+ assertTrue(caught);
+
+ caught = false;
+ Arrays.fill(holder, false);
+ try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(close1).onClose(close2).onClose(close3)) {
+ ints.forEach(i -> {});
+ }
+ catch (RuntimeException e) {
+ assertCascaded(e, 3);
+ assertTrue(holder[0] && holder[1] && holder[2]);
+ caught = true;
+ }
+ assertTrue(caught);
+
+ caught = false;
+ Arrays.fill(holder, false);
+ try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(close1).onClose(close2).filter(e -> true).onClose(close3)) {
+ ints.forEach(i -> {});
+ }
+ catch (RuntimeException e) {
+ assertCascaded(e, 3);
+ assertTrue(holder[0] && holder[1] && holder[2]);
+ caught = true;
+ }
+ assertTrue(caught);
+ }
+
+ private void assertCascaded(RuntimeException e, int n) {
+ assertTrue(e.getMessage().equals("1"));
+ assertTrue(e.getSuppressed().length == n - 1);
+ for (int i=0; i<n-1; i++)
+ assertTrue(e.getSuppressed()[i].getMessage().equals(String.valueOf(i + 2)));
+ }
+}
--- a/jdk/test/javax/imageio/plugins/jpeg/JpegWriterLeakTest.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/javax/imageio/plugins/jpeg/JpegWriterLeakTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -23,7 +23,7 @@
/**
* @test
- * @bug 8020983
+ * @bug 8020983 8024697
* @summary Test verifies that jpeg writer instances are collected
* even if destroy() or reset() methods is not invoked.
*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/MBeanInfo/MBeanInfoHashCodeNPETest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanConstructorInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.modelmbean.DescriptorSupport;
+import javax.management.openmbean.SimpleType;
+
+/*
+ * @test
+ * @bug 8023669
+ * @summary Test that hashCode()throws NullPointerException
+ * @author Shanliang JIANG
+ * @run clean MBeanInfoHashCodeNPETest
+ * @run build MBeanInfoHashCodeNPETest
+ * @run main MBeanInfoHashCodeNPETest
+ */
+public class MBeanInfoHashCodeNPETest {
+ private static int failed = 0;
+
+ public static void main(String[] args) throws Exception {
+ System.out.println("---MBeanInfoHashCodeNPETest-main ...");
+
+ // ----
+ System.out.println("\n---Testing on MBeanAttributeInfo...");
+ MBeanAttributeInfo mbeanAttributeInfo = new MBeanAttributeInfo(
+ null, SimpleType.INTEGER.getClassName(), "description", true, true, false);
+ test(mbeanAttributeInfo, "class name");
+
+ mbeanAttributeInfo = new MBeanAttributeInfo(
+ "name", null, "description", true, true, false);
+ test(mbeanAttributeInfo, "type");
+
+ mbeanAttributeInfo = new MBeanAttributeInfo(
+ "name", SimpleType.INTEGER.getClassName(), null, true, true, false);
+ test(mbeanAttributeInfo, "description");
+
+ // ----
+ System.out.println("\n---Testing on MBeanConstructorInfo...");
+ MBeanConstructorInfo mbeanConstructorInfo = new MBeanConstructorInfo(
+ null, "", new MBeanParameterInfo[]{}, new DescriptorSupport());
+ test(mbeanConstructorInfo, "name");
+
+ mbeanConstructorInfo = new MBeanConstructorInfo(
+ "", null, new MBeanParameterInfo[]{}, new DescriptorSupport());
+ test(mbeanConstructorInfo, "description");
+
+ mbeanConstructorInfo = new MBeanConstructorInfo(
+ "", "", null, new DescriptorSupport());
+ test(mbeanConstructorInfo, "MBeanParameterInfo");
+
+ mbeanConstructorInfo = new MBeanConstructorInfo(
+ "", "", new MBeanParameterInfo[]{}, null);
+ test(mbeanConstructorInfo, "descriptor");
+
+ // ----
+ System.out.println("\n---Testing on MBeanOperationInfo...");
+ MBeanOperationInfo mbeanOperationInfo = new MBeanOperationInfo(
+ null, "description", new MBeanParameterInfo[]{}, "type", 1, new DescriptorSupport());
+ test(mbeanOperationInfo, "name");
+
+ mbeanOperationInfo = new MBeanOperationInfo(
+ "name", null, new MBeanParameterInfo[]{}, "type", 1, new DescriptorSupport());
+ test(mbeanOperationInfo, "description");
+
+ mbeanOperationInfo = new MBeanOperationInfo(
+ "name", "description", null, "type", 1, new DescriptorSupport());
+ test(mbeanOperationInfo, "MBeanParameterInfo");
+
+ mbeanOperationInfo = new MBeanOperationInfo(
+ "name", "description", new MBeanParameterInfo[]{}, null, 1, new DescriptorSupport());
+ test(mbeanOperationInfo, "type");
+
+ mbeanOperationInfo = new MBeanOperationInfo(
+ "name", "description", new MBeanParameterInfo[]{}, "type", -1, new DescriptorSupport());
+ test(mbeanOperationInfo, "native impact");
+
+ mbeanOperationInfo = new MBeanOperationInfo(
+ "name", "description", new MBeanParameterInfo[]{}, "type", 1, null);
+ test(mbeanOperationInfo, "Descriptor");
+
+ // ----
+ System.out.println("\n---Testing on MBeanParameterInfo...");
+ MBeanParameterInfo mbeanParameterInfo = new MBeanParameterInfo(
+ null, "type", "description", new DescriptorSupport());
+ test(mbeanParameterInfo, "name");
+
+ mbeanParameterInfo = new MBeanParameterInfo(
+ "name", null, "description", new DescriptorSupport());
+ test(mbeanParameterInfo, "description");
+
+ mbeanParameterInfo = new MBeanParameterInfo(
+ "name", "type", null, new DescriptorSupport());
+ test(mbeanParameterInfo, "description");
+
+ mbeanParameterInfo = new MBeanParameterInfo(
+ "name", "type", "description", null);
+ test(mbeanParameterInfo, "Descriptor");
+
+ // ----
+ System.out.println("\n---Testing on MBeanInfo...");
+ String className = "toto";
+ String description = "titi";
+ MBeanAttributeInfo[] attrInfos = new MBeanAttributeInfo[]{};
+ MBeanConstructorInfo[] constrInfos = new MBeanConstructorInfo[]{};
+ MBeanOperationInfo[] operaInfos = new MBeanOperationInfo[]{};
+ MBeanNotificationInfo[] notifInfos = new MBeanNotificationInfo[]{};
+
+ MBeanInfo minfo = new MBeanInfo(null, description, attrInfos, constrInfos, operaInfos, notifInfos);
+ test(minfo, "class name");
+
+ minfo = new MBeanInfo(className, description, attrInfos, constrInfos, operaInfos, notifInfos);
+ test(minfo, "name");
+
+ minfo = new MBeanInfo(className, null, attrInfos, constrInfos, operaInfos, notifInfos);
+ test(minfo, "description");
+
+ minfo = new MBeanInfo(className, description, null, constrInfos, operaInfos, notifInfos);
+ test(minfo, "attrInfos");
+
+ minfo = new MBeanInfo(className, description, attrInfos, constrInfos, null, notifInfos);
+ test(minfo, "operaInfos");
+
+ minfo = new MBeanInfo(className, description, attrInfos, constrInfos, operaInfos, null);
+ test(minfo, "notifInfos");
+
+ Thread.sleep(100);
+ if (failed > 0) {
+ throw new RuntimeException("Test failed: "+failed);
+ } else {
+ System.out.println("---Test: PASSED");
+ }
+ }
+
+ private static void test(Object obj, String param) {
+ try {
+ obj.hashCode();
+ System.out.println("OK: "+obj.getClass().getSimpleName()+".hashCode worked with a null "+param);
+ } catch (NullPointerException npe) {
+ System.out.println("--->KO!!! "+obj.getClass().getSimpleName()+".hashCode got NPE with a null "+param);
+ failed++;
+ }
+
+ try {
+ obj.toString();
+ System.out.println("OK: "+obj.getClass().getSimpleName()+".toString worked with a null "+param);
+ } catch (NullPointerException npe) {
+ System.out.println("--->KO!!! "+obj.getClass().getSimpleName()+".toString got NPE.");
+ failed++;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/openmbean/OpenMBeanInfoEqualsNPETest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.modelmbean.DescriptorSupport;
+import javax.management.openmbean.OpenMBeanAttributeInfo;
+import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
+import javax.management.openmbean.OpenMBeanConstructorInfo;
+import javax.management.openmbean.OpenMBeanConstructorInfoSupport;
+import javax.management.openmbean.OpenMBeanInfo;
+import javax.management.openmbean.OpenMBeanInfoSupport;
+import javax.management.openmbean.OpenMBeanOperationInfo;
+import javax.management.openmbean.OpenMBeanOperationInfoSupport;
+import javax.management.openmbean.OpenMBeanParameterInfo;
+import javax.management.openmbean.OpenMBeanParameterInfoSupport;
+import javax.management.openmbean.SimpleType;
+
+/*
+ * @test
+ * @bug 8023529
+ * @summary Test that OpenMBean*Info.equals do not throw NPE
+ * @author Shanliang JIANG
+ * @run clean OpenMBeanInfoEqualsNPETest
+ * @run build OpenMBeanInfoEqualsNPETest
+ * @run main OpenMBeanInfoEqualsNPETest
+ */
+public class OpenMBeanInfoEqualsNPETest {
+ private static int failed = 0;
+
+ public static void main(String[] args) throws Exception {
+ System.out.println("---OpenMBeanInfoEqualsNPETest-main ...");
+
+ // ----
+ System.out.println("\n---Testing on OpenMBeanAttributeInfoSupport...");
+ OpenMBeanAttributeInfo openMBeanAttributeInfo0 = new OpenMBeanAttributeInfoSupport(
+ "name", "description", SimpleType.INTEGER, true, true, false, 1, new Integer[]{1, 2, 3});
+ OpenMBeanAttributeInfo openMBeanAttributeInfo = new OpenMBeanAttributeInfoSupport(
+ "name", "description", SimpleType.INTEGER, true, true, false, null, new Integer[]{1, 2, 3});
+ test(openMBeanAttributeInfo0, openMBeanAttributeInfo, "defaultValue");
+
+ openMBeanAttributeInfo = new OpenMBeanAttributeInfoSupport(
+ "name", "description", SimpleType.INTEGER, true, true, false, 1, null);
+ test(openMBeanAttributeInfo0, openMBeanAttributeInfo, "legalValues");
+
+ // ----
+ System.out.println("\n---Testing on OpenMBeanConstructorInfoSupport...");
+ OpenMBeanConstructorInfo openMBeanConstructorInfo0 = new OpenMBeanConstructorInfoSupport(
+ "name", "description", new OpenMBeanParameterInfo[]{}, new DescriptorSupport());
+ OpenMBeanConstructorInfo openMBeanConstructorInfo;
+
+ openMBeanConstructorInfo = new OpenMBeanConstructorInfoSupport(
+ "name", "description", null, new DescriptorSupport());
+ test(openMBeanConstructorInfo0, openMBeanConstructorInfo, "sigs");
+
+ openMBeanConstructorInfo = new OpenMBeanConstructorInfoSupport(
+ "name", "description", new OpenMBeanParameterInfo[]{}, null);
+ test(openMBeanConstructorInfo0, openMBeanConstructorInfo, "Descriptor");
+
+ // ----
+ System.out.println("\n---Testing on OpenMBeanOperationInfoSupport...");
+ OpenMBeanOperationInfo openMBeanOperationInfo0 = new OpenMBeanOperationInfoSupport(
+ "name", "description", new OpenMBeanParameterInfo[]{}, SimpleType.INTEGER, 1, new DescriptorSupport());
+ OpenMBeanOperationInfo openMBeanOperationInfo;
+
+ openMBeanOperationInfo = new OpenMBeanOperationInfoSupport(
+ "name", "description", null, SimpleType.INTEGER, 1, new DescriptorSupport());
+ test(openMBeanOperationInfo0, openMBeanOperationInfo, "sigs");
+
+ openMBeanOperationInfo = new OpenMBeanOperationInfoSupport(
+ "name", "description", new OpenMBeanParameterInfo[]{}, SimpleType.INTEGER, MBeanOperationInfo.UNKNOWN, null);
+ test(openMBeanOperationInfo0, openMBeanOperationInfo, "Descriptor");
+
+ // ----
+ System.out.println("\n---Testing on OpenMBeanParameterInfoSupport 1...");
+ OpenMBeanParameterInfo openMBeanParameterInfo0 = new OpenMBeanParameterInfoSupport(
+ "name", "description", SimpleType.INTEGER, 0, -1, 1);
+ OpenMBeanParameterInfo openMBeanParameterInfo;
+
+ openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+ "name", "description", SimpleType.INTEGER, null, -1, 1);
+ test(openMBeanParameterInfo0, openMBeanParameterInfo, "default value");
+
+ openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+ "name", "description", SimpleType.INTEGER, 0, null, 1);
+ test(openMBeanParameterInfo0, openMBeanParameterInfo, "min value");
+
+ openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+ "name", "description", SimpleType.INTEGER, 0, -1, null);
+ test(openMBeanParameterInfo0, openMBeanParameterInfo, "max value");
+
+ // ----
+ System.out.println("\n---Testing on OpenMBeanParameterInfoSupport 2...");
+ openMBeanParameterInfo0 = new OpenMBeanParameterInfoSupport(
+ "name", "description", SimpleType.INTEGER, 1, new Integer[]{-1, 1, 2});
+
+ openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+ "name", "description", SimpleType.INTEGER, null, new Integer[]{-1, 1, 2});
+ test(openMBeanParameterInfo0, openMBeanParameterInfo, "default value");
+
+ openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+ "name", "description", SimpleType.INTEGER, 1, null);
+ test(openMBeanParameterInfo0, openMBeanParameterInfo, "legal values");
+
+ // ----
+ System.out.println("\n---Testing on OpenMBeanInfoSupport...");
+ String className = "toto";
+ String description = "titi";
+ OpenMBeanAttributeInfo[] attrInfos = new OpenMBeanAttributeInfo[]{};
+ OpenMBeanConstructorInfo[] constrInfos = new OpenMBeanConstructorInfo[]{};
+ OpenMBeanOperationInfo[] operaInfos = new OpenMBeanOperationInfo[]{};
+ MBeanNotificationInfo[] notifInfos = new MBeanNotificationInfo[]{};
+
+ OpenMBeanInfo ominfo0 = new OpenMBeanInfoSupport("toto", description, attrInfos, constrInfos, operaInfos, notifInfos);
+ OpenMBeanInfo ominfo = new OpenMBeanInfoSupport(null, description, attrInfos, constrInfos, operaInfos, notifInfos);
+ test(ominfo0, ominfo, "class name");
+
+ ominfo = new OpenMBeanInfoSupport(className, null, attrInfos, constrInfos, operaInfos, notifInfos);
+ test(ominfo0, ominfo, "description");
+
+ ominfo = new OpenMBeanInfoSupport(className, description, null, constrInfos, operaInfos, notifInfos);
+ test(ominfo0, ominfo, "attrInfos");
+
+ ominfo = new OpenMBeanInfoSupport(className, description, attrInfos, null, operaInfos, notifInfos);
+ test(ominfo0, ominfo, "constructor infos");
+
+ ominfo = new OpenMBeanInfoSupport(className, description, attrInfos, constrInfos, null, notifInfos);
+ test(ominfo0, ominfo, "operation infos");
+
+ ominfo = new OpenMBeanInfoSupport(className, description, attrInfos, constrInfos, operaInfos, null);
+ test(ominfo0, ominfo, "notif infos");
+
+ if (failed > 0) {
+ throw new RuntimeException("Test failed: "+failed);
+ } else {
+ System.out.println("---Test: PASSED");
+ }
+ }
+
+ private static void test(Object obj1, Object obj2, String param) {
+ try {
+ obj1.equals(obj2);
+ System.out.println("OK-1: "+obj1.getClass().getSimpleName()+
+ ".equals worked with a null field: "+param);
+ } catch (NullPointerException npe) {
+ System.out.println("--->KO-1!!! "+obj1.getClass().getSimpleName()+
+ ".equals got NPE with a null field: "+param);
+ npe.printStackTrace();
+ failed++;
+ }
+
+ try {
+ obj2.equals(obj1);
+ System.out.println("OK-2: "+obj2.getClass().getSimpleName()+
+ ".equals worked with a null field: "+param);
+ } catch (NullPointerException npe) {
+ System.out.println("--->KO-2!!! "+obj2.getClass().getSimpleName()+
+ ".equals got NPE with a null field: "+param);
+ npe.printStackTrace();
+ failed++;
+ }
+
+ try {
+ obj1.equals(null);
+ obj2.equals(null);
+
+ System.out.println("OK-3: "+obj1.getClass().getSimpleName()+
+ ".equals worked with a null object.");
+ } catch (NullPointerException npe) {
+ System.out.println("--->KO-3!!! "+obj1.getClass().getSimpleName()+
+ ".equals got NPE with a null object.");
+ npe.printStackTrace();
+ failed++;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/openmbean/OpenMBeanInfoHashCodeNPETest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+import javax.management.MBeanNotificationInfo;
+import javax.management.modelmbean.DescriptorSupport;
+import javax.management.openmbean.OpenMBeanAttributeInfo;
+import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
+import javax.management.openmbean.OpenMBeanConstructorInfo;
+import javax.management.openmbean.OpenMBeanConstructorInfoSupport;
+import javax.management.openmbean.OpenMBeanInfo;
+import javax.management.openmbean.OpenMBeanInfoSupport;
+import javax.management.openmbean.OpenMBeanOperationInfo;
+import javax.management.openmbean.OpenMBeanOperationInfoSupport;
+import javax.management.openmbean.OpenMBeanParameterInfo;
+import javax.management.openmbean.OpenMBeanParameterInfoSupport;
+import javax.management.openmbean.SimpleType;
+
+/*
+ * @test
+ * @bug 8023529
+ * @summary Test that OpenMBean*Info.hashCode do not throw NPE
+ * @author Shanliang JIANG
+ * @run clean OpenMBeanInfoHashCodeNPETest
+ * @run build OpenMBeanInfoHashCodeNPETest
+ * @run main OpenMBeanInfoHashCodeNPETest
+ */
+public class OpenMBeanInfoHashCodeNPETest {
+ private static int failed = 0;
+
+ public static void main(String[] args) throws Exception {
+ System.out.println("---OpenMBeanInfoHashCodeNPETest-main ...");
+
+ // ----
+ System.out.println("\n---Testing on OpenMBeanInfohashCodeTest...");
+ OpenMBeanAttributeInfo openMBeanAttributeInfo = new OpenMBeanAttributeInfoSupport(
+ "name", "description", SimpleType.INTEGER, true, true, false, null, new Integer[]{1, 2, 3});
+ test(openMBeanAttributeInfo, "defaultValue");
+
+ openMBeanAttributeInfo = new OpenMBeanAttributeInfoSupport(
+ "name", "description", SimpleType.INTEGER, true, true, false, 1, null);
+ test(openMBeanAttributeInfo, "legalValues");
+
+ // ----
+ System.out.println("\n---Testing on OpenMBeanConstructorInfoSupport...");
+ OpenMBeanConstructorInfo openMBeanConstructorInfo;
+
+ openMBeanConstructorInfo = new OpenMBeanConstructorInfoSupport(
+ "name", "description", null, new DescriptorSupport());
+ test(openMBeanConstructorInfo, "sigs");
+
+ openMBeanConstructorInfo = new OpenMBeanConstructorInfoSupport(
+ "name", "description", new OpenMBeanParameterInfo[]{}, null);
+ test(openMBeanConstructorInfo, "Descriptor");
+
+ // ----
+ System.out.println("\n---Testing on OpenMBeanOperationInfoSupport...");
+ OpenMBeanOperationInfo openMBeanOperationInfo;
+
+ openMBeanOperationInfo = new OpenMBeanOperationInfoSupport(
+ "name", "description", null, SimpleType.INTEGER, 1, new DescriptorSupport());
+ test(openMBeanOperationInfo, "sigs");
+
+ openMBeanOperationInfo = new OpenMBeanOperationInfoSupport(
+ "name", "description", new OpenMBeanParameterInfo[]{}, SimpleType.INTEGER, 1, null);
+ test(openMBeanOperationInfo, "Descriptor");
+
+ // ----
+ System.out.println("\n---Testing on OpenMBeanParameterInfoSupport 1...");
+ OpenMBeanParameterInfo openMBeanParameterInfo;
+
+ openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+ "name", "description", SimpleType.INTEGER, null, -1, 1);
+ test(openMBeanParameterInfo, "default value");
+
+ openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+ "name", "description", SimpleType.INTEGER, 0, null, 1);
+ test(openMBeanParameterInfo, "min value");
+
+ openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+ "name", "description", SimpleType.INTEGER, 0, -1, null);
+ test(openMBeanParameterInfo, "max value");
+
+ // ----
+ System.out.println("\n---Testing on OpenMBeanParameterInfoSupport 2...");
+ openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+ "name", "description", SimpleType.INTEGER, 1, new Integer[]{-1, 1, 2});
+
+ openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+ "name", "description", SimpleType.INTEGER, null, new Integer[]{-1, 1, 2});
+ test(openMBeanParameterInfo, "default value");
+
+ openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+ "name", "description", SimpleType.INTEGER, 1, null);
+ test(openMBeanParameterInfo, "legal values");
+
+ // ----
+ System.out.println("\n---Testing on OpenMBeanInfoSupport...");
+ String className = "toto";
+ String description = "titi";
+ OpenMBeanAttributeInfo[] attrInfos = new OpenMBeanAttributeInfo[]{};
+ OpenMBeanConstructorInfo[] constrInfos = new OpenMBeanConstructorInfo[]{};
+ OpenMBeanOperationInfo[] operaInfos = new OpenMBeanOperationInfo[]{};
+ MBeanNotificationInfo[] notifInfos = new MBeanNotificationInfo[]{};
+
+ OpenMBeanInfo ominfo = new OpenMBeanInfoSupport(null, description, attrInfos, constrInfos, operaInfos, notifInfos);
+ test(ominfo, "class name");
+
+ ominfo = new OpenMBeanInfoSupport(className, null, attrInfos, constrInfos, operaInfos, notifInfos);
+ test(ominfo, "description");
+
+ ominfo = new OpenMBeanInfoSupport(className, description, null, constrInfos, operaInfos, notifInfos);
+ test(ominfo, "attrInfos");
+
+ ominfo = new OpenMBeanInfoSupport(className, description, attrInfos, null, operaInfos, notifInfos);
+ test(ominfo, "constructor infos");
+
+ ominfo = new OpenMBeanInfoSupport(className, description, attrInfos, constrInfos, null, notifInfos);
+ test(ominfo, "operation infos");
+
+ ominfo = new OpenMBeanInfoSupport(className, description, attrInfos, constrInfos, operaInfos, null);
+ test(ominfo, "notif infos");
+
+ if (failed > 0) {
+ throw new RuntimeException("Test failed: "+failed);
+ } else {
+ System.out.println("---Test: PASSED");
+ }
+ }
+
+ private static void test(Object obj, String param) {
+ try {
+ obj.hashCode();
+ System.out.println("OK-1: "+obj.getClass().getSimpleName()+
+ ".hashCode worked with a null paramer: "+param);
+ } catch (NullPointerException npe) {
+ System.out.println("--->KO-1!!! "+obj.getClass().getSimpleName()+
+ ".hashCode got NPE with null paramer: "+param);
+ npe.printStackTrace();
+ failed++;
+ }
+
+ try {
+ obj.toString();
+ System.out.println("OK-1: "+obj.getClass().getSimpleName()+
+ ".toString worked with a null paramer: "+param);
+ } catch (NullPointerException npe) {
+ System.out.println("--->KO-1!!! "+obj.getClass().getSimpleName()+
+ ".toString got NPE with null paramer: "+param);
+ npe.printStackTrace();
+ failed++;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+import java.lang.management.ManagementFactory;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.Map;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXPrincipal;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnector;
+import javax.security.auth.Subject;
+
+/*
+ * @test
+ * @bug 6566891
+ * @summary Check no memory leak on RMIConnector's rmbscMap
+ * @author Shanliang JIANG
+ * @run clean RMIConnectorInternalMapTest
+ * @run build RMIConnectorInternalMapTest
+ * @run main RMIConnectorInternalMapTest
+ */
+
+public class RMIConnectorInternalMapTest {
+ public static void main(String[] args) throws Exception {
+ System.out.println("---RMIConnectorInternalMapTest starting...");
+
+ JMXConnectorServer connectorServer = null;
+ JMXConnector connectorClient = null;
+
+ try {
+ MBeanServer mserver = ManagementFactory.getPlatformMBeanServer();
+ JMXServiceURL serverURL = new JMXServiceURL("rmi", "localhost", 0);
+ connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(serverURL, null, mserver);
+ connectorServer.start();
+
+ JMXServiceURL serverAddr = connectorServer.getAddress();
+ connectorClient = JMXConnectorFactory.connect(serverAddr, null);
+ connectorClient.connect();
+
+ Field rmbscMapField = RMIConnector.class.getDeclaredField("rmbscMap");
+ rmbscMapField.setAccessible(true);
+ Map<Subject, WeakReference<MBeanServerConnection>> map =
+ (Map<Subject, WeakReference<MBeanServerConnection>>) rmbscMapField.get(connectorClient);
+ if (map != null && !map.isEmpty()) { // failed
+ throw new RuntimeException("RMIConnector's rmbscMap must be empty at the initial time.");
+ }
+
+ Subject delegationSubject =
+ new Subject(true,
+ Collections.singleton(new JMXPrincipal("delegate")),
+ Collections.EMPTY_SET,
+ Collections.EMPTY_SET);
+ MBeanServerConnection mbsc1 =
+ connectorClient.getMBeanServerConnection(delegationSubject);
+ MBeanServerConnection mbsc2 =
+ connectorClient.getMBeanServerConnection(delegationSubject);
+
+ if (mbsc1 == null) {
+ throw new RuntimeException("Got null connection.");
+ }
+ if (mbsc1 != mbsc2) {
+ throw new RuntimeException("Not got same connection with a same subject.");
+ }
+
+ map = (Map<Subject, WeakReference<MBeanServerConnection>>) rmbscMapField.get(connectorClient);
+ if (map == null || map.isEmpty()) { // failed
+ throw new RuntimeException("RMIConnector's rmbscMap has wrong size "
+ + "after creating a delegated connection.");
+ }
+
+ delegationSubject = null;
+ mbsc1 = null;
+ mbsc2 = null;
+
+ int i = 0;
+ while (!map.isEmpty() && i++ < 60) {
+ System.gc();
+ Thread.sleep(100);
+ }
+ System.out.println("---GC times: " + i);
+
+ if (!map.isEmpty()) {
+ throw new RuntimeException("Failed to clean RMIConnector's rmbscMap");
+ } else {
+ System.out.println("---RMIConnectorInternalMapTest: PASSED!");
+ }
+ } finally {
+ try {
+ connectorClient.close();
+ connectorServer.stop();
+ } catch (Exception e) {
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+import java.lang.management.ManagementFactory;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnector;
+
+/*
+ * @test
+ * @bug 6566891
+ * @summary Check no memory leak on RMIConnector's nullSubjectConn
+ * @author Shanliang JIANG
+ * @run clean RMIConnectorNullSubjectConnTest
+ * @run build RMIConnectorNullSubjectConnTest
+ * @run main RMIConnectorNullSubjectConnTest
+ */
+
+public class RMIConnectorNullSubjectConnTest {
+ public static void main(String[] args) throws Exception {
+ System.out.println("---RMIConnectorNullSubjectConnTest starting...");
+
+ JMXConnectorServer connectorServer = null;
+ JMXConnector connectorClient = null;
+
+ try {
+ MBeanServer mserver = ManagementFactory.getPlatformMBeanServer();
+ JMXServiceURL serverURL = new JMXServiceURL("rmi", "localhost", 0);
+ connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(serverURL, null, mserver);
+ connectorServer.start();
+
+ JMXServiceURL serverAddr = connectorServer.getAddress();
+ connectorClient = JMXConnectorFactory.connect(serverAddr, null);
+ connectorClient.connect();
+
+ Field nullSubjectConnField = RMIConnector.class.getDeclaredField("nullSubjectConnRef");
+ nullSubjectConnField.setAccessible(true);
+
+ WeakReference<MBeanServerConnection> weak =
+ (WeakReference<MBeanServerConnection>)nullSubjectConnField.get(connectorClient);
+
+ if (weak != null && weak.get() != null) {
+ throw new RuntimeException("nullSubjectConnRef must be null at initial time.");
+ }
+
+ MBeanServerConnection conn1 = connectorClient.getMBeanServerConnection(null);
+ MBeanServerConnection conn2 = connectorClient.getMBeanServerConnection(null);
+ if (conn1 == null) {
+ throw new RuntimeException("A connection with null subject should not be null.");
+ } else if (conn1 != conn2) {
+ throw new RuntimeException("The 2 connections with null subject are not equal.");
+ }
+
+ conn1 = null;
+ conn2 = null;
+ int i = 1;
+ do {
+ System.gc();
+ Thread.sleep(100);
+ weak = (WeakReference<MBeanServerConnection>)nullSubjectConnField.get(connectorClient);
+ } while ((weak != null && weak.get() != null) && i++ < 60);
+
+ System.out.println("---GC times: " + i);
+
+ if (weak != null && weak.get() != null) {
+ throw new RuntimeException("Failed to clean RMIConnector's nullSubjectConn");
+ } else {
+ System.out.println("---RMIConnectorNullSubjectConnTest: PASSED!");
+ }
+ } finally {
+ try {
+ connectorClient.close();
+ connectorServer.stop();
+ } catch (Exception e) {
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/lambda/MethodReferenceTestCallerSensitive.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Field;
+import java.util.function.Function;
+
+
+/**
+ * @author Robert Field
+ */
+
+@Test
+public class MethodReferenceTestCallerSensitive {
+
+ private static <T> void getF(T arg) {
+ Function<Class<T>,Field[]> firstFunction = Class<T>::getFields;
+ }
+
+ public void testConstructorReferenceVarArgs() {
+ getF("Hello World");
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/java2d/cmm/ProfileOp/DisposalCrashTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8024511
+ * @summary Verifies that instances of color profiles are destroyed correctly.
+ * A crash during profile destruction indicates failure.
+ *
+ * @run main DisposalCrashTest
+ */
+
+import static java.awt.color.ColorSpace.*;
+import java.awt.color.ICC_Profile;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.Vector;
+
+public class DisposalCrashTest {
+
+ static final ReferenceQueue<ICC_Profile> queue = new ReferenceQueue<>();
+ static final Vector<Reference<? extends ICC_Profile>> v = new Vector<>();
+
+ public static void main(String[] args) {
+ int[] ids = new int[]{
+ CS_sRGB, CS_CIEXYZ, CS_GRAY, CS_LINEAR_RGB, CS_PYCC
+ };
+
+ for (int id : ids) {
+ ICC_Profile p = getCopyOf(id);
+ }
+
+ while (!v.isEmpty()) {
+ System.gc();
+ System.out.println(".");
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {};
+
+ final Reference<? extends ICC_Profile> ref = queue.poll();
+ System.out.println("Got reference: " + ref);
+
+ v.remove(ref);
+ }
+
+ System.out.println("Test PASSED.");
+ }
+
+ private static ICC_Profile getCopyOf(int id) {
+ ICC_Profile std = ICC_Profile.getInstance(id);
+
+ byte[] data = std.getData();
+
+ ICC_Profile p = ICC_Profile.getInstance(data);
+
+ WeakReference<ICC_Profile> ref = new WeakReference<>(p, queue);
+
+ v.add(ref);
+
+ return p;
+ }
+}
--- a/jdk/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -23,7 +23,7 @@
/**
* @test
- * @bug 6476665 6523403 6733501 7042594
+ * @bug 6476665 6523403 6733501 7042594 7043064
* @summary Verifies reading and writing profiles and tags of the standard color
* spaces
* @run main ReadWriteProfileTest
@@ -82,6 +82,7 @@
public void run() {
for (int i = 0; i < cspaces.length; i++) {
+ System.out.println("Profile: " + csNames[i]);
ICC_Profile pf = ICC_Profile.getInstance(cspaces[i]);
byte [] data = pf.getData();
pf = ICC_Profile.getInstance(data);
@@ -92,6 +93,10 @@
}
for (int tagSig : tags[i].keySet()) {
+ String signature = SigToString(tagSig);
+ System.out.printf("Tag: %s\n", signature);
+ System.out.flush();
+
byte [] tagData = pf.getData(tagSig);
byte [] empty = new byte[tagData.length];
boolean emptyDataRejected = false;
@@ -104,15 +109,23 @@
throw new
RuntimeException("Test failed: empty tag data was not rejected.");
}
- pf.setData(tagSig, tagData);
-
+ try {
+ pf.setData(tagSig, tagData);
+ } catch (IllegalArgumentException e) {
+ // let's ignore this exception for Kodak proprietary tags
+ if (isKodakExtention(signature)) {
+ System.out.println("Ignore Kodak tag: " + signature);
+ } else {
+ throw new RuntimeException("Test failed!", e);
+ }
+ }
byte [] tagData1 = pf.getData(tagSig);
if (!Arrays.equals(tagData1, tags[i].get(tagSig)))
{
System.err.println("Incorrect result of getData(int) with" +
" tag " +
- Integer.toHexString(tagSig) +
+ SigToString(tagSig) +
" of " + csNames[i] + " profile");
throw new RuntimeException("Incorrect result of " +
@@ -122,6 +135,19 @@
}
}
+ private static boolean isKodakExtention(String signature) {
+ return signature.matches("K\\d\\d\\d");
+ }
+
+ private static String SigToString(int tagSig ) {
+ return String.format("%c%c%c%c",
+ (char)(0xff & (tagSig >> 24)),
+ (char)(0xff & (tagSig >> 16)),
+ (char)(0xff & (tagSig >> 8)),
+ (char)(0xff & (tagSig)));
+
+ }
+
public static void main(String [] args) {
ReadWriteProfileTest test = new ReadWriteProfileTest();
test.run();
--- a/jdk/test/sun/security/krb5/runNameEquals.sh Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/sun/security/krb5/runNameEquals.sh Sat Sep 14 20:43:34 2013 +0100
@@ -22,7 +22,7 @@
#
# @test
-# @bug 6317711 6944847
+# @bug 6317711 6944847 8024046
# @summary Ensure the GSSName has the correct impl which respects
# the contract for equals and hashCode across different configurations.
@@ -56,6 +56,15 @@
PATHSEP=":"
FILESEP="/"
NATIVE=true
+ # Not all *nix has native GSS libs installed
+ krb5-config --libs gssapi 2> /dev/null
+ if [ $? != 0 ]; then
+ # Fedora has a different path
+ /usr/kerberos/bin/krb5-config --libs gssapi 2> /dev/null
+ if [ $? != 0 ]; then
+ NATIVE=false
+ fi
+ fi
;;
CYGWIN* )
PATHSEP=";"
--- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/CloseEngineException.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/CloseEngineException.java Sat Sep 14 20:43:34 2013 +0100
@@ -21,17 +21,24 @@
* questions.
*/
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
/*
* @test
* @bug 4969799
* @summary javax.net.ssl.SSLSocket.SSLSocket(InetAddress,int) shouldn't
* throw exception
- *
- * This is making sure that starting a new handshake throws the right
- * exception. There is a similar test for SSLSocket.
- *
+ * @run main/othervm CloseEngineException
*/
+//
+// This is making sure that starting a new handshake throws the right
+// exception. There is a similar test for SSLSocket.
+//
+
import javax.net.ssl.*;
import javax.net.ssl.SSLEngineResult.*;
import java.io.*;
--- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/CloseInboundException.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/CloseInboundException.java Sat Sep 14 20:43:34 2013 +0100
@@ -21,11 +21,17 @@
* questions.
*/
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
/*
* @test
* @bug 4931274
* @summary closeInbound does not signal when a close_notify has not
* been received.
+ * @run main/othervm CloseInboundException
* @author Brad Wetmore
*/
--- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/CloseStart.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/CloseStart.java Sat Sep 14 20:43:34 2013 +0100
@@ -21,15 +21,22 @@
* questions.
*/
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
/*
* @test
* @bug 5019096
* @summary Add scatter/gather APIs for SSLEngine
- *
- * Check to see if the args are being parsed properly.
- *
+ * @run main/othervm CloseStart
*/
+//
+// Check to see if the args are being parsed properly.
+//
+
import javax.net.ssl.*;
import javax.net.ssl.SSLEngineResult.*;
import java.io.*;
--- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/DelegatedTaskWrongException.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/DelegatedTaskWrongException.java Sat Sep 14 20:43:34 2013 +0100
@@ -21,11 +21,16 @@
* questions.
*/
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
/*
* @test
* @bug 4969459
* @summary Delegated tasks are not reflecting the subclasses of SSLException
- *
+ * @run main/othervm DelegatedTaskWrongException
*/
import javax.net.ssl.*;
--- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/EmptyExtensionData.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/EmptyExtensionData.java Sat Sep 14 20:43:34 2013 +0100
@@ -21,10 +21,16 @@
* questions.
*/
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
/*
* @test
* @bug 6728126
* @summary Parsing Extensions in Client Hello message is done in a wrong way
+ * @run main/othervm EmptyExtensionData
*/
import javax.net.ssl.*;
--- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/EngineEnforceUseClientMode.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/EngineEnforceUseClientMode.java Sat Sep 14 20:43:34 2013 +0100
@@ -21,11 +21,16 @@
* questions.
*/
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
/*
* @test
* @bug 4980882
* @summary SSLEngine should enforce setUseClientMode
- *
+ * @run main/othervm EngineEnforceUseClientMode
* @author Brad R. Wetmore
*/
--- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/RehandshakeFinished.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/RehandshakeFinished.java Sat Sep 14 20:43:34 2013 +0100
@@ -21,16 +21,21 @@
* questions.
*/
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
/*
* @test
* @bug 6207322
* @summary SSLEngine is returning a premature FINISHED message when doing
- * an abbreviated handshake.
+ * an abbreviated handshake.
* @run main/othervm RehandshakeFinished
- *
- * SunJSSE does not support dynamic system properties, no way to re-use
- * system properties in samevm/agentvm mode.
- *
+ * @author Brad Wetmore
+ */
+
+/*
* This test may need some updating if the messages change order.
* Currently I'm expecting that there is a simple renegotiation, with
* each message being contained in a single SSL packet.
@@ -41,8 +46,6 @@
* FINISHED
* CCS
* FINISHED
- *
- * @author Brad Wetmore
*/
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/ssl/javax/net/ssl/SSLParameters/UseCipherSuitesOrder.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,357 @@
+/*
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 7188657
+ * @summary There should be a way to reorder the JSSE ciphers
+ * @run main/othervm UseCipherSuitesOrder
+ * TLS_RSA_WITH_AES_128_CBC_SHA,SSL_RSA_WITH_RC4_128_SHA
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+import java.util.Arrays;
+
+public class UseCipherSuitesOrder {
+
+ /*
+ * =============================================================
+ * Set the various variables needed for the tests, then
+ * specify what tests to run on each side.
+ */
+
+ /*
+ * Should we run the client or server in a separate thread?
+ * Both sides can throw exceptions, but do you have a preference
+ * as to which side should be the main thread.
+ */
+ static boolean separateServerThread = false;
+
+ /*
+ * Where do we find the keystores?
+ */
+ static String pathToStores = "../../../../etc";
+ static String keyStoreFile = "keystore";
+ static String trustStoreFile = "truststore";
+ static String passwd = "passphrase";
+
+ /*
+ * Is the server ready to serve?
+ */
+ volatile static boolean serverReady = false;
+
+ /*
+ * Turn on SSL debugging?
+ */
+ static boolean debug = false;
+
+ /*
+ * If the client or server is doing some kind of object creation
+ * that the other side depends on, and that thread prematurely
+ * exits, you may experience a hang. The test harness will
+ * terminate all hung threads after its timeout has expired,
+ * currently 3 minutes by default, but you might try to be
+ * smart about it....
+ */
+
+ /*
+ * Define the server side of the test.
+ *
+ * If the server prematurely exits, serverReady will be set to true
+ * to avoid infinite hangs.
+ */
+ void doServerSide() throws Exception {
+ SSLServerSocketFactory sslssf =
+ (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+ SSLServerSocket sslServerSocket =
+ (SSLServerSocket) sslssf.createServerSocket(serverPort);
+ serverPort = sslServerSocket.getLocalPort();
+
+ // use local cipher suites preference
+ SSLParameters params = sslServerSocket.getSSLParameters();
+ params.setUseCipherSuitesOrder(true);
+ params.setCipherSuites(srvEnabledCipherSuites);
+ sslServerSocket.setSSLParameters(params);
+
+ /*
+ * Signal Client, we're ready for his connect.
+ */
+ serverReady = true;
+
+ SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+ InputStream sslIS = sslSocket.getInputStream();
+ OutputStream sslOS = sslSocket.getOutputStream();
+
+ sslIS.read();
+ sslOS.write(85);
+ sslOS.flush();
+
+ SSLSession session = sslSocket.getSession();
+ if (!srvEnabledCipherSuites[0].equals(session.getCipherSuite())) {
+ throw new Exception(
+ "Expected to negotiate " + srvEnabledCipherSuites[0] +
+ " , but not " + session.getCipherSuite());
+ }
+
+ sslSocket.close();
+ }
+
+ /*
+ * Define the client side of the test.
+ *
+ * If the server prematurely exits, serverReady will be set to true
+ * to avoid infinite hangs.
+ */
+ void doClientSide() throws Exception {
+
+ /*
+ * Wait for server to get started.
+ */
+ while (!serverReady) {
+ Thread.sleep(50);
+ }
+
+ SSLSocketFactory sslsf =
+ (SSLSocketFactory) SSLSocketFactory.getDefault();
+ SSLSocket sslSocket = (SSLSocket)
+ sslsf.createSocket("localhost", serverPort);
+ sslSocket.setEnabledCipherSuites(cliEnabledCipherSuites);
+
+ InputStream sslIS = sslSocket.getInputStream();
+ OutputStream sslOS = sslSocket.getOutputStream();
+
+ sslOS.write(280);
+ sslOS.flush();
+ sslIS.read();
+
+ sslSocket.close();
+ }
+
+ // client enabled cipher suites
+ private static String[] cliEnabledCipherSuites;
+
+ // server enabled cipher suites
+ private static String[] srvEnabledCipherSuites;
+
+ private static void parseArguments(String[] args) throws Exception {
+ if (args.length != 1) {
+ System.out.println("Usage: java UseCipherSuitesOrder ciphersuites");
+ System.out.println("\tciphersuites: " +
+ "a list of enabled cipher suites, separated with comma");
+ throw new Exception("Incorrect usage");
+ }
+
+ cliEnabledCipherSuites = args[0].split(",");
+
+ if (cliEnabledCipherSuites.length < 2) {
+ throw new Exception("Need to enable at least two cipher suites");
+ }
+
+ // Only need to use 2 cipher suites in server side.
+ srvEnabledCipherSuites = Arrays.<String>copyOf(
+ cliEnabledCipherSuites, 2);
+
+ // Reverse the cipher suite preference in server side.
+ srvEnabledCipherSuites[0] = cliEnabledCipherSuites[1];
+ srvEnabledCipherSuites[1] = cliEnabledCipherSuites[0];
+ }
+
+ /*
+ * =============================================================
+ * The remainder is just support stuff
+ */
+
+ // use any free port by default
+ volatile int serverPort = 0;
+
+ volatile Exception serverException = null;
+ volatile Exception clientException = null;
+
+ public static void main(String[] args) throws Exception {
+ // parse the arguments
+ parseArguments(args);
+
+ String keyFilename =
+ System.getProperty("test.src", ".") + "/" + pathToStores +
+ "/" + keyStoreFile;
+ String trustFilename =
+ System.getProperty("test.src", ".") + "/" + pathToStores +
+ "/" + trustStoreFile;
+
+ System.setProperty("javax.net.ssl.keyStore", keyFilename);
+ System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+ System.setProperty("javax.net.ssl.trustStore", trustFilename);
+ System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+ if (debug)
+ System.setProperty("javax.net.debug", "all");
+
+ /*
+ * Start the tests.
+ */
+ new UseCipherSuitesOrder();
+ }
+
+ Thread clientThread = null;
+ Thread serverThread = null;
+
+ /*
+ * Primary constructor, used to drive remainder of the test.
+ *
+ * Fork off the other side, then do your work.
+ */
+ UseCipherSuitesOrder() throws Exception {
+ Exception startException = null;
+ try {
+ if (separateServerThread) {
+ startServer(true);
+ startClient(false);
+ } else {
+ startClient(true);
+ startServer(false);
+ }
+ } catch (Exception e) {
+ startException = e;
+ }
+
+ /*
+ * Wait for other side to close down.
+ */
+ if (separateServerThread) {
+ if (serverThread != null) {
+ serverThread.join();
+ }
+ } else {
+ if (clientThread != null) {
+ clientThread.join();
+ }
+ }
+
+ /*
+ * When we get here, the test is pretty much over.
+ * Which side threw the error?
+ */
+ Exception local;
+ Exception remote;
+
+ if (separateServerThread) {
+ remote = serverException;
+ local = clientException;
+ } else {
+ remote = clientException;
+ local = serverException;
+ }
+
+ Exception exception = null;
+
+ /*
+ * Check various exception conditions.
+ */
+ if ((local != null) && (remote != null)) {
+ // If both failed, return the curthread's exception.
+ local.initCause(remote);
+ exception = local;
+ } else if (local != null) {
+ exception = local;
+ } else if (remote != null) {
+ exception = remote;
+ } else if (startException != null) {
+ exception = startException;
+ }
+
+ /*
+ * If there was an exception *AND* a startException,
+ * output it.
+ */
+ if (exception != null) {
+ if (exception != startException && startException != null) {
+ exception.addSuppressed(startException);
+ }
+ throw exception;
+ }
+
+ // Fall-through: no exception to throw!
+ }
+
+ void startServer(boolean newThread) throws Exception {
+ if (newThread) {
+ serverThread = new Thread() {
+ public void run() {
+ try {
+ doServerSide();
+ } catch (Exception e) {
+ /*
+ * Our server thread just died.
+ *
+ * Release the client, if not active already...
+ */
+ System.err.println("Server died...");
+ serverReady = true;
+ serverException = e;
+ }
+ }
+ };
+ serverThread.start();
+ } else {
+ try {
+ doServerSide();
+ } catch (Exception e) {
+ serverException = e;
+ } finally {
+ serverReady = true;
+ }
+ }
+ }
+
+ void startClient(boolean newThread) throws Exception {
+ if (newThread) {
+ clientThread = new Thread() {
+ public void run() {
+ try {
+ doClientSide();
+ } catch (Exception e) {
+ /*
+ * Our client thread just died.
+ */
+ System.err.println("Client died...");
+ clientException = e;
+ }
+ }
+ };
+ clientThread.start();
+ } else {
+ try {
+ doClientSide();
+ } catch (Exception e) {
+ clientException = e;
+ }
+ }
+ }
+}
--- a/jdk/test/sun/security/ssl/javax/net/ssl/ServerName/IllegalSNIName.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/sun/security/ssl/javax/net/ssl/ServerName/IllegalSNIName.java Sat Sep 14 20:43:34 2013 +0100
@@ -34,7 +34,7 @@
public static void main(String[] args) throws Exception {
String[] illegalNames = {
- "example\u3003\u3002com",
+ "example\u3002\u3002com",
"example..com",
"com\u3002",
"com.",
--- a/jdk/test/sun/tools/jconsole/ImmutableResourceTest.java Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 isn't the test case: ImmutableResourceTest.sh is.
- * Refer to ImmutableResourceTest.sh when running this test.
- *
- * @bug 6287579
- * @summary SubClasses of ListResourceBundle should fix getContents()
- */
-import java.util.ResourceBundle;
-
-public class ImmutableResourceTest {
-
- public static void main(String[] args) throws Exception {
-
- /* Reach under the covers and get the message strings */
- sun.tools.jconsole.resources.JConsoleResources jcr =
- new sun.tools.jconsole.resources.JConsoleResources ();
- Object [][] testData = jcr.getContents();
-
- /* Shred our copy of the message strings */
- for (int ii = 0; ii < testData.length; ii++) {
- testData[ii][0] = "xxx";
- testData[ii][1] = "yyy";
- }
-
- /*
- * Try a lookup for the shredded key.
- * If this is successful we have a problem.
- */
- String ss = sun.tools.jconsole.Resources.getText("xxx");
- if ("yyy".equals(ss)) {
- throw new Exception ("SubClasses of ListResourceBundle should fix getContents()");
- }
- System.out.println("...Finished.");
- }
-}
--- a/jdk/test/sun/tools/jconsole/ImmutableResourceTest.sh Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-#
-# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please 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 6287579
-# @summary SubClasses of ListResourceBundle should fix getContents()
-#
-# @run shell ImmutableResourceTest.sh
-
-# Beginning of subroutines:
-status=1
-
-#Call this from anywhere to fail the test with an error message
-# usage: fail "reason why the test failed"
-fail()
- { echo "The test failed :-("
- echo "$*" 1>&2
- echo "exit status was $status"
- exit $status
- } #end of fail()
-
-#Call this from anywhere to pass the test with a message
-# usage: pass "reason why the test passed if applicable"
-pass()
- { echo "The test passed!!!"
- echo "$*" 1>&2
- exit 0
- } #end of pass()
-
-# end of subroutines
-
-# The beginning of the script proper
-
-OS=`uname -s`
-case "$OS" in
- SunOS | Linux | Darwin )
- PATHSEP=":"
- ;;
-
- Windows* | CYGWIN*)
- PATHSEP=";"
- ;;
-
- # catch all other OSs
- * )
- echo "Unrecognized system! $OS"
- fail "Unrecognized system! $OS"
- ;;
-esac
-
-TARGETCLASS="ImmutableResourceTest"
-if [ -z "${TESTJAVA}" ] ; then
- # TESTJAVA is not set, so the test is running stand-alone.
- # TESTJAVA holds the path to the root directory of the build of the JDK
- # to be tested. That is, any java files run explicitly in this shell
- # should use TESTJAVA in the path to the java interpreter.
- # So, we'll set this to the JDK spec'd on the command line. If none
- # is given on the command line, tell the user that and use a default.
- # THIS IS THE JDK BEING TESTED.
- if [ -n "$1" ] ; then
- TESTJAVA=$1
- else
- TESTJAVA=$JAVA_HOME
- fi
- TESTSRC=.
- TESTCLASSES=.
- #Deal with .class files:
-fi
-#
-echo "JDK under test is: $TESTJAVA"
-#
-CP="-classpath ${TESTCLASSES}${PATHSEP}${TESTJAVA}/lib/jconsole.jar"
-# Compile the test class using the classpath we need:
-#
-env
-#
-set -vx
-#
-#Compile. jconsole.jar is required on the classpath.
-${TESTJAVA}/bin/javac -d "${TESTCLASSES}" ${CP} -g \
- "${TESTSRC}"/"${TARGETCLASS}".java
-#
-#Run the test class, again with the classpath we need:
-${TESTJAVA}/bin/java ${CP} ${TARGETCLASS}
-status=$?
-echo "test status was: $status"
-if [ $status -eq "0" ];
- then pass ""
-
- else fail "unspecified test failure"
-fi
--- a/jdk/test/sun/tools/jconsole/ResourceCheckTest.java Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/sun/tools/jconsole/ResourceCheckTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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
@@ -27,377 +27,134 @@
* This isn't the test case: ResourceCheckTest.sh is.
* Refer to ResourceCheckTest.sh when running this test.
*
- * @bug 5008856 5023573 5024917 5062569
+ * @bug 5008856 5023573 5024917 5062569 7172176
* @summary 'missing resource key' error for key = "Operating system"
*/
-import java.awt.event.KeyEvent;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import sun.tools.jconsole.Messages;
import sun.tools.jconsole.Resources;
+/*
+ * Ensures that there is a one-to-one mapping between constants in the
+ * Message class and the keys in the sun.tools.jconsole.resources.messages
+ * bundle.
+ *
+ * An error will be thrown if there is a:
+ *
+ * - key in the resource bundle that doesn't have a public static field with
+ * the same name in the Message class.
+ *
+ * - public static field in the Message class that doesn't have a key with
+ * the same name in the resource bundle.
+ *
+ * - message with a mnemonic identifier(&) for which a mnemonic can't
+ * be looked up using Resources#getMnemonicInt().
+ *
+ */
public class ResourceCheckTest {
+ private static final String MISSING_RESOURCE_KEY_PREFIX = "missing message for";
+ private static final String RESOURCE_BUNDLE = "sun.tools.jconsole.resources.messages";
+ private static final String NEW_LINE = String.format("%n");
- public static void main(String[] args){
- Object [][] testData = {
- {"<", "", "", "", ""},
- {"<<", "", "", "", ""},
- {">", "", "", "", ""},
- {" 1 day", "", "", "", ""},
- {" 1 hour", "", "", "", ""},
- {" 1 min", "", "", "", ""},
- {" 1 month", "", "", "", ""},
- {" 1 year", "", "", "", ""},
- {" 2 hours", "", "", "", ""},
- {" 3 hours", "", "", "", ""},
- {" 3 months", "", "", "", ""},
- {" 5 min", "", "", "", ""},
- {" 6 hours", "", "", "", ""},
- {" 6 months", "", "", "", ""},
- {" 7 days", "", "", "", ""},
- {"10 min", "", "", "", ""},
- {"12 hours", "", "", "", ""},
- {"30 min", "", "", "", ""},
- {"ACTION", "", "", "", ""},
- {"ACTION_INFO", "", "", "", ""},
- {"All", "", "", "", ""},
- {"Architecture", "", "", "", ""},
- {"Attribute", "", "", "", ""},
- {"Attribute value", "", "", "", ""},
- {"Attribute values", "", "", "", ""},
- {"Attributes", "", "", "", ""},
- {"Blank", "", "", "", ""},
- {"BlockedCount WaitedCount", "BlockedCount", "WaitedCount", "", ""},
- {"Boot class path", "", "", "", ""},
- {"BorderedComponent.moreOrLessButton.toolTip", "", "", "", ""},
- {"Close", "", "", "", ""},
- {"CPU Usage", "", "", "", ""},
- {"CPUUsageFormat","PhonyPercentage", "", "", ""},
- {"Cancel", "", "", "", ""},
- {"Cascade", "", "", "", ""},
- {"Cascade.mnemonic", "", "", "", ""},
- {"Chart:", "", "", "", ""},
- {"Chart:.mnemonic", "", "", "", ""},
- {"ClassTab.infoLabelFormat", "LoadedCount", "UnloadedCount", "TotalCount", ""},
- {"ClassTab.loadedClassesPlotter.accessibleName", "", "", "", ""},
- {"Class path", "", "", "", ""},
- {"Classes", "", "", "", ""},
- {"ClassName", "", "", "", ""},
- {"Column.Name", "", "", "", ""},
- {"Column.PID", "", "", "", ""},
- {"Committed", "", "", "", ""},
- {"Committed memory", "", "", "", ""},
- {"Committed virtual memory", "", "", "", ""},
- {"Compiler", "", "", "", ""},
- {"Connect...", "", "", "", ""},
- {"Connect", "", "", "", ""},
- {"Connect.mnemonic", "", "", "", ""},
- {"ConnectDialog.connectButton.toolTip", "", "", "", ""},
- {"ConnectDialog.accessibleDescription", "", "", "", ""},
- {"ConnectDialog.masthead.accessibleName", "", "", "", ""},
- {"ConnectDialog.masthead.title", "", "", "", ""},
- {"ConnectDialog.statusBar.accessibleName", "", "", "", ""},
- {"ConnectDialog.title", "", "", "", ""},
- {"Connected. Click to disconnect.", "", "", "", ""},
- {"connectingTo1", "PhonyConnectionName", "", "", ""},
- {"connectingTo2", "PhonyConnectionName", "", "", ""},
- {"connectionFailed1", "", "", "", ""},
- {"connectionFailed2", "PhonyConnectionName", "", "", ""},
- {"connectionLost1", "", "", "", ""},
- {"connectionLost2", "PhonyConnectionName", "", "", ""},
- {"Connection failed", "", "", "", ""},
- {"Connection", "", "", "", ""},
- {"Connection.mnemonic", "", "", "", ""},
- {"Connection name", "", "", "", ""},
- {"ConnectionName (disconnected)", "Phony", "Phony", "", ""},
- {"Constructor", "", "", "", ""},
- {"Create", "Phony", "Phony", "", ""},
- {"Current classes loaded", "", "", "", ""},
- {"Current heap size", "", "", "", ""},
- {"Current value", "PhonyValue", "", "", ""},
- {"Daemon threads", "", "", "", ""},
- {"deadlockAllTab", "", "", "", ""},
- {"deadlockTab", "", "", "", ""},
- {"deadlockTabN", "PhonyInt", "", "", ""},
- {"Description", "", "", "", ""},
- {"Descriptor", "", "", "", ""},
- {"Details", "", "", "", ""},
- {"Detect Deadlock", "", "", "", ""},
- {"Detect Deadlock.mnemonic", "", "", "", ""},
- {"Detect Deadlock.toolTip", "", "", "", ""},
- {"Dimension is not supported:", "", "", "", ""},
- {"Discard chart", "", "", "", ""},
- {"Disconnected. Click to connect.", "", "", "", ""},
- {"Double click to expand/collapse", "", "", "", ""},
- {"Double click to visualize", "", "", "", ""},
- {"DurationDaysHoursMinutes", 0, 13, 54, ""},
- {"DurationDaysHoursMinutes", 1, 13, 54, ""},
- {"DurationDaysHoursMinutes", 2, 13, 54, ""},
- {"DurationDaysHoursMinutes", 1024, 13, 45, ""},
- {"DurationHoursMinutes", 0, 13, "", ""},
- {"DurationHoursMinutes", 1, 0, "", ""},
- {"DurationHoursMinutes", 1, 1, "", ""},
- {"DurationHoursMinutes", 2, 42, "", ""},
- {"DurationMinutes", 0, "", "", ""},
- {"DurationMinutes", 1, "", "", ""},
- {"DurationMinutes", 2, "", "", ""},
- {"DurationSeconds", 0, "", "", ""},
- {"DurationSeconds", 1, "", "", ""},
- {"DurationSeconds", 2, "", "", ""},
- {"Empty array", "", "", "", ""},
- {"Error", "", "", "", ""},
- {"Error: MBeans already exist", "", "", "", ""},
- {"Error: MBeans do not exist", "", "", "", ""},
- {"Event", "", "", "", ""},
- {"Exit", "", "", "", ""},
- {"Exit.mnemonic", "", "", "", ""},
- {"expand", "", "", "", ""},
- {"Fail to load plugin", "", "", "", ""},
- {"FileChooser.fileExists.cancelOption", "", "", "", ""},
- {"FileChooser.fileExists.message", "PhonyFileName", "", "", ""},
- {"FileChooser.fileExists.okOption", "", "", "", ""},
- {"FileChooser.fileExists.title", "", "", "", ""},
- {"FileChooser.savedFile", "PhonyFilePath", "PhonyFileSize", "", ""},
- {"FileChooser.saveFailed.message", "PhonyFilePath", "PhonyMessage", "", ""},
- {"FileChooser.saveFailed.title", "", "", "", ""},
- {"Free physical memory", "", "", "", ""},
- {"Free swap space", "", "", "", ""},
- {"Garbage collector", "", "", "", ""},
- {"GC time", "", "", "", ""},
- {"GC time details", 54, "Phony", 11, ""},
- {"GcInfo", "Phony", -1, 768, ""},
- {"GcInfo", "Phony", 0, 768, ""},
- {"GcInfo", "Phony", 1, 768, ""},
- {"Heap", "", "", "", ""},
- {"Heap Memory Usage", "", "", "", ""},
- {"Help.AboutDialog.accessibleDescription", "", "", "", ""},
- {"Help.AboutDialog.jConsoleVersion", "DummyVersion", "", "", ""},
- {"Help.AboutDialog.javaVersion", "DummyVersion", "", "", ""},
- {"Help.AboutDialog.masthead.accessibleName", "", "", "", ""},
- {"Help.AboutDialog.masthead.title", "", "", "", ""},
- {"Help.AboutDialog.title", "", "", "", ""},
- {"Help.AboutDialog.userGuideLink", "DummyMessage", "", "", ""},
- {"Help.AboutDialog.userGuideLink.mnemonic", "", "", "", ""},
- {"Help.AboutDialog.userGuideLink.url", "DummyURL", "", "", ""},
- {"HelpMenu.About.title", "", "", "", ""},
- {"HelpMenu.About.title.mnemonic", "", "", "", ""},
- {"HelpMenu.UserGuide.title", "", "", "", ""},
- {"HelpMenu.UserGuide.title.mnemonic", "", "", "", ""},
- {"HelpMenu.title", "", "", "", ""},
- {"HelpMenu.title.mnemonic", "", "", "", ""},
- {"Hotspot MBeans...", "", "", "", ""},
- {"Hotspot MBeans....mnemonic", "", "", "", ""},
- {"Hotspot MBeans.dialog.accessibleDescription", "", "", "", ""},
- {"Impact", "", "", "", ""},
- {"Info", "", "", "", ""},
- {"INFO", "", "", "", ""},
- {"Invalid plugin path", "", "", "", ""},
- {"Invalid URL", "", "", "", ""},
- {"Is", "", "", "", ""},
- {"Java Monitoring & Management Console", "", "", "", ""},
- {"Java Virtual Machine", "", "", "", ""},
- {"JConsole: ", "", "", "", ""},
- {"JConsole.accessibleDescription", "", "", "", ""},
- {"JConsole version", "PhonyVersion", "", "", ""},
- {"JIT compiler", "", "", "", ""},
- {"Library path", "", "", "", ""},
- {"Live Threads", "", "", "", ""},
- {"Loaded", "", "", "", ""},
- {"Local Process:", "", "", "", ""},
- {"Local Process:.mnemonic", "", "", "", ""},
- {"Manage Hotspot MBeans in: ", "", "", "", ""},
- {"Management Not Enabled", "", "", "", ""},
- {"Management Will Be Enabled", "", "", "", ""},
- {"Masthead.font", "", "", "", ""},
- {"Max", "", "", "", ""},
- {"Max", "", "", "", ""},
- {"Maximum heap size", "", "", "", ""},
- {"MBeanAttributeInfo", "", "", "", ""},
- {"MBeanInfo", "", "", "", ""},
- {"MBeanNotificationInfo", "", "", "", ""},
- {"MBeanOperationInfo", "", "", "", ""},
- {"MBeans", "", "", "", ""},
- {"MBeansTab.clearNotificationsButton", "", "", "", ""},
- {"MBeansTab.clearNotificationsButton.mnemonic", "", "", "", ""},
- {"MBeansTab.clearNotificationsButton.toolTip", "", "", "", ""},
- {"MBeansTab.compositeNavigationMultiple", 0, 0, "", ""},
- {"MBeansTab.compositeNavigationSingle", "", "", "", ""},
- {"MBeansTab.refreshAttributesButton", "", "", "", ""},
- {"MBeansTab.refreshAttributesButton.mnemonic", "", "", "", ""},
- {"MBeansTab.refreshAttributesButton.toolTip", "", "", "", ""},
- {"MBeansTab.subscribeNotificationsButton", "", "", "", ""},
- {"MBeansTab.subscribeNotificationsButton.mnemonic", "", "", "", ""},
- {"MBeansTab.subscribeNotificationsButton.toolTip", "", "", "", ""},
- {"MBeansTab.tabularNavigationMultiple", 0, 0, "", ""},
- {"MBeansTab.tabularNavigationSingle", "", "", "", ""},
- {"MBeansTab.unsubscribeNotificationsButton", "", "", "", ""},
- {"MBeansTab.unsubscribeNotificationsButton.mnemonic", "", "", "", ""},
- {"MBeansTab.unsubscribeNotificationsButton.toolTip", "", "", "", ""},
- {"Memory", "", "", "", ""},
- {"MemoryPoolLabel", "PhonyMemoryPool", "", "", ""},
- {"MemoryTab.heapPlotter.accessibleName", "", "", "", ""},
- {"MemoryTab.infoLabelFormat", "UsedCount", "CommittedCount", "MaxCount", ""},
- {"MemoryTab.nonHeapPlotter.accessibleName", "", "", "", ""},
- {"MemoryTab.poolChart.aboveThreshold", "Threshold", "", "", ""},
- {"MemoryTab.poolChart.accessibleName", "", "", "", ""},
- {"MemoryTab.poolChart.belowThreshold", "Threshold", "", "", ""},
- {"MemoryTab.poolPlotter.accessibleName", "PhonyMemoryPool", "", "", ""},
- {"Message", "", "", "", ""},
- {"Method successfully invoked", "", "", "", ""},
- {"Monitor locked", "", "", "", ""},
- {"Minimize All", "", "", "", ""},
- {"Minimize All.mnemonic", "", "", "", ""},
- {"Name", "", "", "", ""},
- {"Name and Build", "PhonyName", "PhonyBuild", "", ""},
- {"Name Build and Mode", "PhonyName", "PhonyBuild", "PhonyMode", ""},
- {"Name State", "PhonyName", "PhonyState", "", ""},
- {"Name State LockName", "PhonyName", "PhonyState", "PhonyLock", ""},
- {"Name State LockName LockOwner", "PhonyName", "PhonyState", "PhonyLock", "PhonyOwner"},
- {"New Connection...", "", "", "", ""},
- {"New Connection....mnemonic", "", "", "", ""},
- {"No deadlock detected", "", "", "", ""},
- {"Non-Heap", "", "", "", ""},
- {"Non-Heap Memory Usage", "", "", "", ""},
- {"Notification", "", "", "", ""},
- {"Notification buffer", "", "", "", ""},
- {"Notifications", "", "", "", ""},
- {"NotifTypes", "", "", "", ""},
- {"Number of Loaded Classes", "", "", "", ""},
- {"Number of processors", "", "", "", ""},
- {"Number of Threads", "", "", "", ""},
- {"ObjectName", "", "", "", ""},
- {"Operating System", "", "", "", ""},
- {"Operation", "", "", "", ""},
- {"Operation invocation", "", "", "", ""},
- {"Operation return value", "", "", "", ""},
- {"Operations", "", "", "", ""},
- {"Overview", "", "", "", ""},
- {"OverviewPanel.plotter.accessibleName", "PhonyPlotter", "", "", ""},
- {"Parameter", "", "", "", ""},
- {"Password: ", "", "", "", ""},
- {"Password: .mnemonic", "", "", "", ""},
- {"Password.accessibleName", "", "", "", ""},
- {"Peak", "", "", "", ""},
- {"Perform GC", "", "", "", ""},
- {"Perform GC.mnemonic", "", "", "", ""},
- {"Perform GC.toolTip", "", "", "", ""},
- {"Plotter.accessibleName", "", "", "", ""},
- {"Plotter.accessibleName.keyAndValue", "Key", "Value", "", ""},
- {"Plotter.accessibleName.noData", "", "", "", ""},
- {"Plotter.saveAsMenuItem", "", "", "", ""},
- {"Plotter.saveAsMenuItem.mnemonic", "", "", "", ""},
- {"Plotter.timeRangeMenu", "", "", "", ""},
- {"Plotter.timeRangeMenu.mnemonic", "", "", "", ""},
- {"plot", "", "", "", ""},
- {"Problem adding listener", "", "", "", ""},
- {"Problem displaying MBean", "", "", "", ""},
- {"Problem invoking", "", "", "", ""},
- {"Problem removing listener", "", "", "", ""},
- {"Problem setting attribute", "", "", "", ""},
- {"Process CPU time", "", "", "", ""},
- {"Readable", "", "", "", ""},
- {"Reconnect", "", "", "", ""},
- {"Remote Process:", "", "", "", ""},
- {"Remote Process:.mnemonic", "", "", "", ""},
- {"Remote Process.textField.accessibleName", "", "", "", ""},
- {"remoteTF.usage", "", "", "", ""},
- {"Restore All", "", "", "", ""},
- {"Restore All.mnemonic", "", "", "", ""},
- {"ReturnType", "", "", "", ""},
- {"SeqNum", "", "", "", ""},
- {"Size Bytes", 512, "", "", ""},
- {"Size Gb", 512, "", "", ""},
- {"Size Kb", 512, "", "", ""},
- {"Size Mb", 512, "", "", ""},
- {"Source", "", "", "", ""},
- {"Stack trace", "", "", "", ""},
- {"SummaryTab.headerDateTimeFormat", "", "", "", ""},
- {"SummaryTab.pendingFinalization.label", "", "", "", ""},
- {"SummaryTab.pendingFinalization.value", "ObjectCount", "", "", ""},
- {"SummaryTab.tabName", "", "", "", ""},
- {"SummaryTab.vmVersion", "VMName", "VMVersion", "", ""},
- {"ThreadTab.infoLabelFormat", "LiveCount", "PeakCount", "TotalCount", ""},
- {"ThreadTab.threadInfo.accessibleName", "", "", "", ""},
- {"ThreadTab.threadPlotter.accessibleName", "", "", "", ""},
- {"Threads", "", "", "", ""},
- {"Threshold", "", "", "", ""},
- {"Tile", "", "", "", ""},
- {"Tile.mnemonic", "", "", "", ""},
- {"Time", "", "", "", ""},
- {"Time Range:", "", "", "", ""},
- {"Time Range:.mnemonic", "", "", "", ""},
- {"TimeStamp", "", "", "", ""},
- {"Total classes loaded", "", "", "", ""},
- {"Total classes unloaded", "", "", "", ""},
- {"Total compile time", "", "", "", ""},
- {"Total Loaded", "", "", "", ""},
- {"Total physical memory", "", "", "", ""},
- {"Total swap space", "", "", "", ""},
- {"Total threads started", "", "", "", ""},
- {"Type", "", "", "", ""},
- {"Unavailable", "", "", "", ""},
- {"UNKNOWN", "", "", "", ""},
- {"Unregister", "", "", "", ""},
- {"Uptime", "", "", "", ""},
- {"Usage Threshold", "", "", "", ""},
- {"Used", "", "", "", ""},
- {"Username: ", "", "", "", ""},
- {"Username: .mnemonic", "", "", "", ""},
- {"Username.accessibleName", "", "", "", ""},
- {"UserData", "", "", "", ""},
- {"Value", "", "", "", ""},
- {"Vendor", "", "", "", ""},
- {"Verbose Output", "", "", "", ""},
- {"Verbose Output.toolTip", "", "", "", ""},
- {"visualize", "", "", "", ""},
- {"VM", "", "", "", ""},
- {"VMInternalFrame.accessibleDescription", "", "", "", ""},
- {"VM arguments", "", "", "", ""},
- {"Virtual Machine", "", "", "", ""},
- {"Window", "", "", "", ""},
- {"Window.mnemonic", "", "", "", ""},
- {"Writable", "", "", "", ""},
- {"zz usage text", "PhonyName", "", "", ""},
- };
- //boolean verbose = false;
- boolean verbose = true;
-
- long badLookups = 0;
- System.out.println("Start...");
- for (int ii = 0; ii < testData.length; ii++) {
- String key = (String)testData[ii][0];
-
- if (key.endsWith(".mnemonic")) {
- String baseKey = key.substring(0, key.length() - ".mnemonic".length());
- int mnemonic = Resources.getMnemonicInt(baseKey);
- if (mnemonic == 0) {
- badLookups++;
- System.out.println("****lookup failed for key = " + key);
+ public static void main(String... args) {
+ List<String> errors = new ArrayList<>();
+ // Ensure that all Message fields have a corresponding key/value
+ // in the resource bundle and that mnemonics can be looked
+ // up where applicable.
+ ResourceBundle rb = ResourceBundle.getBundle(RESOURCE_BUNDLE);
+ for (Field field : Messages.class.getFields()) {
+ if (isResourceKeyField(field)) {
+ String resourceKey = field.getName();
+ String message = readField(field);
+ if (message.startsWith(MISSING_RESOURCE_KEY_PREFIX)) {
+ errors.add("Can't find message (and perhaps mnemonic) for "
+ + Messages.class.getSimpleName() + "."
+ + resourceKey + " in resource bundle.");
} else {
- if (verbose) {
- System.out.println(" mnemonic: " + KeyEvent.getKeyText(mnemonic));
+ String resourceMessage = rb.getString(resourceKey);
+ if (hasMnemonicIdentifier(resourceMessage)) {
+ int mi = Resources.getMnemonicInt(message);
+ if (mi == 0) {
+ errors.add("Could not look up mnemonic for message '"
+ + message + "'.");
+ }
}
}
- continue;
- }
-
- String ss = Resources.getText(key,
- testData[ii][1],
- testData[ii][2],
- testData[ii][3],
- testData[ii][4]);
- if (ss.startsWith("missing resource key")) {
- badLookups++;
- System.out.println("****lookup failed for key = " + key);
- } else {
- if (verbose) {
- System.out.println(" " + ss);
- }
}
}
- if (badLookups > 0) {
- throw new Error ("Resource lookup failed " + badLookups +
- " time(s); Test failed");
+
+ // Ensure that there is Message class field for every resource key.
+ for (String key : Collections.list(rb.getKeys())) {
+ try {
+ Messages.class.getField(key);
+ } catch (NoSuchFieldException nfe) {
+ errors.add("Can't find static field ("
+ + Messages.class.getSimpleName() + "." + key
+ + ") matching '" + key
+ + "' in resource bundle. Unused message?");
+ }
+ }
+
+ if (errors.size() > 0) {
+ throwError(errors);
+ }
+ }
+
+ private static String readField(Field field) {
+ try {
+ return (String) field.get(null);
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ throw new Error("Could not access field " + field.getName()
+ + " when trying to read resource message.");
}
- System.out.println("...Finished.");
+ }
+
+ private static boolean isResourceKeyField(Field field) {
+ int modifiers = field.getModifiers();
+ return Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers);
+ }
+
+ private static boolean hasMnemonicIdentifier(String s) {
+ for (int i = 0; i < s.length() - 1; i++) {
+ if (s.charAt(i) == '&') {
+ if (s.charAt(i + 1) != '&') {
+ return true;
+ } else {
+ i++;
+ }
+ }
+ }
+ return false;
+ }
+
+ private static void throwError(List<String> errors) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("Found ");
+ buffer.append(errors.size());
+ buffer.append(" error(s) when checking one-to-one mapping ");
+ buffer.append("between Message and resource bundle keys in ");
+ buffer.append(RESOURCE_BUNDLE);
+ buffer.append(" with ");
+ buffer.append(Locale.getDefault());
+ buffer.append(" locale.");
+ buffer.append(NEW_LINE);
+ int errorIndex = 1;
+ for (String error : errors) {
+ buffer.append("Error ");
+ buffer.append(errorIndex);
+ buffer.append(": ");
+ buffer.append(error);
+ buffer.append(NEW_LINE);
+ errorIndex++;
+ }
+ throw new Error(buffer.toString());
}
}
--- a/jdk/test/sun/tools/jconsole/ResourceCheckTest.sh Fri Sep 06 09:55:59 2013 +0100
+++ b/jdk/test/sun/tools/jconsole/ResourceCheckTest.sh Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2004, 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
@@ -54,7 +54,7 @@
OS=`uname -s`
case "$OS" in
- SunOS | Linux )
+ SunOS | Linux | Darwin)
PATHSEP=":"
;;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/util/locale/provider/Bug8024141.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8024141
+ * @summary Test for cache support of sun.util.locale.provider.LocaleResources.getTimeZoneNames
+ */
+
+import java.time.ZoneId;
+import static java.util.Locale.ENGLISH;
+import static java.time.format.TextStyle.FULL;
+import static java.time.format.TextStyle.SHORT;
+
+public class Bug8024141 {
+ // This test assumes that the two time zones are in GMT. If
+ // they become different zones, need to pick up another zones.
+ private static final String[] ZONES = {
+ "Africa/Abidjan",
+ "Africa/Bamako"
+ };
+
+ public static void main(String[] args) {
+ ZoneId gmt = ZoneId.of("GMT");
+ String gmtName = gmt.getDisplayName(FULL, ENGLISH);
+ String gmtAbbr = gmt.getDisplayName(SHORT, ENGLISH);
+
+ for (String zone : ZONES) {
+ ZoneId id = ZoneId.of(zone);
+ String name = id.getDisplayName(FULL, ENGLISH);
+ String abbr = id.getDisplayName(SHORT, ENGLISH);
+
+ if (!name.equals(gmtName) || !abbr.equals(gmtAbbr)) {
+ throw new RuntimeException("inconsistent name/abbr for " + zone + ":\n"
+ + "name=" + name + ", abbr=" + abbr);
+ }
+ }
+ }
+}
--- a/langtools/.hgtags Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/.hgtags Sat Sep 14 20:43:34 2013 +0100
@@ -228,3 +228,4 @@
dd4a00c220c6e14d9b2ce93a2bd436a1d04f0d03 jdk8-b104
375834b5cf086dd7ce9e49f602d81bb51d3e0fa9 jdk8-b105
fcd768844b9926c5f994292ec6350c20cc7c0f76 jdk8-b106
+3f274927ec1863544b8214262ab02b7de2970da6 jdk8-b107
--- a/langtools/README Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/README Sat Sep 14 20:43:34 2013 +0100
@@ -32,7 +32,7 @@
JLS and JVMS.
In addition, there is a substantial collection of regression and unit
-tests for all the tools in the maain langtools test/ directory.
+tests for all the tools in the main langtools test/ directory.
Finally, there is a small set of tests to do basic validation of a build
of the langtools workspace for use by JDK. These tests check the contents
--- a/langtools/make/netbeans/langtools/build.xml Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/make/netbeans/langtools/build.xml Sat Sep 14 20:43:34 2013 +0100
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@@ -55,10 +55,18 @@
description="Build one or all langtools tools"
/>
+ <condition property="bootstrap" value="bootstrap-" else="">
+ <isset property="langtools.tool.bootstrap"/>
+ </condition>
+
+ <condition property="bcp" value="${build.bootstrap.dir}/classes" else="${build.classes.dir}">
+ <isset property="langtools.tool.bootstrap"/>
+ </condition>
+
<target name="-build-tool" if="langtools.tool.name">
- <echo level="info" message="Building ${langtools.tool.name}"/>
+ <echo level="info" message="Building ${bootstrap}${langtools.tool.name}"/>
<echo level="verbose" message="(Unset langtools.tool.name to build all tools)"/>
- <antcall target="build-${langtools.tool.name}"/>
+ <antcall target="build-${bootstrap}${langtools.tool.name}"/>
</target>
<target name="-build-all" unless="langtools.tool.name">
@@ -89,8 +97,9 @@
<target name="run" depends="-check-target.java.home,build,-def-run,-get-tool-and-args"
description="run tool">
- <echo level="info" message="Run ${langtools.tool.name} with args ${langtools.tool.args}"/>
- <run mainclass="com.sun.tools.${langtools.tool.name}.Main" args="${langtools.tool.args}"/>
+ <echo level="info" message="${bcp}"/>
+ <echo level="info" message="Run ${bootstrap}${langtools.tool.name} with args ${langtools.tool.args}"/>
+ <run bcp="${bcp}" mainclass="com.sun.tools.${langtools.tool.name}.Main" args="${langtools.tool.args}"/>
</target>
<!-- Run a selected class. (action: run.single; shift-F6) -->
@@ -136,9 +145,9 @@
<!-- Debug tool in NetBeans. -->
<target name="debug" depends="-check-target.java.home,-def-run,-def-start-debugger,-get-tool-and-args,build" if="netbeans.home">
- <echo level="info" message="Debug ${langtools.tool.name} with args ${langtools.tool.args}"/>
+ <echo level="info" message="Debug ${boostrap}${langtools.tool.name} with args ${langtools.tool.args}"/>
<start-debugger/>
- <run mainclass="com.sun.tools.${langtools.tool.name}.Main" args="${langtools.tool.args}" jpda.jvmargs="${jpda.jvmargs}"/>
+ <run bcp="${bcp}" mainclass="com.sun.tools.${langtools.tool.name}.Main" args="${langtools.tool.args}" jpda.jvmargs="${jpda.jvmargs}"/>
</target>
<!-- Debug a selected class . -->
@@ -207,6 +216,7 @@
<target name="-get-tool-if-set" depends="-def-select-tool">
<select-tool
toolproperty="langtools.tool.name"
+ bootstrapproperty="langtools.tool.bootstrap"
propertyfile="${langtools.properties}"
askIfUnset="false"
/>
@@ -216,6 +226,7 @@
<select-tool
toolproperty="langtools.tool.name"
argsproperty="langtools.tool.args"
+ bootstrapproperty="langtools.tool.bootstrap"
propertyfile="${langtools.properties}"
askIfUnset="true"
/>
@@ -226,10 +237,12 @@
<macrodef name="run">
<attribute name="mainclass"/>
<attribute name="args" default=""/>
+ <attribute name="bcp" default="${build.classes.dir}"/>
<attribute name="jpda.jvmargs" default=""/>
+
<sequential>
<java fork="true" jvm="${target.java}" classname="@{mainclass}">
- <jvmarg line="-Xbootclasspath/p:${build.classes.dir}"/>
+ <jvmarg line="-Xbootclasspath/p:${bcp}"/>
<jvmarg line="@{jpda.jvmargs}"/>
<arg line="@{args}"/>
</java>
--- a/langtools/make/tools/anttasks/SelectToolTask.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/make/tools/anttasks/SelectToolTask.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -43,6 +43,7 @@
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.EnumSet;
import java.util.List;
import java.util.Properties;
import javax.swing.JButton;
@@ -71,6 +72,31 @@
* is invoked to allow the user to set or reset values for use in property mode.
*/
public class SelectToolTask extends Task {
+
+ enum ToolChoices {
+ NONE(""),
+ JAVAC("javac"),
+ JAVADOC("javadoc"),
+ JAVAH("javah"),
+ JAVAP("javap");
+
+ String toolName;
+ boolean bootstrap;
+
+ ToolChoices(String toolName) {
+ this(toolName, false);
+ }
+
+ ToolChoices(String toolName, boolean boostrap) {
+ this.toolName = toolName;
+ }
+
+ @Override
+ public String toString() {
+ return toolName;
+ }
+ }
+
/**
* Set the location of the private properties file used to keep the retain
* user preferences for this repository.
@@ -97,6 +123,14 @@
}
/**
+ * Set the name of the property which will be set to the execution args of the
+ * selected tool, if any. The args default to an empty string.
+ */
+ public void setBootstrapProperty(String bootstrapProperty) {
+ this.bootstrapProperty = bootstrapProperty;
+ }
+
+ /**
* Specify whether or not to pop up a dialog if the user has not specified
* a default value for a property.
*/
@@ -110,6 +144,7 @@
Properties props = readProperties(propertyFile);
toolName = props.getProperty("tool.name");
+ toolBootstrap = props.getProperty("tool.bootstrap") != null;
if (toolName != null) {
toolArgs = props.getProperty(toolName + ".args", "");
}
@@ -123,6 +158,8 @@
// finally, return required values, if any
if (toolProperty != null && !(toolName == null || toolName.equals(""))) {
p.setProperty(toolProperty, toolName);
+ if (toolBootstrap)
+ p.setProperty(bootstrapProperty, "true");
if (argsProperty != null && toolArgs != null)
p.setProperty(argsProperty, toolArgs);
@@ -134,14 +171,20 @@
JOptionPane p = createPane(guiProps);
p.createDialog("Select Tool").setVisible(true);
- toolName = (String) toolChoice.getSelectedItem();
+ toolName = ((ToolChoices)toolChoice.getSelectedItem()).toolName;
toolArgs = argsField.getText();
-
+ toolBootstrap = bootstrapCheckbox.isSelected();
if (defaultCheck.isSelected()) {
if (toolName.equals("")) {
fileProps.remove("tool.name");
+ fileProps.remove("tool.bootstrap");
} else {
fileProps.put("tool.name", toolName);
+ if (toolBootstrap) {
+ fileProps.put("tool.bootstrap", "true");
+ } else {
+ fileProps.remove("tool.bootstrap");
+ }
fileProps.put(toolName + ".args", toolArgs);
}
writeProperties(propertyFile, fileProps);
@@ -154,32 +197,38 @@
lc.insets.right = 10;
lc.insets.bottom = 3;
GridBagConstraints fc = new GridBagConstraints();
- fc.anchor = GridBagConstraints.WEST;
fc.gridx = 1;
- fc.gridwidth = GridBagConstraints.REMAINDER;
+ fc.gridwidth = GridBagConstraints.NONE;
fc.insets.bottom = 3;
+ JPanel toolPane = new JPanel(new GridBagLayout());
+
JLabel toolLabel = new JLabel("Tool:");
body.add(toolLabel, lc);
- String[] toolChoices = { "apt", "javac", "javadoc", "javah", "javap" };
- if (true || toolProperty == null) {
- // include empty value in setup mode
- List<String> l = new ArrayList<String>(Arrays.asList(toolChoices));
- l.add(0, "");
- toolChoices = l.toArray(new String[l.size()]);
- }
- toolChoice = new JComboBox(toolChoices);
+ EnumSet<ToolChoices> toolChoices = toolProperty == null ?
+ EnumSet.allOf(ToolChoices.class) : EnumSet.range(ToolChoices.JAVAC, ToolChoices.JAVAP);
+ toolChoice = new JComboBox(toolChoices.toArray());
if (toolName != null)
- toolChoice.setSelectedItem(toolName);
+ toolChoice.setSelectedItem(ToolChoices.valueOf(toolName.toUpperCase()));
toolChoice.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
- String tn = (String) e.getItem();
+ String tn = ((ToolChoices)e.getItem()).toolName;
argsField.setText(getDefaultArgsForTool(props, tn));
if (toolProperty != null)
okButton.setEnabled(!tn.equals(""));
}
});
- body.add(toolChoice, fc);
+ GridBagConstraints checkConstraint = new GridBagConstraints();
+ fc.anchor = GridBagConstraints.EAST;
+
+ GridBagConstraints toolConstraint = new GridBagConstraints();
+ fc.anchor = GridBagConstraints.WEST;
+
+ toolPane.add(toolChoice, toolConstraint);
+ bootstrapCheckbox = new JCheckBox("bootstrap", toolBootstrap);
+ toolPane.add(bootstrapCheckbox, checkConstraint);
+
+ body.add(toolPane, fc);
argsField = new JTextField(getDefaultArgsForTool(props, toolName), 40);
if (toolProperty == null || argsProperty != null) {
@@ -190,7 +239,7 @@
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
- String toolName = (String) toolChoice.getSelectedItem();
+ String toolName = ((ToolChoices)toolChoice.getSelectedItem()).toolName;
if (toolName.length() > 0)
props.put(toolName + ".args", argsField.getText());
}
@@ -271,16 +320,19 @@
// Ant task parameters
private boolean askIfUnset;
private String toolProperty;
+ private String bootstrapProperty;
private String argsProperty;
private File propertyFile;
// GUI components
private JComboBox toolChoice;
+ private JCheckBox bootstrapCheckbox;
private JTextField argsField;
private JCheckBox defaultCheck;
private JButton okButton;
// Result values for the client
private String toolName;
+ private boolean toolBootstrap;
private String toolArgs;
}
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java Sat Sep 14 20:43:34 2013 +0100
@@ -157,7 +157,7 @@
addAllProfilesLink(div);
}
body.addContent(div);
- if (configuration.showProfiles) {
+ if (configuration.showProfiles && configuration.profilePackages.size() > 0) {
Content profileSummary = configuration.getResource("doclet.Profiles");
addProfilesList(profileSummary, body);
}
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeWriterImpl.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeWriterImpl.java Sat Sep 14 20:43:34 2013 +0100
@@ -118,7 +118,7 @@
if (prev != null) {
Content prevLink = getLink(new LinkInfoImpl(configuration,
LinkInfoImpl.Kind.CLASS, prev.asClassDoc())
- .label(configuration.getText("doclet.Prev_Class")).strong(true));
+ .label(prevclassLabel).strong(true));
li = HtmlTree.LI(prevLink);
}
else
@@ -136,7 +136,7 @@
if (next != null) {
Content nextLink = getLink(new LinkInfoImpl(configuration,
LinkInfoImpl.Kind.CLASS, next.asClassDoc())
- .label(configuration.getText("doclet.Next_Class")).strong(true));
+ .label(nextclassLabel).strong(true));
li = HtmlTree.LI(nextLink);
}
else
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java Sat Sep 14 20:43:34 2013 +0100
@@ -126,7 +126,7 @@
if (prev != null) {
Content prevLink = getLink(new LinkInfoImpl(configuration,
LinkInfoImpl.Kind.CLASS, prev)
- .label(configuration.getText("doclet.Prev_Class")).strong(true));
+ .label(prevclassLabel).strong(true));
li = HtmlTree.LI(prevLink);
}
else
@@ -144,7 +144,7 @@
if (next != null) {
Content nextLink = getLink(new LinkInfoImpl(configuration,
LinkInfoImpl.Kind.CLASS, next)
- .label(configuration.getText("doclet.Next_Class")).strong(true));
+ .label(nextclassLabel).strong(true));
li = HtmlTree.LI(nextLink);
}
else
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDoclet.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDoclet.java Sat Sep 14 20:43:34 2013 +0100
@@ -205,13 +205,20 @@
* {@inheritDoc}
*/
protected void generateProfileFiles() throws Exception {
- if (configuration.showProfiles) {
+ if (configuration.showProfiles && configuration.profilePackages.size() > 0) {
ProfileIndexFrameWriter.generate(configuration);
Profile prevProfile = null, nextProfile;
+ String profileName;
for (int i = 1; i < configuration.profiles.getProfileCount(); i++) {
- ProfilePackageIndexFrameWriter.generate(configuration, Profile.lookup(i).name);
+ profileName = Profile.lookup(i).name;
+ // Generate profile package pages only if there are any packages
+ // in a profile to be documented. The profilePackages map will not
+ // contain an entry for the profile if there are no packages to be documented.
+ if (!configuration.shouldDocumentProfile(profileName))
+ continue;
+ ProfilePackageIndexFrameWriter.generate(configuration, profileName);
PackageDoc[] packages = configuration.profilePackages.get(
- Profile.lookup(i).name);
+ profileName);
PackageDoc prev = null, next;
for (int j = 0; j < packages.length; j++) {
// if -nodeprecated option is set and the package is marked as
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java Sat Sep 14 20:43:34 2013 +0100
@@ -406,10 +406,7 @@
Content htmlDocType = DocType.TRANSITIONAL;
Content htmlComment = new Comment(configuration.getText("doclet.New_Page"));
Content head = new HtmlTree(HtmlTag.HEAD);
- if (!configuration.notimestamp) {
- Content headComment = new Comment(getGeneratedByString());
- head.addContent(headComment);
- }
+ head.addContent(getGeneratedBy(!configuration.notimestamp));
if (configuration.charset.length() > 0) {
Content meta = HtmlTree.META("Content-Type", CONTENT_TYPE,
configuration.charset);
@@ -502,16 +499,17 @@
if (!configuration.nonavbar) {
String allClassesId = "allclasses_";
HtmlTree navDiv = new HtmlTree(HtmlTag.DIV);
+ Content skipNavLinks = configuration.getResource("doclet.Skip_navigation_links");
if (header) {
body.addContent(HtmlConstants.START_OF_TOP_NAVBAR);
navDiv.addStyle(HtmlStyle.topNav);
allClassesId += "navbar_top";
Content a = getMarkerAnchor("navbar_top");
+ //WCAG - Hyperlinks should contain text or an image with alt text - for AT tools
navDiv.addContent(a);
- Content skipLinkContent = getHyperLink(DocLink.fragment("skip-navbar_top"),
- HtmlTree.EMPTY,
- configuration.getText("doclet.Skip_navigation_links"),
- "");
+ Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav, getHyperLink(
+ DocLink.fragment("skip-navbar_top"), skipNavLinks,
+ skipNavLinks.toString(), ""));
navDiv.addContent(skipLinkContent);
} else {
body.addContent(HtmlConstants.START_OF_BOTTOM_NAVBAR);
@@ -519,10 +517,9 @@
allClassesId += "navbar_bottom";
Content a = getMarkerAnchor("navbar_bottom");
navDiv.addContent(a);
- Content skipLinkContent = getHyperLink(DocLink.fragment("skip-navbar_bottom"),
- HtmlTree.EMPTY,
- configuration.getText("doclet.Skip_navigation_links"),
- "");
+ Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav, getHyperLink(
+ DocLink.fragment("skip-navbar_bottom"), skipNavLinks,
+ skipNavLinks.toString(), ""));
navDiv.addContent(skipLinkContent);
}
if (header) {
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java Sat Sep 14 20:43:34 2013 +0100
@@ -130,10 +130,14 @@
String profileName;
for (int i = 1; i < configuration.profiles.getProfileCount(); i++) {
profileName = Profile.lookup(i).name;
- Content profileLinkContent = getTargetProfileLink("classFrame",
- new StringContent(profileName), profileName);
- Content li = HtmlTree.LI(profileLinkContent);
- ul.addContent(li);
+ // If the profile has valid packages to be documented, add it to the
+ // profiles list on overview-summary.html page.
+ if (configuration.shouldDocumentProfile(profileName)) {
+ Content profileLinkContent = getTargetProfileLink("classFrame",
+ new StringContent(profileName), profileName);
+ Content li = HtmlTree.LI(profileLinkContent);
+ ul.addContent(li);
+ }
}
profilesDiv.addContent(ul);
Content div = HtmlTree.DIV(HtmlStyle.contentContainer, profilesDiv);
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ProfileIndexFrameWriter.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ProfileIndexFrameWriter.java Sat Sep 14 20:43:34 2013 +0100
@@ -88,8 +88,13 @@
Content div = HtmlTree.DIV(HtmlStyle.indexContainer, heading);
HtmlTree ul = new HtmlTree(HtmlTag.UL);
ul.setTitle(profilesLabel);
+ String profileName;
for (int i = 1; i < profiles.getProfileCount(); i++) {
- ul.addContent(getProfile(i));
+ profileName = (Profile.lookup(i)).name;
+ // If the profile has valid packages to be documented, add it to the
+ // left-frame generated for profile index.
+ if (configuration.shouldDocumentProfile(profileName))
+ ul.addContent(getProfile(profileName));
}
div.addContent(ul);
body.addContent(div);
@@ -98,13 +103,12 @@
/**
* Gets each profile name as a separate link.
*
- * @param profile the profile being documented
+ * @param profileName the profile being documented
* @return content for the profile link
*/
- protected Content getProfile(int profile) {
+ protected Content getProfile(String profileName) {
Content profileLinkContent;
Content profileLabel;
- String profileName = (Profile.lookup(profile)).name;
profileLabel = new StringContent(profileName);
profileLinkContent = getHyperLink(DocPaths.profileFrame(profileName), profileLabel, "",
"packageListFrame");
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ProfileWriterImpl.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ProfileWriterImpl.java Sat Sep 14 20:43:34 2013 +0100
@@ -138,6 +138,7 @@
"classFrame", new StringContent(pkg.name()), profile.name);
Content heading = HtmlTree.HEADING(HtmlTag.H3, pkgName);
HtmlTree li = HtmlTree.LI(HtmlStyle.blockList, heading);
+ addPackageDeprecationInfo(li, pkg);
return li;
}
@@ -175,6 +176,30 @@
}
/**
+ * Add the profile package deprecation information to the documentation tree.
+ *
+ * @param li the content tree to which the deprecation information will be added
+ * @param pkg the PackageDoc that is added
+ */
+ public void addPackageDeprecationInfo(Content li, PackageDoc pkg) {
+ Tag[] deprs;
+ if (Util.isDeprecated(pkg)) {
+ deprs = pkg.tags("deprecated");
+ HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
+ deprDiv.addStyle(HtmlStyle.deprecatedContent);
+ Content deprPhrase = HtmlTree.SPAN(HtmlStyle.strong, deprecatedPhrase);
+ deprDiv.addContent(deprPhrase);
+ if (deprs.length > 0) {
+ Tag[] commentTags = deprs[0].inlineTags();
+ if (commentTags.length > 0) {
+ addInlineDeprecatedComment(pkg, deprs[0], deprDiv);
+ }
+ }
+ li.addContent(deprDiv);
+ }
+ }
+
+ /**
* Get "PREV PROFILE" link in the navigation bar.
*
* @return a content tree for the previous link
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java Sat Sep 14 20:43:34 2013 +0100
@@ -191,10 +191,7 @@
Content htmlDocType = DocType.FRAMESET;
Content htmlComment = new Comment(configuration.getText("doclet.New_Page"));
Content head = new HtmlTree(HtmlTag.HEAD);
- if (! noTimeStamp) {
- Content headComment = new Comment(getGeneratedByString());
- head.addContent(headComment);
- }
+ head.addContent(getGeneratedBy(!noTimeStamp));
if (configuration.charset.length() > 0) {
Content meta = HtmlTree.META("Content-Type", CONTENT_TYPE,
configuration.charset);
@@ -210,9 +207,13 @@
write(htmlDocument);
}
- protected String getGeneratedByString() {
- Calendar calendar = new GregorianCalendar(TimeZone.getDefault());
- Date today = calendar.getTime();
- return "Generated by javadoc ("+ ConfigurationImpl.BUILD_DATE + ") on " + today;
+ protected Comment getGeneratedBy(boolean timestamp) {
+ String text = "Generated by javadoc"; // marker string, deliberately not localized
+ if (timestamp) {
+ Calendar calendar = new GregorianCalendar(TimeZone.getDefault());
+ Date today = calendar.getTime();
+ text += " ("+ ConfigurationImpl.BUILD_DATE + ") on " + today;
+ }
+ return new Comment(text);
}
}
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlStyle.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlStyle.java Sat Sep 14 20:43:34 2013 +0100
@@ -68,6 +68,7 @@
packageSummary,
rowColor,
serializedFormContainer,
+ skipNav,
sourceContainer,
sourceLineNo,
strong,
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java Sat Sep 14 20:43:34 2013 +0100
@@ -203,27 +203,27 @@
useLabel = getResource("doclet.navClassUse");
prevLabel = getResource("doclet.Prev");
nextLabel = getResource("doclet.Next");
- prevclassLabel = getResource("doclet.Prev_Class");
- nextclassLabel = getResource("doclet.Next_Class");
+ prevclassLabel = getNonBreakResource("doclet.Prev_Class");
+ nextclassLabel = getNonBreakResource("doclet.Next_Class");
summaryLabel = getResource("doclet.Summary");
detailLabel = getResource("doclet.Detail");
framesLabel = getResource("doclet.Frames");
- noframesLabel = getResource("doclet.No_Frames");
+ noframesLabel = getNonBreakResource("doclet.No_Frames");
treeLabel = getResource("doclet.Tree");
classLabel = getResource("doclet.Class");
deprecatedLabel = getResource("doclet.navDeprecated");
deprecatedPhrase = getResource("doclet.Deprecated");
- allclassesLabel = getResource("doclet.All_Classes");
- allpackagesLabel = getResource("doclet.All_Packages");
- allprofilesLabel = getResource("doclet.All_Profiles");
+ allclassesLabel = getNonBreakResource("doclet.All_Classes");
+ allpackagesLabel = getNonBreakResource("doclet.All_Packages");
+ allprofilesLabel = getNonBreakResource("doclet.All_Profiles");
indexLabel = getResource("doclet.Index");
helpLabel = getResource("doclet.Help");
seeLabel = getResource("doclet.See");
descriptionLabel = getResource("doclet.Description");
- prevpackageLabel = getResource("doclet.Prev_Package");
- nextpackageLabel = getResource("doclet.Next_Package");
- prevprofileLabel = getResource("doclet.Prev_Profile");
- nextprofileLabel = getResource("doclet.Next_Profile");
+ prevpackageLabel = getNonBreakResource("doclet.Prev_Package");
+ nextpackageLabel = getNonBreakResource("doclet.Next_Package");
+ prevprofileLabel = getNonBreakResource("doclet.Prev_Profile");
+ nextprofileLabel = getNonBreakResource("doclet.Next_Profile");
packagesLabel = getResource("doclet.Packages");
profilesLabel = getResource("doclet.Profiles");
methodDetailsLabel = getResource("doclet.Method_Detail");
@@ -257,6 +257,27 @@
}
/**
+ * Get the configuration string as a content, replacing spaces
+ * with non-breaking spaces.
+ *
+ * @param key the key to look for in the configuration file
+ * @return a content tree for the text
+ */
+ public Content getNonBreakResource(String key) {
+ String text = configuration.getText(key);
+ Content c = configuration.newContent();
+ int start = 0;
+ int p;
+ while ((p = text.indexOf(" ", start)) != -1) {
+ c.addContent(text.substring(start, p));
+ c.addContent(RawHtml.nbsp);
+ start = p + 1;
+ }
+ c.addContent(text.substring(start));
+ return c;
+ }
+
+ /**
* Get the configuration string as a content.
*
* @param key the key to look for in the configuration file
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java Sat Sep 14 20:43:34 2013 +0100
@@ -383,35 +383,52 @@
DocErrorReporter reporter);
private void initProfiles() throws IOException {
+ if (profilespath.isEmpty())
+ return;
+
profiles = Profiles.read(new File(profilespath));
- // Generate profiles documentation only is profilespath is set and if
- // profiles is not null and profiles count is 1 or more.
- showProfiles = (!profilespath.isEmpty() && profiles != null &&
- profiles.getProfileCount() > 0);
- }
+
+ // Group the packages to be documented by the lowest profile (if any)
+ // in which each appears
+ Map<Profile, List<PackageDoc>> interimResults =
+ new EnumMap<Profile, List<PackageDoc>>(Profile.class);
+ for (Profile p: Profile.values())
+ interimResults.put(p, new ArrayList<PackageDoc>());
- private void initProfilePackages() throws IOException {
- profilePackages = new HashMap<String,PackageDoc[]>();
- ArrayList<PackageDoc> results;
- Map<String,PackageDoc> packageIndex = new HashMap<String,PackageDoc>();
- for (int i = 0; i < packages.length; i++) {
- PackageDoc pkg = packages[i];
- packageIndex.put(pkg.name(), pkg);
+ for (PackageDoc pkg: packages) {
+ if (nodeprecated && Util.isDeprecated(pkg)) {
+ continue;
+ }
+ // the getProfile method takes a type name, not a package name,
+ // but isn't particularly fussy about the simple name -- so just use *
+ int i = profiles.getProfile(pkg.name().replace(".", "/") + "/*");
+ Profile p = Profile.lookup(i);
+ if (p != null) {
+ List<PackageDoc> pkgs = interimResults.get(p);
+ pkgs.add(pkg);
+ }
}
- for (int i = 1; i < profiles.getProfileCount(); i++) {
- Set<String> profPkgs = profiles.getPackages(i);
- results = new ArrayList<PackageDoc>();
- for (String packageName : profPkgs) {
- packageName = packageName.replace("/", ".");
- PackageDoc profPkg = packageIndex.get(packageName);
- if (profPkg != null) {
- results.add(profPkg);
- }
- }
- Collections.sort(results);
- PackageDoc[] profilePkgs = results.toArray(new PackageDoc[]{});
- profilePackages.put(Profile.lookup(i).name, profilePkgs);
+
+ // Build the profilePackages structure used by the doclet
+ profilePackages = new HashMap<String,PackageDoc[]>();
+ List<PackageDoc> prev = Collections.<PackageDoc>emptyList();
+ int size;
+ for (Map.Entry<Profile,List<PackageDoc>> e: interimResults.entrySet()) {
+ Profile p = e.getKey();
+ List<PackageDoc> pkgs = e.getValue();
+ pkgs.addAll(prev); // each profile contains all lower profiles
+ Collections.sort(pkgs);
+ size = pkgs.size();
+ // For a profile, if there are no packages to be documented, do not add
+ // it to profilePackages map.
+ if (size > 0)
+ profilePackages.put(p.name, pkgs.toArray(new PackageDoc[pkgs.size()]));
+ prev = pkgs;
}
+
+ // Generate profiles documentation if any profile contains any
+ // of the packages to be documented.
+ showProfiles = !prev.isEmpty();
}
private void initPackageArray() {
@@ -534,13 +551,10 @@
public void setOptions() throws Fault {
initPackageArray();
setOptions(root.options());
- if (!profilespath.isEmpty()) {
- try {
- initProfiles();
- initProfilePackages();
- } catch (Exception e) {
- throw new DocletAbortException(e);
- }
+ try {
+ initProfiles();
+ } catch (Exception e) {
+ throw new DocletAbortException(e);
}
setSpecificDocletOptions(root.options());
}
@@ -713,6 +727,17 @@
}
/**
+ * Check the validity of the given profile. Return false if there are no
+ * valid packages to be documented for the profile.
+ *
+ * @param profileName the profile that needs to be validated.
+ * @return true if the profile has valid packages to be documented.
+ */
+ public boolean shouldDocumentProfile(String profileName) {
+ return profilePackages.containsKey(profileName);
+ }
+
+ /**
* Check the validity of the given Source or Output File encoding on this
* platform.
*
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/stylesheet.css Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/stylesheet.css Sat Sep 14 20:43:34 2013 +0100
@@ -180,6 +180,12 @@
margin: auto 5px;
border:1px solid #c9aa44;
}
+.skipNav {
+ position:absolute;
+ top:auto;
+ left:-9999px;
+ overflow:hidden;
+ }
/*
Page header and footer styles
*/
@@ -372,7 +378,6 @@
overflow:hidden;
padding:0px;
margin:0px;
- white-space:pre;
}
caption a:link, caption a:hover, caption a:active, caption a:visited {
color:#FFFFFF;
@@ -381,35 +386,32 @@
white-space:nowrap;
padding-top:8px;
padding-left:8px;
- display:block;
+ display:inline-block;
float:left;
background-image:url(resources/titlebar.gif);
- height:18px;
}
.contentContainer ul.blockList li.blockList caption span.activeTableTab span {
white-space:nowrap;
padding-top:8px;
padding-left:8px;
- display:block;
+ display:inline-block;
float:left;
background-image:url(resources/activetitlebar.gif);
- height:18px;
}
.contentContainer ul.blockList li.blockList caption span.tableTab span {
white-space:nowrap;
padding-top:8px;
padding-left:8px;
- display:block;
+ display:inline-block;
float:left;
background-image:url(resources/titlebar.gif);
- height:18px;
}
.contentContainer ul.blockList li.blockList caption span.tableTab, .contentContainer ul.blockList li.blockList caption span.activeTableTab {
padding-top:0px;
padding-left:0px;
background-image:none;
float:none;
- display:inline;
+ display:inline-block;
}
.overviewSummary .tabEnd, .packageSummary .tabEnd, .contentContainer ul.blockList li.blockList .tabEnd, .summary .tabEnd, .classUseContainer .tabEnd, .constantValuesContainer .tabEnd {
width:10px;
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/taglets/LegacyTaglet.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/taglets/LegacyTaglet.java Sat Sep 14 20:43:34 2013 +0100
@@ -130,7 +130,13 @@
public Content getTagletOutput(Doc holder, TagletWriter writer)
throws IllegalArgumentException {
Content output = writer.getOutputInstance();
- output.addContent(new RawHtml(legacyTaglet.toString(holder.tags(getName()))));
+ Tag[] tags = holder.tags(getName());
+ if (tags.length > 0) {
+ String tagString = legacyTaglet.toString(tags);
+ if (tagString != null) {
+ output.addContent(new RawHtml(tagString));
+ }
+ }
return output;
}
}
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/PathDocFileFactory.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/PathDocFileFactory.java Sat Sep 14 20:43:34 2013 +0100
@@ -34,6 +34,7 @@
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
+import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -221,8 +222,10 @@
/** If the file is a directory, list its contents. */
public Iterable<DocFile> list() throws IOException {
List<DocFile> files = new ArrayList<DocFile>();
- for (Path f: Files.newDirectoryStream(file)) {
- files.add(new StandardDocFile(f));
+ try (DirectoryStream<Path> ds = Files.newDirectoryStream(file)) {
+ for (Path f: ds) {
+ files.add(new StandardDocFile(f));
+ }
}
return files;
}
--- a/langtools/src/share/classes/com/sun/tools/javac/Main.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/Main.java Sat Sep 14 20:43:34 2013 +0100
@@ -30,14 +30,6 @@
/**
* The programmatic interface for the Java Programming Language
* compiler, javac.
- *
- * <p>Except for the two methods
- * {@link #compile(java.lang.String[])}
- * {@link #compile(java.lang.String[],java.io.PrintWriter)},
- * nothing described in this source file is part of any supported
- * API. If you write code that depends on this, you do so at your own
- * risk. This code and its internal interfaces are subject to change
- * or deletion without notice.
*/
@jdk.Supported
public class Main {
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Annotations.java Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,451 +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. 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 com.sun.tools.javac.code;
-
-import java.util.Map;
-
-import javax.tools.JavaFileObject;
-
-import com.sun.tools.javac.comp.Annotate;
-import com.sun.tools.javac.comp.AttrContext;
-import com.sun.tools.javac.comp.Env;
-import com.sun.tools.javac.util.*;
-import com.sun.tools.javac.util.Assert;
-import com.sun.tools.javac.util.List;
-import com.sun.tools.javac.util.Log;
-import com.sun.tools.javac.util.Pair;
-import static com.sun.tools.javac.code.Kinds.PCK;
-
-/**
- * Container for all annotations (attributes in javac) on a Symbol.
- *
- * This class is explicitly mutable. Its contents will change when attributes
- * are annotated onto the Symbol. However this class depends on the facts that
- * List (in javac) is immutable.
- *
- * An instance of this class can be in one of three states:
- *
- * NOT_STARTED indicates that the Symbol this instance belongs to has not been
- * annotated (yet). Specifically if the declaration is not annotated this
- * instance will never move past NOT_STARTED. You can never go back to
- * NOT_STARTED.
- *
- * IN_PROGRESS annotations have been found on the declaration. Will be processed
- * later. You can reset to IN_PROGRESS. While IN_PROGRESS you can set the list
- * of attributes (and this moves out of the IN_PROGRESS state).
- *
- * "unnamed" this Annotations contains some attributes, possibly the final set.
- * While in this state you can only prepend or append to the attributes not set
- * it directly. You can also move back to the IN_PROGRESS state using reset().
- *
- * <p><b>This is NOT part of any supported API. If you write code that depends
- * on this, you do so at your own risk. This code and its internal interfaces
- * are subject to change or deletion without notice.</b>
- */
-public class Annotations {
-
- private static final List<Attribute.Compound> DECL_NOT_STARTED = List.of(null);
- private static final List<Attribute.Compound> DECL_IN_PROGRESS = List.of(null);
-
- /*
- * This field should never be null
- */
- private List<Attribute.Compound> attributes = DECL_NOT_STARTED;
-
- /*
- * Type attributes for this symbol.
- * This field should never be null.
- */
- private List<Attribute.TypeCompound> type_attributes = List.<Attribute.TypeCompound>nil();
-
- /*
- * Type attributes of initializers in this class.
- * Unused if the current symbol is not a ClassSymbol.
- */
- private List<Attribute.TypeCompound> init_type_attributes = List.<Attribute.TypeCompound>nil();
-
- /*
- * Type attributes of class initializers in this class.
- * Unused if the current symbol is not a ClassSymbol.
- */
- private List<Attribute.TypeCompound> clinit_type_attributes = List.<Attribute.TypeCompound>nil();
-
- /*
- * The Symbol this Annotations instance belongs to
- */
- private final Symbol sym;
-
- public Annotations(Symbol sym) {
- this.sym = sym;
- }
-
- public List<Attribute.Compound> getDeclarationAttributes() {
- return filterDeclSentinels(attributes);
- }
-
- public List<Attribute.TypeCompound> getTypeAttributes() {
- return type_attributes;
- }
-
- public List<Attribute.TypeCompound> getInitTypeAttributes() {
- return init_type_attributes;
- }
-
- public List<Attribute.TypeCompound> getClassInitTypeAttributes() {
- return clinit_type_attributes;
- }
-
- public void setDeclarationAttributes(List<Attribute.Compound> a) {
- Assert.check(pendingCompletion() || !isStarted());
- if (a == null) {
- throw new NullPointerException();
- }
- attributes = a;
- }
-
- public void setTypeAttributes(List<Attribute.TypeCompound> a) {
- if (a == null) {
- throw new NullPointerException();
- }
- type_attributes = a;
- }
-
- public void setInitTypeAttributes(List<Attribute.TypeCompound> a) {
- if (a == null) {
- throw new NullPointerException();
- }
- init_type_attributes = a;
- }
-
- public void setClassInitTypeAttributes(List<Attribute.TypeCompound> a) {
- if (a == null) {
- throw new NullPointerException();
- }
- clinit_type_attributes = a;
- }
-
- public void setAttributes(Annotations other) {
- if (other == null) {
- throw new NullPointerException();
- }
- setDeclarationAttributes(other.getDeclarationAttributes());
- setTypeAttributes(other.getTypeAttributes());
- setInitTypeAttributes(other.getInitTypeAttributes());
- setClassInitTypeAttributes(other.getClassInitTypeAttributes());
- }
-
- public void setDeclarationAttributesWithCompletion(final Annotate.AnnotateRepeatedContext<Attribute.Compound> ctx) {
- Assert.check(pendingCompletion() || (!isStarted() && sym.kind == PCK));
- this.setDeclarationAttributes(getAttributesForCompletion(ctx));
- }
-
- public void appendTypeAttributesWithCompletion(final Annotate.AnnotateRepeatedContext<Attribute.TypeCompound> ctx) {
- this.appendUniqueTypes(getAttributesForCompletion(ctx));
- }
-
- private <T extends Attribute.Compound> List<T> getAttributesForCompletion(
- final Annotate.AnnotateRepeatedContext<T> ctx) {
-
- Map<Symbol.TypeSymbol, ListBuffer<T>> annotated = ctx.annotated;
- boolean atLeastOneRepeated = false;
- List<T> buf = List.<T>nil();
- for (ListBuffer<T> lb : annotated.values()) {
- if (lb.size() == 1) {
- buf = buf.prepend(lb.first());
- } else { // repeated
- // This will break when other subtypes of Attributs.Compound
- // are introduced, because PlaceHolder is a subtype of TypeCompound.
- T res;
- @SuppressWarnings("unchecked")
- T ph = (T) new Placeholder<T>(ctx, lb.toList(), sym);
- res = ph;
- buf = buf.prepend(res);
- atLeastOneRepeated = true;
- }
- }
-
- if (atLeastOneRepeated) {
- // The Symbol s is now annotated with a combination of
- // finished non-repeating annotations and placeholders for
- // repeating annotations.
- //
- // We need to do this in two passes because when creating
- // a container for a repeating annotation we must
- // guarantee that the @Repeatable on the
- // contained annotation is fully annotated
- //
- // The way we force this order is to do all repeating
- // annotations in a pass after all non-repeating are
- // finished. This will work because @Repeatable
- // is non-repeating and therefore will be annotated in the
- // fist pass.
-
- // Queue a pass that will replace Attribute.Placeholders
- // with Attribute.Compound (made from synthesized containers).
- ctx.annotateRepeated(new Annotate.Annotator() {
- @Override
- public String toString() {
- return "repeated annotation pass of: " + sym + " in: " + sym.owner;
- }
-
- @Override
- public void enterAnnotation() {
- complete(ctx);
- }
- });
- }
- // Add non-repeating attributes
- return buf.reverse();
- }
-
- public Annotations reset() {
- attributes = DECL_IN_PROGRESS;
- return this;
- }
-
- public boolean isEmpty() {
- return !isStarted()
- || pendingCompletion()
- || attributes.isEmpty();
- }
-
- public boolean isTypesEmpty() {
- return type_attributes.isEmpty();
- }
-
- public boolean pendingCompletion() {
- return attributes == DECL_IN_PROGRESS;
- }
-
- public Annotations append(List<Attribute.Compound> l) {
- attributes = filterDeclSentinels(attributes);
-
- if (l.isEmpty()) {
- ; // no-op
- } else if (attributes.isEmpty()) {
- attributes = l;
- } else {
- attributes = attributes.appendList(l);
- }
- return this;
- }
-
- public Annotations appendUniqueTypes(List<Attribute.TypeCompound> l) {
- if (l.isEmpty()) {
- ; // no-op
- } else if (type_attributes.isEmpty()) {
- type_attributes = l;
- } else {
- // TODO: in case we expect a large number of annotations, this
- // might be inefficient.
- for (Attribute.TypeCompound tc : l) {
- if (!type_attributes.contains(tc))
- type_attributes = type_attributes.append(tc);
- }
- }
- return this;
- }
-
- public Annotations appendInitTypeAttributes(List<Attribute.TypeCompound> l) {
- if (l.isEmpty()) {
- ; // no-op
- } else if (init_type_attributes.isEmpty()) {
- init_type_attributes = l;
- } else {
- init_type_attributes = init_type_attributes.appendList(l);
- }
- return this;
- }
-
- public Annotations appendClassInitTypeAttributes(List<Attribute.TypeCompound> l) {
- if (l.isEmpty()) {
- ; // no-op
- } else if (clinit_type_attributes.isEmpty()) {
- clinit_type_attributes = l;
- } else {
- clinit_type_attributes = clinit_type_attributes.appendList(l);
- }
- return this;
- }
-
- public Annotations prepend(List<Attribute.Compound> l) {
- attributes = filterDeclSentinels(attributes);
-
- if (l.isEmpty()) {
- ; // no-op
- } else if (attributes.isEmpty()) {
- attributes = l;
- } else {
- attributes = attributes.prependList(l);
- }
- return this;
- }
-
- private List<Attribute.Compound> filterDeclSentinels(List<Attribute.Compound> a) {
- return (a == DECL_IN_PROGRESS || a == DECL_NOT_STARTED)
- ? List.<Attribute.Compound>nil()
- : a;
- }
-
- private boolean isStarted() {
- return attributes != DECL_NOT_STARTED;
- }
-
- private List<Attribute.Compound> getPlaceholders() {
- List<Attribute.Compound> res = List.<Attribute.Compound>nil();
- for (Attribute.Compound a : filterDeclSentinels(attributes)) {
- if (a instanceof Placeholder) {
- res = res.prepend(a);
- }
- }
- return res.reverse();
- }
-
- private List<Attribute.TypeCompound> getTypePlaceholders() {
- List<Attribute.TypeCompound> res = List.<Attribute.TypeCompound>nil();
- for (Attribute.TypeCompound a : type_attributes) {
- if (a instanceof Placeholder) {
- res = res.prepend(a);
- }
- }
- return res.reverse();
- }
-
- /*
- * Replace Placeholders for repeating annotations with their containers
- */
- private <T extends Attribute.Compound> void complete(Annotate.AnnotateRepeatedContext<T> ctx) {
- Log log = ctx.log;
- Env<AttrContext> env = ctx.env;
- JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile);
- try {
- // TODO: can we reduce duplication in the following branches?
- if (ctx.isTypeCompound) {
- Assert.check(!isTypesEmpty());
-
- if (isTypesEmpty()) {
- return;
- }
-
- List<Attribute.TypeCompound> result = List.nil();
- for (Attribute.TypeCompound a : getTypeAttributes()) {
- if (a instanceof Placeholder) {
- @SuppressWarnings("unchecked")
- Placeholder<Attribute.TypeCompound> ph = (Placeholder<Attribute.TypeCompound>) a;
- Attribute.TypeCompound replacement = replaceOne(ph, ph.getRepeatedContext());
-
- if (null != replacement) {
- result = result.prepend(replacement);
- }
- } else {
- result = result.prepend(a);
- }
- }
-
- type_attributes = result.reverse();
-
- Assert.check(Annotations.this.getTypePlaceholders().isEmpty());
- } else {
- Assert.check(!pendingCompletion());
-
- if (isEmpty()) {
- return;
- }
-
- List<Attribute.Compound> result = List.nil();
- for (Attribute.Compound a : getDeclarationAttributes()) {
- if (a instanceof Placeholder) {
- @SuppressWarnings("unchecked")
- Attribute.Compound replacement = replaceOne((Placeholder<T>) a, ctx);
-
- if (null != replacement) {
- result = result.prepend(replacement);
- }
- } else {
- result = result.prepend(a);
- }
- }
-
- attributes = result.reverse();
-
- Assert.check(Annotations.this.getPlaceholders().isEmpty());
- }
- } finally {
- log.useSource(oldSource);
- }
- }
-
- private <T extends Attribute.Compound> T replaceOne(Placeholder<T> placeholder, Annotate.AnnotateRepeatedContext<T> ctx) {
- Log log = ctx.log;
-
- // Process repeated annotations
- T validRepeated = ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor(), sym);
-
- if (validRepeated != null) {
- // Check that the container isn't manually
- // present along with repeated instances of
- // its contained annotation.
- ListBuffer<T> manualContainer = ctx.annotated.get(validRepeated.type.tsym);
- if (manualContainer != null) {
- log.error(ctx.pos.get(manualContainer.first()), "invalid.repeatable.annotation.repeated.and.container.present",
- manualContainer.first().type.tsym);
- }
- }
-
- // A null return will delete the Placeholder
- return validRepeated;
- }
-
- private static class Placeholder<T extends Attribute.Compound> extends Attribute.TypeCompound {
-
- private final Annotate.AnnotateRepeatedContext<T> ctx;
- private final List<T> placeholderFor;
- private final Symbol on;
-
- public Placeholder(Annotate.AnnotateRepeatedContext<T> ctx, List<T> placeholderFor, Symbol on) {
- super(on.type, List.<Pair<Symbol.MethodSymbol, Attribute>>nil(),
- ctx.isTypeCompound ?
- ((Attribute.TypeCompound)placeholderFor.head).position :
- null);
- this.ctx = ctx;
- this.placeholderFor = placeholderFor;
- this.on = on;
- }
-
- @Override
- public String toString() {
- return "<placeholder: " + placeholderFor + " on: " + on + ">";
- }
-
- public List<T> getPlaceholderFor() {
- return placeholderFor;
- }
-
- public Annotate.AnnotateRepeatedContext<T> getRepeatedContext() {
- return ctx;
- }
- }
-}
--- a/langtools/src/share/classes/com/sun/tools/javac/code/DeferredLintHandler.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/DeferredLintHandler.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,8 @@
import java.util.HashMap;
import java.util.Map;
+import com.sun.tools.javac.tree.EndPosTable;
+import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@@ -53,10 +55,13 @@
protected DeferredLintHandler(Context context) {
context.put(deferredLintHandlerKey, this);
+ this.currentPos = IMMEDIATE_POSITION;
}
- private DeferredLintHandler() {}
-
+ /**An interface for deferred lint reporting - loggers passed to
+ * {@link #report(LintLogger) } will be called when
+ * {@link #flush(DiagnosticPosition) } is invoked.
+ */
public interface LintLogger {
void report();
}
@@ -64,12 +69,26 @@
private DiagnosticPosition currentPos;
private Map<DiagnosticPosition, ListBuffer<LintLogger>> loggersQueue = new HashMap<DiagnosticPosition, ListBuffer<LintLogger>>();
+ /**Associate the given logger with the current position as set by {@link #setPos(DiagnosticPosition) }.
+ * Will be invoked when {@link #flush(DiagnosticPosition) } will be invoked with the same position.
+ * <br>
+ * Will invoke the logger synchronously if {@link #immediate() } was called
+ * instead of {@link #setPos(DiagnosticPosition) }.
+ */
public void report(LintLogger logger) {
- ListBuffer<LintLogger> loggers = loggersQueue.get(currentPos);
- Assert.checkNonNull(loggers);
- loggers.append(logger);
+ if (currentPos == IMMEDIATE_POSITION) {
+ logger.report();
+ } else {
+ ListBuffer<LintLogger> loggers = loggersQueue.get(currentPos);
+ if (loggers == null) {
+ loggersQueue.put(currentPos, loggers = ListBuffer.<LintLogger>lb());
+ }
+ loggers.append(logger);
+ }
}
+ /**Invoke all {@link LintLogger}s that were associated with the provided {@code pos}.
+ */
public void flush(DiagnosticPosition pos) {
ListBuffer<LintLogger> loggers = loggersQueue.get(pos);
if (loggers != null) {
@@ -80,16 +99,46 @@
}
}
- public DeferredLintHandler setPos(DiagnosticPosition currentPos) {
+ /**Sets the current position to the provided {@code currentPos}. {@link LintLogger}s
+ * passed to subsequent invocations of {@link #report(LintLogger) } will be associated
+ * with the given position.
+ */
+ public DiagnosticPosition setPos(DiagnosticPosition currentPos) {
+ DiagnosticPosition prevPosition = this.currentPos;
this.currentPos = currentPos;
- loggersQueue.put(currentPos, ListBuffer.<LintLogger>lb());
- return this;
+ return prevPosition;
+ }
+
+ /**{@link LintLogger}s passed to subsequent invocations of
+ * {@link #report(LintLogger) } will be invoked immediately.
+ */
+ public DiagnosticPosition immediate() {
+ return setPos(IMMEDIATE_POSITION);
}
- public static final DeferredLintHandler immediateHandler = new DeferredLintHandler() {
+ private static final DiagnosticPosition IMMEDIATE_POSITION = new DiagnosticPosition() {
+ @Override
+ public JCTree getTree() {
+ Assert.error();
+ return null;
+ }
+
@Override
- public void report(LintLogger logger) {
- logger.report();
+ public int getStartPosition() {
+ Assert.error();
+ return -1;
+ }
+
+ @Override
+ public int getPreferredPosition() {
+ Assert.error();
+ return -1;
+ }
+
+ @Override
+ public int getEndPosition(EndPosTable endPosTable) {
+ Assert.error();
+ return -1;
}
};
}
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Flags.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Flags.java Sat Sep 14 20:43:34 2013 +0100
@@ -97,7 +97,6 @@
public static final int MANDATED = 1<<15;
public static final int StandardFlags = 0x0fff;
- public static final int ModifierFlags = StandardFlags & ~INTERFACE;
// Because the following access flags are overloaded with other
// bit positions, we translate them when reading and writing class
@@ -266,6 +265,11 @@
*/
public static final long THROWS = 1L<<47;
+ /**
+ * Flag that marks potentially ambiguous overloads
+ */
+ public static final long POTENTIALLY_AMBIGUOUS = 1L<<48;
+
/** Modifier masks.
*/
public static final int
@@ -282,7 +286,9 @@
SYNCHRONIZED | FINAL | STRICTFP;
public static final long
ExtendedStandardFlags = (long)StandardFlags | DEFAULT,
+ ModifierFlags = ((long)StandardFlags & ~INTERFACE) | DEFAULT,
InterfaceMethodMask = ABSTRACT | STATIC | PUBLIC | STRICTFP | DEFAULT,
+ AnnotationTypeElementMask = FINAL | ABSTRACT | PUBLIC | STRICTFP,
LocalVarFlags = FINAL | PARAMETER;
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Lint.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Lint.java Sat Sep 14 20:43:34 2013 +0100
@@ -33,9 +33,6 @@
import com.sun.tools.javac.util.Options;
import com.sun.tools.javac.util.Pair;
-import static com.sun.tools.javac.code.Flags.*;
-
-
/**
* A class for handling -Xlint suboptions and @SuppresssWarnings.
*
@@ -81,7 +78,6 @@
return l;
}
-
private final AugmentVisitor augmentor;
private final EnumSet<LintCategory> values;
@@ -90,7 +86,6 @@
private static final Map<String, LintCategory> map =
new java.util.concurrent.ConcurrentHashMap<String, LintCategory>(20);
-
protected Lint(Context context) {
// initialize values according to the lint options
Options options = Options.instance(context);
@@ -175,6 +170,11 @@
OPTIONS("options"),
/**
+ * Warn about issues regarding method overloads.
+ */
+ OVERLOADS("overloads"),
+
+ /**
* Warn about issues regarding method overrides.
*/
OVERRIDES("overrides"),
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Sat Sep 14 20:43:34 2013 +0100
@@ -46,6 +46,7 @@
import static com.sun.tools.javac.code.TypeTag.CLASS;
import static com.sun.tools.javac.code.TypeTag.FORALL;
import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
/** Root class for Java symbols. It contains subclasses
* for specific sorts of symbols, such as variables, methods and operators,
@@ -98,9 +99,9 @@
// <editor-fold defaultstate="collapsed" desc="annotations">
/** The attributes of this symbol are contained in this
- * Annotations. The Annotations instance is NOT immutable.
+ * SymbolMetadata. The SymbolMetadata instance is NOT immutable.
*/
- protected Annotations annotations;
+ protected SymbolMetadata annotations;
/** An accessor method for the attributes of this symbol.
* Attributes of class symbols should be accessed through the accessor
@@ -217,19 +218,19 @@
public void setTypeAttributes(List<Attribute.TypeCompound> a) {
if (annotations != null || a.nonEmpty()) {
if (annotations == null)
- annotations = new Annotations(this);
+ annotations = new SymbolMetadata(this);
annotations.setTypeAttributes(a);
}
}
- private Annotations initedAnnos() {
+ private SymbolMetadata initedAnnos() {
if (annotations == null)
- annotations = new Annotations(this);
+ annotations = new SymbolMetadata(this);
return annotations;
}
/** This method is intended for debugging only. */
- public Annotations getAnnotations() {
+ public SymbolMetadata getAnnotations() {
return annotations;
}
@@ -852,7 +853,7 @@
private void mergeAttributes() {
if (annotations == null &&
package_info.annotations != null) {
- annotations = new Annotations(this);
+ annotations = new SymbolMetadata(this);
annotations.setAttributes(package_info.annotations);
}
}
@@ -1167,11 +1168,11 @@
public void setLazyConstValue(final Env<AttrContext> env,
final Attr attr,
- final JCTree.JCExpression initializer)
+ final JCVariableDecl variable)
{
setData(new Callable<Object>() {
public Object call() {
- return attr.attribLazyConstantValue(env, initializer, type);
+ return attr.attribLazyConstantValue(env, variable, type);
}
});
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/SymbolMetadata.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,451 @@
+/*
+ * 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. 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 com.sun.tools.javac.code;
+
+import java.util.Map;
+
+import javax.tools.JavaFileObject;
+
+import com.sun.tools.javac.comp.Annotate;
+import com.sun.tools.javac.comp.AttrContext;
+import com.sun.tools.javac.comp.Env;
+import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.Assert;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Pair;
+import static com.sun.tools.javac.code.Kinds.PCK;
+
+/**
+ * Container for all annotations (attributes in javac) on a Symbol.
+ *
+ * This class is explicitly mutable. Its contents will change when attributes
+ * are annotated onto the Symbol. However this class depends on the facts that
+ * List (in javac) is immutable.
+ *
+ * An instance of this class can be in one of three states:
+ *
+ * NOT_STARTED indicates that the Symbol this instance belongs to has not been
+ * annotated (yet). Specifically if the declaration is not annotated this
+ * instance will never move past NOT_STARTED. You can never go back to
+ * NOT_STARTED.
+ *
+ * IN_PROGRESS annotations have been found on the declaration. Will be processed
+ * later. You can reset to IN_PROGRESS. While IN_PROGRESS you can set the list
+ * of attributes (and this moves out of the IN_PROGRESS state).
+ *
+ * "unnamed" this SymbolMetadata contains some attributes, possibly the final set.
+ * While in this state you can only prepend or append to the attributes not set
+ * it directly. You can also move back to the IN_PROGRESS state using reset().
+ *
+ * <p><b>This is NOT part of any supported API. If you write code that depends
+ * on this, you do so at your own risk. This code and its internal interfaces
+ * are subject to change or deletion without notice.</b>
+ */
+public class SymbolMetadata {
+
+ private static final List<Attribute.Compound> DECL_NOT_STARTED = List.of(null);
+ private static final List<Attribute.Compound> DECL_IN_PROGRESS = List.of(null);
+
+ /*
+ * This field should never be null
+ */
+ private List<Attribute.Compound> attributes = DECL_NOT_STARTED;
+
+ /*
+ * Type attributes for this symbol.
+ * This field should never be null.
+ */
+ private List<Attribute.TypeCompound> type_attributes = List.<Attribute.TypeCompound>nil();
+
+ /*
+ * Type attributes of initializers in this class.
+ * Unused if the current symbol is not a ClassSymbol.
+ */
+ private List<Attribute.TypeCompound> init_type_attributes = List.<Attribute.TypeCompound>nil();
+
+ /*
+ * Type attributes of class initializers in this class.
+ * Unused if the current symbol is not a ClassSymbol.
+ */
+ private List<Attribute.TypeCompound> clinit_type_attributes = List.<Attribute.TypeCompound>nil();
+
+ /*
+ * The Symbol this SymbolMetadata instance belongs to
+ */
+ private final Symbol sym;
+
+ public SymbolMetadata(Symbol sym) {
+ this.sym = sym;
+ }
+
+ public List<Attribute.Compound> getDeclarationAttributes() {
+ return filterDeclSentinels(attributes);
+ }
+
+ public List<Attribute.TypeCompound> getTypeAttributes() {
+ return type_attributes;
+ }
+
+ public List<Attribute.TypeCompound> getInitTypeAttributes() {
+ return init_type_attributes;
+ }
+
+ public List<Attribute.TypeCompound> getClassInitTypeAttributes() {
+ return clinit_type_attributes;
+ }
+
+ public void setDeclarationAttributes(List<Attribute.Compound> a) {
+ Assert.check(pendingCompletion() || !isStarted());
+ if (a == null) {
+ throw new NullPointerException();
+ }
+ attributes = a;
+ }
+
+ public void setTypeAttributes(List<Attribute.TypeCompound> a) {
+ if (a == null) {
+ throw new NullPointerException();
+ }
+ type_attributes = a;
+ }
+
+ public void setInitTypeAttributes(List<Attribute.TypeCompound> a) {
+ if (a == null) {
+ throw new NullPointerException();
+ }
+ init_type_attributes = a;
+ }
+
+ public void setClassInitTypeAttributes(List<Attribute.TypeCompound> a) {
+ if (a == null) {
+ throw new NullPointerException();
+ }
+ clinit_type_attributes = a;
+ }
+
+ public void setAttributes(SymbolMetadata other) {
+ if (other == null) {
+ throw new NullPointerException();
+ }
+ setDeclarationAttributes(other.getDeclarationAttributes());
+ setTypeAttributes(other.getTypeAttributes());
+ setInitTypeAttributes(other.getInitTypeAttributes());
+ setClassInitTypeAttributes(other.getClassInitTypeAttributes());
+ }
+
+ public void setDeclarationAttributesWithCompletion(final Annotate.AnnotateRepeatedContext<Attribute.Compound> ctx) {
+ Assert.check(pendingCompletion() || (!isStarted() && sym.kind == PCK));
+ this.setDeclarationAttributes(getAttributesForCompletion(ctx));
+ }
+
+ public void appendTypeAttributesWithCompletion(final Annotate.AnnotateRepeatedContext<Attribute.TypeCompound> ctx) {
+ this.appendUniqueTypes(getAttributesForCompletion(ctx));
+ }
+
+ private <T extends Attribute.Compound> List<T> getAttributesForCompletion(
+ final Annotate.AnnotateRepeatedContext<T> ctx) {
+
+ Map<Symbol.TypeSymbol, ListBuffer<T>> annotated = ctx.annotated;
+ boolean atLeastOneRepeated = false;
+ List<T> buf = List.<T>nil();
+ for (ListBuffer<T> lb : annotated.values()) {
+ if (lb.size() == 1) {
+ buf = buf.prepend(lb.first());
+ } else { // repeated
+ // This will break when other subtypes of Attributs.Compound
+ // are introduced, because PlaceHolder is a subtype of TypeCompound.
+ T res;
+ @SuppressWarnings("unchecked")
+ T ph = (T) new Placeholder<T>(ctx, lb.toList(), sym);
+ res = ph;
+ buf = buf.prepend(res);
+ atLeastOneRepeated = true;
+ }
+ }
+
+ if (atLeastOneRepeated) {
+ // The Symbol s is now annotated with a combination of
+ // finished non-repeating annotations and placeholders for
+ // repeating annotations.
+ //
+ // We need to do this in two passes because when creating
+ // a container for a repeating annotation we must
+ // guarantee that the @Repeatable on the
+ // contained annotation is fully annotated
+ //
+ // The way we force this order is to do all repeating
+ // annotations in a pass after all non-repeating are
+ // finished. This will work because @Repeatable
+ // is non-repeating and therefore will be annotated in the
+ // fist pass.
+
+ // Queue a pass that will replace Attribute.Placeholders
+ // with Attribute.Compound (made from synthesized containers).
+ ctx.annotateRepeated(new Annotate.Annotator() {
+ @Override
+ public String toString() {
+ return "repeated annotation pass of: " + sym + " in: " + sym.owner;
+ }
+
+ @Override
+ public void enterAnnotation() {
+ complete(ctx);
+ }
+ });
+ }
+ // Add non-repeating attributes
+ return buf.reverse();
+ }
+
+ public SymbolMetadata reset() {
+ attributes = DECL_IN_PROGRESS;
+ return this;
+ }
+
+ public boolean isEmpty() {
+ return !isStarted()
+ || pendingCompletion()
+ || attributes.isEmpty();
+ }
+
+ public boolean isTypesEmpty() {
+ return type_attributes.isEmpty();
+ }
+
+ public boolean pendingCompletion() {
+ return attributes == DECL_IN_PROGRESS;
+ }
+
+ public SymbolMetadata append(List<Attribute.Compound> l) {
+ attributes = filterDeclSentinels(attributes);
+
+ if (l.isEmpty()) {
+ ; // no-op
+ } else if (attributes.isEmpty()) {
+ attributes = l;
+ } else {
+ attributes = attributes.appendList(l);
+ }
+ return this;
+ }
+
+ public SymbolMetadata appendUniqueTypes(List<Attribute.TypeCompound> l) {
+ if (l.isEmpty()) {
+ ; // no-op
+ } else if (type_attributes.isEmpty()) {
+ type_attributes = l;
+ } else {
+ // TODO: in case we expect a large number of annotations, this
+ // might be inefficient.
+ for (Attribute.TypeCompound tc : l) {
+ if (!type_attributes.contains(tc))
+ type_attributes = type_attributes.append(tc);
+ }
+ }
+ return this;
+ }
+
+ public SymbolMetadata appendInitTypeAttributes(List<Attribute.TypeCompound> l) {
+ if (l.isEmpty()) {
+ ; // no-op
+ } else if (init_type_attributes.isEmpty()) {
+ init_type_attributes = l;
+ } else {
+ init_type_attributes = init_type_attributes.appendList(l);
+ }
+ return this;
+ }
+
+ public SymbolMetadata appendClassInitTypeAttributes(List<Attribute.TypeCompound> l) {
+ if (l.isEmpty()) {
+ ; // no-op
+ } else if (clinit_type_attributes.isEmpty()) {
+ clinit_type_attributes = l;
+ } else {
+ clinit_type_attributes = clinit_type_attributes.appendList(l);
+ }
+ return this;
+ }
+
+ public SymbolMetadata prepend(List<Attribute.Compound> l) {
+ attributes = filterDeclSentinels(attributes);
+
+ if (l.isEmpty()) {
+ ; // no-op
+ } else if (attributes.isEmpty()) {
+ attributes = l;
+ } else {
+ attributes = attributes.prependList(l);
+ }
+ return this;
+ }
+
+ private List<Attribute.Compound> filterDeclSentinels(List<Attribute.Compound> a) {
+ return (a == DECL_IN_PROGRESS || a == DECL_NOT_STARTED)
+ ? List.<Attribute.Compound>nil()
+ : a;
+ }
+
+ private boolean isStarted() {
+ return attributes != DECL_NOT_STARTED;
+ }
+
+ private List<Attribute.Compound> getPlaceholders() {
+ List<Attribute.Compound> res = List.<Attribute.Compound>nil();
+ for (Attribute.Compound a : filterDeclSentinels(attributes)) {
+ if (a instanceof Placeholder) {
+ res = res.prepend(a);
+ }
+ }
+ return res.reverse();
+ }
+
+ private List<Attribute.TypeCompound> getTypePlaceholders() {
+ List<Attribute.TypeCompound> res = List.<Attribute.TypeCompound>nil();
+ for (Attribute.TypeCompound a : type_attributes) {
+ if (a instanceof Placeholder) {
+ res = res.prepend(a);
+ }
+ }
+ return res.reverse();
+ }
+
+ /*
+ * Replace Placeholders for repeating annotations with their containers
+ */
+ private <T extends Attribute.Compound> void complete(Annotate.AnnotateRepeatedContext<T> ctx) {
+ Log log = ctx.log;
+ Env<AttrContext> env = ctx.env;
+ JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile);
+ try {
+ // TODO: can we reduce duplication in the following branches?
+ if (ctx.isTypeCompound) {
+ Assert.check(!isTypesEmpty());
+
+ if (isTypesEmpty()) {
+ return;
+ }
+
+ List<Attribute.TypeCompound> result = List.nil();
+ for (Attribute.TypeCompound a : getTypeAttributes()) {
+ if (a instanceof Placeholder) {
+ @SuppressWarnings("unchecked")
+ Placeholder<Attribute.TypeCompound> ph = (Placeholder<Attribute.TypeCompound>) a;
+ Attribute.TypeCompound replacement = replaceOne(ph, ph.getRepeatedContext());
+
+ if (null != replacement) {
+ result = result.prepend(replacement);
+ }
+ } else {
+ result = result.prepend(a);
+ }
+ }
+
+ type_attributes = result.reverse();
+
+ Assert.check(SymbolMetadata.this.getTypePlaceholders().isEmpty());
+ } else {
+ Assert.check(!pendingCompletion());
+
+ if (isEmpty()) {
+ return;
+ }
+
+ List<Attribute.Compound> result = List.nil();
+ for (Attribute.Compound a : getDeclarationAttributes()) {
+ if (a instanceof Placeholder) {
+ @SuppressWarnings("unchecked")
+ Attribute.Compound replacement = replaceOne((Placeholder<T>) a, ctx);
+
+ if (null != replacement) {
+ result = result.prepend(replacement);
+ }
+ } else {
+ result = result.prepend(a);
+ }
+ }
+
+ attributes = result.reverse();
+
+ Assert.check(SymbolMetadata.this.getPlaceholders().isEmpty());
+ }
+ } finally {
+ log.useSource(oldSource);
+ }
+ }
+
+ private <T extends Attribute.Compound> T replaceOne(Placeholder<T> placeholder, Annotate.AnnotateRepeatedContext<T> ctx) {
+ Log log = ctx.log;
+
+ // Process repeated annotations
+ T validRepeated = ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor(), sym);
+
+ if (validRepeated != null) {
+ // Check that the container isn't manually
+ // present along with repeated instances of
+ // its contained annotation.
+ ListBuffer<T> manualContainer = ctx.annotated.get(validRepeated.type.tsym);
+ if (manualContainer != null) {
+ log.error(ctx.pos.get(manualContainer.first()), "invalid.repeatable.annotation.repeated.and.container.present",
+ manualContainer.first().type.tsym);
+ }
+ }
+
+ // A null return will delete the Placeholder
+ return validRepeated;
+ }
+
+ private static class Placeholder<T extends Attribute.Compound> extends Attribute.TypeCompound {
+
+ private final Annotate.AnnotateRepeatedContext<T> ctx;
+ private final List<T> placeholderFor;
+ private final Symbol on;
+
+ public Placeholder(Annotate.AnnotateRepeatedContext<T> ctx, List<T> placeholderFor, Symbol on) {
+ super(on.type, List.<Pair<Symbol.MethodSymbol, Attribute>>nil(),
+ ctx.isTypeCompound ?
+ ((Attribute.TypeCompound)placeholderFor.head).position :
+ null);
+ this.ctx = ctx;
+ this.placeholderFor = placeholderFor;
+ this.on = on;
+ }
+
+ @Override
+ public String toString() {
+ return "<placeholder: " + placeholderFor + " on: " + on + ">";
+ }
+
+ public List<T> getPlaceholderFor() {
+ return placeholderFor;
+ }
+
+ public Annotate.AnnotateRepeatedContext<T> getRepeatedContext() {
+ return ctx;
+ }
+ }
+}
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Sat Sep 14 20:43:34 2013 +0100
@@ -3055,7 +3055,7 @@
/**
* Does t have the same bounds for quantified variables as s?
*/
- boolean hasSameBounds(ForAll t, ForAll s) {
+ public boolean hasSameBounds(ForAll t, ForAll s) {
List<Type> l1 = t.tvars;
List<Type> l2 = s.tvars;
while (l1.nonEmpty() && l2.nonEmpty() &&
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Sat Sep 14 20:43:34 2013 +0100
@@ -748,19 +748,11 @@
* @see VarSymbol#setLazyConstValue
*/
public Object attribLazyConstantValue(Env<AttrContext> env,
- JCTree.JCExpression initializer,
+ JCVariableDecl variable,
Type type) {
- /* When this env was created, it didn't have the correct lint nor had
- * annotations has been processed.
- * But now at this phase we have already processed annotations and the
- * correct lint must have been set in chk, so we should use that one to
- * attribute the initializer.
- */
- Lint prevLint = env.info.lint;
- env.info.lint = chk.getLint();
-
- JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
+ DiagnosticPosition prevLintPos
+ = deferredLintHandler.setPos(variable.pos());
try {
// Use null as symbol to not attach the type annotation to any symbol.
@@ -768,17 +760,16 @@
// to the symbol.
// This prevents having multiple type annotations, just because of
// lazy constant value evaluation.
- memberEnter.typeAnnotate(initializer, env, null);
+ memberEnter.typeAnnotate(variable.init, env, null, variable.pos());
annotate.flush();
- Type itype = attribExpr(initializer, env, type);
+ Type itype = attribExpr(variable.init, env, type);
if (itype.constValue() != null) {
return coerce(itype, type).constValue();
} else {
return null;
}
} finally {
- env.info.lint = prevLint;
- log.useSource(prevSource);
+ deferredLintHandler.setPos(prevLintPos);
}
}
@@ -1012,7 +1003,7 @@
}
// Attribute all type annotations in the body
- memberEnter.typeAnnotate(tree.body, localEnv, m);
+ memberEnter.typeAnnotate(tree.body, localEnv, m, null);
annotate.flush();
// Attribute method body.
@@ -1042,7 +1033,7 @@
} else {
if (tree.init != null) {
// Field initializer expression need to be entered.
- memberEnter.typeAnnotate(tree.init, env, tree.sym);
+ memberEnter.typeAnnotate(tree.init, env, tree.sym, tree.pos());
annotate.flush();
}
}
@@ -1056,18 +1047,16 @@
((JCLambda)env.tree).paramKind == JCLambda.ParameterKind.IMPLICIT &&
(tree.sym.flags() & PARAMETER) != 0;
chk.validate(tree.vartype, env, !isImplicitLambdaParameter);
- deferredLintHandler.flush(tree.pos());
try {
+ v.getConstValue(); // ensure compile-time constant initializer is evaluated
+ deferredLintHandler.flush(tree.pos());
chk.checkDeprecatedAnnotation(tree.pos(), v);
if (tree.init != null) {
- if ((v.flags_field & FINAL) != 0 &&
- memberEnter.needsLazyConstValue(tree.init)) {
- // In this case, `v' is final. Ensure that it's initializer is
- // evaluated.
- v.getConstValue(); // ensure initializer is evaluated
- } else {
+ if ((v.flags_field & FINAL) == 0 ||
+ !memberEnter.needsLazyConstValue(tree.init)) {
+ // Not a compile-time constant
// Attribute initializer in a new environment
// with the declared variable as owner.
// Check that initializer conforms to variable's declared type.
@@ -1106,7 +1095,7 @@
if ((tree.flags & STATIC) != 0) localEnv.info.staticLevel++;
// Attribute all type annotations in the block
- memberEnter.typeAnnotate(tree, localEnv, localEnv.info.scope.owner);
+ memberEnter.typeAnnotate(tree, localEnv, localEnv.info.scope.owner, null);
annotate.flush();
{
@@ -2319,30 +2308,37 @@
boolean needsRecovery =
resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK;
try {
- Type target = pt();
+ Type currentTarget = pt();
List<Type> explicitParamTypes = null;
if (that.paramKind == JCLambda.ParameterKind.EXPLICIT) {
//attribute lambda parameters
attribStats(that.params, localEnv);
explicitParamTypes = TreeInfo.types(that.params);
- target = infer.instantiateFunctionalInterface(that, target, explicitParamTypes, resultInfo.checkContext);
}
Type lambdaType;
if (pt() != Type.recoveryType) {
- target = targetChecker.visit(target, that);
- lambdaType = types.findDescriptorType(target);
+ /* We need to adjust the target. If the target is an
+ * intersection type, for example: SAM & I1 & I2 ...
+ * the target will be updated to SAM
+ */
+ currentTarget = targetChecker.visit(currentTarget, that);
+ if (explicitParamTypes != null) {
+ currentTarget = infer.instantiateFunctionalInterface(that,
+ currentTarget, explicitParamTypes, resultInfo.checkContext);
+ }
+ lambdaType = types.findDescriptorType(currentTarget);
} else {
- target = Type.recoveryType;
+ currentTarget = Type.recoveryType;
lambdaType = fallbackDescriptorType(that);
}
- setFunctionalInfo(localEnv, that, pt(), lambdaType, target, resultInfo.checkContext);
+ setFunctionalInfo(localEnv, that, pt(), lambdaType, currentTarget, resultInfo.checkContext);
if (lambdaType.hasTag(FORALL)) {
//lambda expression target desc cannot be a generic method
resultInfo.checkContext.report(that, diags.fragment("invalid.generic.lambda.target",
- lambdaType, kindName(target.tsym), target.tsym));
+ lambdaType, kindName(currentTarget.tsym), currentTarget.tsym));
result = that.type = types.createErrorType(pt());
return;
}
@@ -2376,7 +2372,7 @@
if (arityMismatch) {
resultInfo.checkContext.report(that, diags.fragment("incompatible.arg.types.in.lambda"));
- result = that.type = types.createErrorType(target);
+ result = that.type = types.createErrorType(currentTarget);
return;
}
}
@@ -2396,38 +2392,14 @@
new ResultInfo(VAL, lambdaType.getReturnType(), funcContext);
localEnv.info.returnResult = bodyResultInfo;
- Log.DeferredDiagnosticHandler lambdaDeferredHandler = new Log.DeferredDiagnosticHandler(log);
- try {
- if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
- attribTree(that.getBody(), localEnv, bodyResultInfo);
- } else {
- JCBlock body = (JCBlock)that.body;
- attribStats(body.stats, localEnv);
- }
-
- if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.SPECULATIVE) {
- //check for errors in lambda body
- for (JCDiagnostic deferredDiag : lambdaDeferredHandler.getDiagnostics()) {
- if (deferredDiag.getKind() == JCDiagnostic.Kind.ERROR) {
- resultInfo.checkContext
- .report(that, diags.fragment("bad.arg.types.in.lambda", TreeInfo.types(that.params),
- deferredDiag)); //hidden diag parameter
- //we mark the lambda as erroneous - this is crucial in the recovery step
- //as parameter-dependent type error won't be reported in that stage,
- //meaning that a lambda will be deemed erroeneous only if there is
- //a target-independent error (which will cause method diagnostic
- //to be skipped).
- result = that.type = types.createErrorType(target);
- return;
- }
- }
- }
- } finally {
- lambdaDeferredHandler.reportDeferredDiagnostics();
- log.popDiagnosticHandler(lambdaDeferredHandler);
+ if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
+ attribTree(that.getBody(), localEnv, bodyResultInfo);
+ } else {
+ JCBlock body = (JCBlock)that.body;
+ attribStats(body.stats, localEnv);
}
- result = check(that, target, VAL, resultInfo);
+ result = check(that, currentTarget, VAL, resultInfo);
boolean isSpeculativeRound =
resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.SPECULATIVE;
@@ -2435,12 +2407,20 @@
preFlow(that);
flow.analyzeLambda(env, that, make, isSpeculativeRound);
- checkLambdaCompatible(that, lambdaType, resultInfo.checkContext, isSpeculativeRound);
+ checkLambdaCompatible(that, lambdaType, resultInfo.checkContext);
if (!isSpeculativeRound) {
- checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), lambdaType, target);
+ //add thrown types as bounds to the thrown types free variables if needed:
+ if (resultInfo.checkContext.inferenceContext().free(lambdaType.getThrownTypes())) {
+ List<Type> inferredThrownTypes = flow.analyzeLambdaThrownTypes(env, that, make);
+ List<Type> thrownTypes = resultInfo.checkContext.inferenceContext().asFree(lambdaType.getThrownTypes());
+
+ chk.unhandled(inferredThrownTypes, thrownTypes);
+ }
+
+ checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), lambdaType, currentTarget);
}
- result = check(that, target, VAL, resultInfo);
+ result = check(that, currentTarget, VAL, resultInfo);
} catch (Types.FunctionDescriptorLookupError ex) {
JCDiagnostic cause = ex.getDiagnostic();
resultInfo.checkContext.report(that, cause);
@@ -2604,10 +2584,9 @@
* Lambda compatibility. Check that given return types, thrown types, parameter types
* are compatible with the expected functional interface descriptor. This means that:
* (i) parameter types must be identical to those of the target descriptor; (ii) return
- * types must be compatible with the return type of the expected descriptor;
- * (iii) finish inference of thrown types if required.
+ * types must be compatible with the return type of the expected descriptor.
*/
- private void checkLambdaCompatible(JCLambda tree, Type descriptor, CheckContext checkContext, boolean speculativeAttr) {
+ private void checkLambdaCompatible(JCLambda tree, Type descriptor, CheckContext checkContext) {
Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType());
//return values have already been checked - but if lambda has no return
@@ -2624,11 +2603,6 @@
if (!types.isSameTypes(argTypes, TreeInfo.types(tree.params))) {
checkContext.report(tree, diags.fragment("incompatible.arg.types.in.lambda"));
}
-
- if (!speculativeAttr) {
- List<Type> thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes());
- chk.unhandled(tree.inferredThrownTypes == null ? List.<Type>nil() : tree.inferredThrownTypes, thrownTypes);
- }
}
private Env<AttrContext> lambdaEnv(JCLambda that, Env<AttrContext> env) {
@@ -2664,6 +2638,13 @@
if (that.getMode() == JCMemberReference.ReferenceMode.NEW) {
exprType = chk.checkConstructorRefType(that.expr, exprType);
+ if (!exprType.isErroneous() &&
+ exprType.isRaw() &&
+ that.typeargs != null) {
+ log.error(that.expr.pos(), "invalid.mref", Kinds.kindName(that.getMode()),
+ diags.fragment("mref.infer.and.explicit.params"));
+ exprType = types.createErrorType(exprType);
+ }
}
if (exprType.isErroneous()) {
@@ -3731,7 +3712,7 @@
* Check that method arguments conform to its instantiation.
**/
public Type checkMethod(Type site,
- Symbol sym,
+ final Symbol sym,
ResultInfo resultInfo,
Env<AttrContext> env,
final List<JCExpression> argtrees,
@@ -3820,8 +3801,19 @@
resultInfo.checkContext.report(env.tree.pos(), ex.getDiagnostic());
return types.createErrorType(site);
} catch (Resolve.InapplicableMethodException ex) {
- Assert.error(ex.getDiagnostic().getMessage(Locale.getDefault()));
- return null;
+ final JCDiagnostic diag = ex.getDiagnostic();
+ Resolve.InapplicableSymbolError errSym = rs.new InapplicableSymbolError(null) {
+ @Override
+ protected Pair<Symbol, JCDiagnostic> errCandidate() {
+ return new Pair<Symbol, JCDiagnostic>(sym, diag);
+ }
+ };
+ List<Type> argtypes2 = Type.map(argtypes,
+ rs.new ResolveDeferredRecoveryMap(AttrMode.CHECK, sym, env.info.pendingResolutionPhase));
+ JCDiagnostic errDiag = errSym.getDiagnostic(JCDiagnostic.DiagnosticType.ERROR,
+ env.tree, sym, site, sym.name, argtypes2, typeargtypes);
+ log.report(errDiag);
+ return types.createErrorType(site);
}
}
@@ -4206,6 +4198,7 @@
ResultInfo prevReturnRes = env.info.returnResult;
try {
+ deferredLintHandler.flush(env.tree);
env.info.returnResult = null;
// java.lang.Enum may not be subclassed by a non-enum
if (st.tsym == syms.enumSym &&
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Sat Sep 14 20:43:34 2013 +0100
@@ -148,7 +148,7 @@
sunApiHandler = new MandatoryWarningHandler(log, verboseSunApi,
enforceMandatoryWarnings, "sunapi", null);
- deferredLintHandler = DeferredLintHandler.immediateHandler;
+ deferredLintHandler = DeferredLintHandler.instance(context);
}
/** Switch: generics enabled?
@@ -218,20 +218,6 @@
return prev;
}
- /* This idiom should be used only in cases when it is needed to set the lint
- * of an environment that has been created in a phase previous to annotations
- * processing.
- */
- Lint getLint() {
- return lint;
- }
-
- DeferredLintHandler setDeferredLintHandler(DeferredLintHandler newDeferredLintHandler) {
- DeferredLintHandler prev = deferredLintHandler;
- deferredLintHandler = newDeferredLintHandler;
- return prev;
- }
-
MethodSymbol setMethod(MethodSymbol newMethod) {
MethodSymbol prev = method;
method = newMethod;
@@ -582,14 +568,19 @@
/** Check for redundant casts (i.e. where source type is a subtype of target type)
* The problem should only be reported for non-292 cast
*/
- public void checkRedundantCast(Env<AttrContext> env, JCTypeCast tree) {
- if (!tree.type.isErroneous() &&
- (env.info.lint == null || env.info.lint.isEnabled(Lint.LintCategory.CAST))
+ public void checkRedundantCast(Env<AttrContext> env, final JCTypeCast tree) {
+ if (!tree.type.isErroneous()
&& types.isSameType(tree.expr.type, tree.clazz.type)
&& !(ignoreAnnotatedCasts && TreeInfo.containsTypeAnnotation(tree.clazz))
&& !is292targetTypeCast(tree)) {
- log.warning(Lint.LintCategory.CAST,
- tree.pos(), "redundant.cast", tree.expr.type);
+ deferredLintHandler.report(new DeferredLintHandler.LintLogger() {
+ @Override
+ public void report() {
+ if (lint.isEnabled(Lint.LintCategory.CAST))
+ log.warning(Lint.LintCategory.CAST,
+ tree.pos(), "redundant.cast", tree.expr.type);
+ }
+ });
}
}
//where
@@ -1050,6 +1041,7 @@
long checkFlags(DiagnosticPosition pos, long flags, Symbol sym, JCTree tree) {
long mask;
long implicit = 0;
+
switch (sym.kind) {
case VAR:
if (sym.owner.kind != TYP)
@@ -1070,7 +1062,10 @@
} else
mask = ConstructorFlags;
} else if ((sym.owner.flags_field & INTERFACE) != 0) {
- if ((flags & (DEFAULT | STATIC)) != 0) {
+ if ((sym.owner.flags_field & ANNOTATION) != 0) {
+ mask = AnnotationTypeElementMask;
+ implicit = PUBLIC | ABSTRACT;
+ } else if ((flags & (DEFAULT | STATIC)) != 0) {
mask = InterfaceMethodMask;
implicit = PUBLIC;
if ((flags & DEFAULT) != 0) {
@@ -1079,8 +1074,7 @@
} else {
mask = implicit = InterfaceMethodFlags;
}
- }
- else {
+ } else {
mask = MethodFlags;
}
// Imply STRICTFP if owner has STRICTFP set.
@@ -2368,7 +2362,10 @@
//for each method m1 that is overridden (directly or indirectly)
//by method 'sym' in 'site'...
for (Symbol m1 : types.membersClosure(site, false).getElementsByName(sym.name, cf)) {
- if (!sym.overrides(m1, site.tsym, types, false)) continue;
+ if (!sym.overrides(m1, site.tsym, types, false)) {
+ checkPotentiallyAmbiguousOverloads(pos, site, sym, (MethodSymbol)m1);
+ continue;
+ }
//...check each method m2 that is a member of 'site'
for (Symbol m2 : types.membersClosure(site, false).getElementsByName(sym.name, cf)) {
if (m2 == m1) continue;
@@ -2406,14 +2403,17 @@
for (Symbol s : types.membersClosure(site, true).getElementsByName(sym.name, cf)) {
//if (i) the signature of 'sym' is not a subsignature of m1 (seen as
//a member of 'site') and (ii) 'sym' has the same erasure as m1, issue an error
- if (!types.isSubSignature(sym.type, types.memberType(site, s), allowStrictMethodClashCheck) &&
- types.hasSameArgs(s.erasure(types), sym.erasure(types))) {
- log.error(pos,
- "name.clash.same.erasure.no.hide",
- sym, sym.location(),
- s, s.location());
- return;
- }
+ if (!types.isSubSignature(sym.type, types.memberType(site, s), allowStrictMethodClashCheck)) {
+ if (types.hasSameArgs(s.erasure(types), sym.erasure(types))) {
+ log.error(pos,
+ "name.clash.same.erasure.no.hide",
+ sym, sym.location(),
+ s, s.location());
+ return;
+ } else {
+ checkPotentiallyAmbiguousOverloads(pos, site, sym, (MethodSymbol)s);
+ }
+ }
}
}
@@ -2496,6 +2496,62 @@
}
}
+ /**
+ * Report warnings for potentially ambiguous method declarations. Two declarations
+ * are potentially ambiguous if they feature two unrelated functional interface
+ * in same argument position (in which case, a call site passing an implicit
+ * lambda would be ambiguous).
+ */
+ void checkPotentiallyAmbiguousOverloads(DiagnosticPosition pos, Type site,
+ MethodSymbol msym1, MethodSymbol msym2) {
+ if (msym1 != msym2 &&
+ allowDefaultMethods &&
+ lint.isEnabled(LintCategory.OVERLOADS) &&
+ (msym1.flags() & POTENTIALLY_AMBIGUOUS) == 0 &&
+ (msym2.flags() & POTENTIALLY_AMBIGUOUS) == 0) {
+ Type mt1 = types.memberType(site, msym1);
+ Type mt2 = types.memberType(site, msym2);
+ //if both generic methods, adjust type variables
+ if (mt1.hasTag(FORALL) && mt2.hasTag(FORALL) &&
+ types.hasSameBounds((ForAll)mt1, (ForAll)mt2)) {
+ mt2 = types.subst(mt2, ((ForAll)mt2).tvars, ((ForAll)mt1).tvars);
+ }
+ //expand varargs methods if needed
+ int maxLength = Math.max(mt1.getParameterTypes().length(), mt2.getParameterTypes().length());
+ List<Type> args1 = rs.adjustArgs(mt1.getParameterTypes(), msym1, maxLength, true);
+ List<Type> args2 = rs.adjustArgs(mt2.getParameterTypes(), msym2, maxLength, true);
+ //if arities don't match, exit
+ if (args1.length() != args2.length()) return;
+ boolean potentiallyAmbiguous = false;
+ while (args1.nonEmpty() && args2.nonEmpty()) {
+ Type s = args1.head;
+ Type t = args2.head;
+ if (!types.isSubtype(t, s) && !types.isSubtype(s, t)) {
+ if (types.isFunctionalInterface(s) && types.isFunctionalInterface(t) &&
+ types.findDescriptorType(s).getParameterTypes().length() > 0 &&
+ types.findDescriptorType(s).getParameterTypes().length() ==
+ types.findDescriptorType(t).getParameterTypes().length()) {
+ potentiallyAmbiguous = true;
+ } else {
+ break;
+ }
+ }
+ args1 = args1.tail;
+ args2 = args2.tail;
+ }
+ if (potentiallyAmbiguous) {
+ //we found two incompatible functional interfaces with same arity
+ //this means a call site passing an implicit lambda would be ambigiuous
+ msym1.flags_field |= POTENTIALLY_AMBIGUOUS;
+ msym2.flags_field |= POTENTIALLY_AMBIGUOUS;
+ log.warning(LintCategory.OVERLOADS, pos, "potentially.ambiguous.overload",
+ msym1, msym1.location(),
+ msym2, msym2.location());
+ return;
+ }
+ }
+ }
+
/** Report a conflict between a user symbol and a synthetic symbol.
*/
private void syntheticError(DiagnosticPosition pos, Symbol sym) {
@@ -3275,7 +3331,9 @@
(e.sym.flags() & CLASH) == 0 &&
sym.kind == e.sym.kind &&
sym.name != names.error &&
- (sym.kind != MTH || types.hasSameArgs(types.erasure(sym.type), types.erasure(e.sym.type)))) {
+ (sym.kind != MTH ||
+ types.hasSameArgs(sym.type, e.sym.type) ||
+ types.hasSameArgs(types.erasure(sym.type), types.erasure(e.sym.type)))) {
if ((sym.flags() & VARARGS) != (e.sym.flags() & VARARGS)) {
varargsDuplicateError(pos, sym, e.sym);
return true;
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Sat Sep 14 20:43:34 2013 +0100
@@ -25,6 +25,7 @@
package com.sun.tools.javac.comp;
+import com.sun.source.tree.MemberReferenceTree;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.util.*;
@@ -39,7 +40,9 @@
import java.util.ArrayList;
+import java.util.Collections;
import java.util.EnumSet;
+import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
@@ -98,7 +101,7 @@
emptyDeferredAttrContext =
new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) {
@Override
- void addDeferredAttrNode(DeferredType dt, ResultInfo ri, List<Type> stuckVars) {
+ void addDeferredAttrNode(DeferredType dt, ResultInfo ri, DeferredStuckPolicy deferredStuckPolicy) {
Assert.error("Empty deferred context!");
}
@Override
@@ -149,15 +152,15 @@
class Entry {
JCTree speculativeTree;
- Resolve.MethodResolutionPhase phase;
+ ResultInfo resultInfo;
- public Entry(JCTree speculativeTree, MethodResolutionPhase phase) {
+ public Entry(JCTree speculativeTree, ResultInfo resultInfo) {
this.speculativeTree = speculativeTree;
- this.phase = phase;
+ this.resultInfo = resultInfo;
}
- boolean matches(Resolve.MethodResolutionPhase phase) {
- return this.phase == phase;
+ boolean matches(MethodResolutionPhase phase) {
+ return resultInfo.checkContext.deferredAttrContext().phase == phase;
}
}
@@ -178,12 +181,13 @@
* Stores a speculative cache entry corresponding to given symbol
* and resolution phase
*/
- void put(Symbol msym, JCTree speculativeTree, MethodResolutionPhase phase) {
+ void put(JCTree speculativeTree, ResultInfo resultInfo) {
+ Symbol msym = resultInfo.checkContext.deferredAttrContext().msym;
List<Entry> entries = cache.get(msym);
if (entries == null) {
entries = List.nil();
}
- cache.put(msym, entries.prepend(new Entry(speculativeTree, phase)));
+ cache.put(msym, entries.prepend(new Entry(speculativeTree, resultInfo)));
}
}
@@ -203,15 +207,24 @@
* attribution round must follow one or more speculative rounds.
*/
Type check(ResultInfo resultInfo) {
- return check(resultInfo, stuckVars(tree, env, resultInfo), basicCompleter);
+ DeferredStuckPolicy deferredStuckPolicy;
+ if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
+ deferredStuckPolicy = dummyStuckPolicy;
+ } else if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.SPECULATIVE) {
+ deferredStuckPolicy = new OverloadStuckPolicy(resultInfo, this);
+ } else {
+ deferredStuckPolicy = new CheckStuckPolicy(resultInfo, this);
+ }
+ return check(resultInfo, deferredStuckPolicy, basicCompleter);
}
- Type check(ResultInfo resultInfo, List<Type> stuckVars, DeferredTypeCompleter deferredTypeCompleter) {
+ private Type check(ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy,
+ DeferredTypeCompleter deferredTypeCompleter) {
DeferredAttrContext deferredAttrContext =
resultInfo.checkContext.deferredAttrContext();
Assert.check(deferredAttrContext != emptyDeferredAttrContext);
- if (stuckVars.nonEmpty()) {
- deferredAttrContext.addDeferredAttrNode(this, resultInfo, stuckVars);
+ if (deferredStuckPolicy.isStuck()) {
+ deferredAttrContext.addDeferredAttrNode(this, resultInfo, deferredStuckPolicy);
return Type.noType;
} else {
try {
@@ -236,6 +249,7 @@
Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext);
}
+
/**
* A basic completer for deferred types. This completer type-checks a deferred type
* using attribution; depending on the attribution mode, this could be either standard
@@ -249,7 +263,7 @@
//speculative rounds...
Assert.check(dt.mode == null || dt.mode == AttrMode.SPECULATIVE);
JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo);
- dt.speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase);
+ dt.speculativeCache.put(speculativeTree, resultInfo);
return speculativeTree.type;
case CHECK:
Assert.check(dt.mode != null);
@@ -268,6 +282,45 @@
};
/**
+ * Policy for detecting stuck expressions. Different criteria might cause
+ * an expression to be judged as stuck, depending on whether the check
+ * is performed during overload resolution or after most specific.
+ */
+ interface DeferredStuckPolicy {
+ /**
+ * Has the policy detected that a given expression should be considered stuck?
+ */
+ boolean isStuck();
+ /**
+ * Get the set of inference variables a given expression depends upon.
+ */
+ Set<Type> stuckVars();
+ /**
+ * Get the set of inference variables which might get new constraints
+ * if a given expression is being type-checked.
+ */
+ Set<Type> depVars();
+ }
+
+ /**
+ * Basic stuck policy; an expression is never considered to be stuck.
+ */
+ DeferredStuckPolicy dummyStuckPolicy = new DeferredStuckPolicy() {
+ @Override
+ public boolean isStuck() {
+ return false;
+ }
+ @Override
+ public Set<Type> stuckVars() {
+ return Collections.emptySet();
+ }
+ @Override
+ public Set<Type> depVars() {
+ return Collections.emptySet();
+ }
+ };
+
+ /**
* The 'mode' in which the deferred type is to be type-checked
*/
public enum AttrMode {
@@ -388,8 +441,9 @@
* Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable
* Nodes added this way act as 'roots' for the out-of-order method checking process.
*/
- void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo, List<Type> stuckVars) {
- deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, stuckVars));
+ void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo,
+ DeferredStuckPolicy deferredStuckPolicy) {
+ deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, deferredStuckPolicy));
}
/**
@@ -400,23 +454,52 @@
*/
void complete() {
while (!deferredAttrNodes.isEmpty()) {
- Set<Type> stuckVars = new LinkedHashSet<Type>();
+ Map<Type, Set<Type>> depVarsMap = new LinkedHashMap<Type, Set<Type>>();
+ List<Type> stuckVars = List.nil();
boolean progress = false;
//scan a defensive copy of the node list - this is because a deferred
//attribution round can add new nodes to the list
for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
if (!deferredAttrNode.process(this)) {
- stuckVars.addAll(deferredAttrNode.stuckVars);
+ List<Type> restStuckVars =
+ List.from(deferredAttrNode.deferredStuckPolicy.stuckVars())
+ .intersect(inferenceContext.restvars());
+ stuckVars = stuckVars.prependList(restStuckVars);
+ //update dependency map
+ for (Type t : List.from(deferredAttrNode.deferredStuckPolicy.depVars())
+ .intersect(inferenceContext.restvars())) {
+ Set<Type> prevDeps = depVarsMap.get(t);
+ if (prevDeps == null) {
+ prevDeps = new LinkedHashSet<Type>();
+ depVarsMap.put(t, prevDeps);
+ }
+ prevDeps.addAll(restStuckVars);
+ }
} else {
deferredAttrNodes.remove(deferredAttrNode);
progress = true;
}
}
if (!progress) {
+ DeferredAttrContext dac = this;
+ while (dac != emptyDeferredAttrContext) {
+ if (dac.mode == AttrMode.SPECULATIVE) {
+ //unsticking does not take place during overload
+ break;
+ }
+ dac = dac.parent;
+ }
//remove all variables that have already been instantiated
//from the list of stuck variables
- inferenceContext.solveAny(List.from(stuckVars), warn);
- inferenceContext.notifyChange();
+ try {
+ inferenceContext.solveAny(stuckVars, depVarsMap, warn);
+ inferenceContext.notifyChange();
+ } catch (Infer.GraphStrategy.NodeNotFoundException ex) {
+ //this means that we are in speculative mode and the
+ //set of contraints are too tight for progess to be made.
+ //Just leave the remaining expressions as stuck.
+ break;
+ }
}
}
}
@@ -426,7 +509,7 @@
* Class representing a deferred attribution node. It keeps track of
* a deferred type, along with the expected target type information.
*/
- class DeferredAttrNode implements Infer.FreeTypeListener {
+ class DeferredAttrNode {
/** underlying deferred type */
DeferredType dt;
@@ -434,22 +517,13 @@
/** underlying target type information */
ResultInfo resultInfo;
- /** list of uninferred inference variables causing this node to be stuck */
- List<Type> stuckVars;
+ /** stuck policy associated with this node */
+ DeferredStuckPolicy deferredStuckPolicy;
- DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, List<Type> stuckVars) {
+ DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy) {
this.dt = dt;
this.resultInfo = resultInfo;
- this.stuckVars = stuckVars;
- if (!stuckVars.isEmpty()) {
- resultInfo.checkContext.inferenceContext().addFreeTypeListener(stuckVars, this);
- }
- }
-
- @Override
- public void typesInferred(InferenceContext inferenceContext) {
- stuckVars = List.nil();
- resultInfo = resultInfo.dup(inferenceContext.asInstType(resultInfo.pt));
+ this.deferredStuckPolicy = deferredStuckPolicy;
}
/**
@@ -457,24 +531,41 @@
* Invariant: a stuck node cannot be processed.
*/
@SuppressWarnings("fallthrough")
- boolean process(DeferredAttrContext deferredAttrContext) {
+ boolean process(final DeferredAttrContext deferredAttrContext) {
switch (deferredAttrContext.mode) {
case SPECULATIVE:
- dt.check(resultInfo, List.<Type>nil(), new StructuralStuckChecker());
- return true;
+ if (deferredStuckPolicy.isStuck()) {
+ dt.check(resultInfo, dummyStuckPolicy, new StructuralStuckChecker());
+ return true;
+ } else {
+ Assert.error("Cannot get here");
+ }
case CHECK:
- if (stuckVars.nonEmpty()) {
+ if (deferredStuckPolicy.isStuck()) {
//stuck expression - see if we can propagate
if (deferredAttrContext.parent != emptyDeferredAttrContext &&
- Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars, List.from(stuckVars))) {
- deferredAttrContext.parent.deferredAttrNodes.add(this);
- dt.check(resultInfo, List.<Type>nil(), dummyCompleter);
+ Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars,
+ List.from(deferredStuckPolicy.stuckVars()))) {
+ deferredAttrContext.parent.addDeferredAttrNode(dt,
+ resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) {
+ @Override
+ public InferenceContext inferenceContext() {
+ return deferredAttrContext.parent.inferenceContext;
+ }
+ @Override
+ public DeferredAttrContext deferredAttrContext() {
+ return deferredAttrContext.parent;
+ }
+ }), deferredStuckPolicy);
+ dt.tree.type = Type.stuckType;
return true;
} else {
return false;
}
} else {
- dt.check(resultInfo, stuckVars, basicCompleter);
+ ResultInfo instResultInfo =
+ resultInfo.dup(deferredAttrContext.inferenceContext.asInstType(resultInfo.pt));
+ dt.check(instResultInfo, dummyStuckPolicy, basicCompleter);
return true;
}
default:
@@ -489,12 +580,14 @@
ResultInfo resultInfo;
InferenceContext inferenceContext;
+ Env<AttrContext> env;
public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
this.resultInfo = resultInfo;
this.inferenceContext = deferredAttrContext.inferenceContext;
+ this.env = dt.env;
dt.tree.accept(this);
- dt.speculativeCache.put(deferredAttrContext.msym, stuckTree, deferredAttrContext.phase);
+ dt.speculativeCache.put(stuckTree, resultInfo);
return Type.noType;
}
@@ -541,15 +634,25 @@
} catch (Types.FunctionDescriptorLookupError ex) {
checkContext.report(null, ex.getDiagnostic());
}
- switch (tree.sym.kind) {
+ Env<AttrContext> localEnv = env.dup(tree);
+ JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
+ attr.memberReferenceQualifierResult(tree));
+ ListBuffer<Type> argtypes = ListBuffer.lb();
+ for (Type t : types.findDescriptorType(pt).getParameterTypes()) {
+ argtypes.append(Type.noType);
+ }
+ JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
+ mref2.expr = exprTree;
+ Pair<Symbol, ?> lookupRes =
+ rs.resolveMemberReference(tree, localEnv, mref2, exprTree.type,
+ tree.name, argtypes.toList(), null, true, rs.arityMethodCheck, inferenceContext);
+ switch (lookupRes.fst.kind) {
//note: as argtypes are erroneous types, type-errors must
//have been caused by arity mismatch
case Kinds.ABSENT_MTH:
case Kinds.WRONG_MTH:
case Kinds.WRONG_MTHS:
- case Kinds.STATICERR:
- case Kinds.MISSING_ENCL:
- checkContext.report(null, diags.fragment("incompatible.arg.types.in.mref"));
+ checkContext.report(tree, diags.fragment("incompatible.arg.types.in.mref"));
}
}
}
@@ -575,18 +678,12 @@
infer.emptyContext, emptyDeferredAttrContext, types.noWarnings);
}
- protected boolean validState(DeferredType dt) {
- return dt.mode != null &&
- deferredAttrContext.mode.ordinal() <= dt.mode.ordinal();
- }
-
@Override
public Type apply(Type t) {
if (!t.hasTag(DEFERRED)) {
return t.map(this);
} else {
DeferredType dt = (DeferredType)t;
- Assert.check(validState(dt));
return typeOf(dt);
}
}
@@ -623,11 +720,6 @@
recover(dt) : owntype;
}
- @Override
- protected boolean validState(DeferredType dt) {
- return true;
- }
-
/**
* Synthesize a type for a deferred type that hasn't been previously
* reduced to an ordinary type. Functional deferred types and conditionals
@@ -647,25 +739,6 @@
}
/**
- * Retrieves the list of inference variables that need to be inferred before
- * an AST node can be type-checked
- */
- @SuppressWarnings("fallthrough")
- List<Type> stuckVars(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
- if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
- return List.nil();
- } else {
- return stuckVarsInternal(tree, resultInfo.pt, env, resultInfo.checkContext.inferenceContext());
- }
- }
- //where
- private List<Type> stuckVarsInternal(JCTree tree, Type pt, Env<AttrContext> env, Infer.InferenceContext inferenceContext) {
- StuckChecker sc = new StuckChecker(pt, env, inferenceContext);
- sc.scan(tree);
- return List.from(sc.stuckVars);
- }
-
- /**
* A special tree scanner that would only visit portions of a given tree.
* The set of nodes visited by the scanner can be customized at construction-time.
*/
@@ -737,17 +810,41 @@
* inferring types that make some of the nested expressions incompatible
* with their corresponding instantiated target
*/
- class StuckChecker extends PolyScanner {
+ class CheckStuckPolicy extends PolyScanner implements DeferredStuckPolicy, Infer.FreeTypeListener {
Type pt;
- Env<AttrContext> env;
Infer.InferenceContext inferenceContext;
Set<Type> stuckVars = new LinkedHashSet<Type>();
+ Set<Type> depVars = new LinkedHashSet<Type>();
- StuckChecker(Type pt, Env<AttrContext> env, Infer.InferenceContext inferenceContext) {
- this.pt = pt;
- this.env = env;
- this.inferenceContext = inferenceContext;
+ @Override
+ public boolean isStuck() {
+ return !stuckVars.isEmpty();
+ }
+
+ @Override
+ public Set<Type> stuckVars() {
+ return stuckVars;
+ }
+
+ @Override
+ public Set<Type> depVars() {
+ return depVars;
+ }
+
+ public CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
+ this.pt = resultInfo.pt;
+ this.inferenceContext = resultInfo.checkContext.inferenceContext();
+ scan(dt.tree);
+ if (!stuckVars.isEmpty()) {
+ resultInfo.checkContext.inferenceContext()
+ .addFreeTypeListener(List.from(stuckVars), this);
+ }
+ }
+
+ @Override
+ public void typesInferred(InferenceContext inferenceContext) {
+ stuckVars.clear();
}
@Override
@@ -763,6 +860,7 @@
if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT &&
freeArgVars.nonEmpty()) {
stuckVars.addAll(freeArgVars);
+ depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
}
scanLambdaBody(tree, descType.getReturnType());
}
@@ -780,41 +878,34 @@
Type descType = types.findDescriptorType(pt);
List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
- Env<AttrContext> localEnv = env.dup(tree, env.info.dup());
- if (freeArgVars.nonEmpty()) {
- //perform arity-based check
- JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
- attr.memberReferenceQualifierResult(tree));
- ListBuffer<Type> argtypes = ListBuffer.lb();
- for (Type t : descType.getParameterTypes()) {
- argtypes.append(Type.noType);
- }
- JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
- mref2.expr = exprTree;
- Pair<Symbol, ReferenceLookupHelper> lookupRes =
- rs.resolveMemberReference(tree, localEnv, mref2, exprTree.type,
- tree.name, argtypes.toList(), null, true, rs.arityMethodCheck,
- inferenceContext);
- Symbol res = tree.sym = lookupRes.fst;
- if (res.kind >= Kinds.ERRONEOUS ||
- res.type.hasTag(FORALL) ||
- (res.flags() & Flags.VARARGS) != 0 ||
- (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
- exprTree.type.isRaw())) {
- stuckVars.addAll(freeArgVars);
- }
+ if (freeArgVars.nonEmpty() &&
+ tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
+ stuckVars.addAll(freeArgVars);
+ depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
}
}
void scanLambdaBody(JCLambda lambda, final Type pt) {
if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
- stuckVars.addAll(stuckVarsInternal(lambda.body, pt, env, inferenceContext));
+ Type prevPt = this.pt;
+ try {
+ this.pt = pt;
+ scan(lambda.body);
+ } finally {
+ this.pt = prevPt;
+ }
} else {
LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
@Override
public void visitReturn(JCReturn tree) {
if (tree.expr != null) {
- stuckVars.addAll(stuckVarsInternal(tree.expr, pt, env, inferenceContext));
+ Type prevPt = CheckStuckPolicy.this.pt;
+ try {
+ CheckStuckPolicy.this.pt = pt;
+ CheckStuckPolicy.this.scan(tree.expr);
+ } finally {
+ CheckStuckPolicy.this.pt = prevPt;
+ }
}
}
};
@@ -824,6 +915,42 @@
}
/**
+ * This visitor is used to check that structural expressions conform
+ * to their target - this step is required as inference could end up
+ * inferring types that make some of the nested expressions incompatible
+ * with their corresponding instantiated target
+ */
+ class OverloadStuckPolicy extends CheckStuckPolicy implements DeferredStuckPolicy {
+
+ boolean stuck;
+
+ @Override
+ public boolean isStuck() {
+ return super.isStuck() || stuck;
+ }
+
+ public OverloadStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
+ super(resultInfo, dt);
+ }
+
+ @Override
+ public void visitLambda(JCLambda tree) {
+ super.visitLambda(tree);
+ if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT) {
+ stuck = true;
+ }
+ }
+
+ @Override
+ public void visitReference(JCMemberReference tree) {
+ super.visitReference(tree);
+ if (tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
+ stuck = true;
+ }
+ }
+ }
+
+ /**
* Does the argument expression {@code expr} need speculative type-checking?
*/
boolean isDeferred(Env<AttrContext> env, JCExpression expr) {
@@ -904,6 +1031,26 @@
@Override
public void visitReference(JCMemberReference tree) {
+ //perform arity-based check
+ Env<AttrContext> localEnv = env.dup(tree);
+ JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
+ attr.memberReferenceQualifierResult(tree));
+ JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
+ mref2.expr = exprTree;
+ Pair<Symbol, ReferenceLookupHelper> lookupRes =
+ rs.resolveMemberReference(tree, localEnv, mref2, exprTree.type,
+ tree.name, List.<Type>nil(), null, true, rs.nilMethodCheck,
+ infer.emptyContext);
+ Symbol res = tree.sym = lookupRes.fst;
+ if (res.kind >= Kinds.ERRONEOUS ||
+ res.type.hasTag(FORALL) ||
+ (res.flags() & Flags.VARARGS) != 0 ||
+ (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
+ exprTree.type.isRaw())) {
+ tree.overloadKind = JCMemberReference.OverloadKind.OVERLOADED;
+ } else {
+ tree.overloadKind = JCMemberReference.OverloadKind.UNOVERLOADED;
+ }
//a method reference is always a poly expression
result = ArgumentExpressionKind.POLY;
}
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java Sat Sep 14 20:43:34 2013 +0100
@@ -207,7 +207,7 @@
public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
new AliveAnalyzer().analyzeTree(env, make);
- new AssignAnalyzer().analyzeTree(env, make);
+ new AssignAnalyzer(log, syms, lint, names).analyzeTree(env);
new FlowAnalyzer().analyzeTree(env, make);
new CaptureAnalyzer().analyzeTree(env, make);
}
@@ -224,7 +224,6 @@
}
try {
new AliveAnalyzer().analyzeTree(env, that, make);
- new LambdaFlowAnalyzer().analyzeTree(env, that, make);
} finally {
if (!speculative) {
log.popDiagnosticHandler(diagHandler);
@@ -232,6 +231,23 @@
}
}
+ public List<Type> analyzeLambdaThrownTypes(Env<AttrContext> env, JCLambda that, TreeMaker make) {
+ //we need to disable diagnostics temporarily; the problem is that if
+ //a lambda expression contains e.g. an unreachable statement, an error
+ //message will be reported and will cause compilation to skip the flow analyis
+ //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
+ //related errors, which will allow for more errors to be detected
+ Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
+ try {
+ new AssignAnalyzer(log, syms, lint, names).analyzeTree(env);
+ LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
+ flowAnalyzer.analyzeTree(env, that, make);
+ return flowAnalyzer.inferredThrownTypes;
+ } finally {
+ log.popDiagnosticHandler(diagHandler);
+ }
+ }
+
/**
* Definite assignment scan mode
*/
@@ -276,15 +292,6 @@
}
/**
- * Utility method to reset several Bits instances.
- */
- private void resetBits(Bits... bits) {
- for (Bits b : bits) {
- b.reset();
- }
- }
-
- /**
* Base visitor class for all visitors implementing dataflow analysis logic.
* This class define the shared logic for handling jumps (break/continue statements).
*/
@@ -331,17 +338,17 @@
this.tree = tree;
}
- void resolveJump() {
+ void resolveJump(JCTree tree) {
//do nothing
}
}
- abstract void markDead();
+ abstract void markDead(JCTree tree);
/** Record an outward transfer of control. */
void recordExit(JCTree tree, P pe) {
pendingExits.append(pe);
- markDead();
+ markDead(tree);
}
/** Resolve all jumps of this statement. */
@@ -355,7 +362,7 @@
P exit = exits.head;
if (exit.tree.hasTag(jk.treeTag) &&
jk.getTarget(exit.tree) == tree) {
- exit.resolveJump();
+ exit.resolveJump(tree);
resolved = true;
} else {
pendingExits.append(exit);
@@ -364,12 +371,12 @@
return resolved;
}
- /** Resolve all breaks of this statement. */
+ /** Resolve all continues of this statement. */
boolean resolveContinues(JCTree tree) {
return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
}
- /** Resolve all continues of this statement. */
+ /** Resolve all breaks of this statement. */
boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
}
@@ -398,7 +405,7 @@
private boolean alive;
@Override
- void markDead() {
+ void markDead(JCTree tree) {
alive = false;
}
@@ -680,7 +687,7 @@
public void visitThrow(JCThrow tree) {
scan(tree.expr);
- markDead();
+ markDead(tree);
}
public void visitApply(JCMethodInvocation tree) {
@@ -781,7 +788,7 @@
}
@Override
- void markDead() {
+ void markDead(JCTree tree) {
//do nothing
}
@@ -1206,7 +1213,7 @@
else {
markThrown(tree, tree.expr.type);
}
- markDead();
+ markDead(tree);
}
public void visitApply(JCMethodInvocation tree) {
@@ -1318,27 +1325,35 @@
* Specialized pass that performs inference of thrown types for lambdas.
*/
class LambdaFlowAnalyzer extends FlowAnalyzer {
+ List<Type> inferredThrownTypes;
+ boolean inLambda;
@Override
public void visitLambda(JCLambda tree) {
- if (tree.type != null &&
- tree.type.isErroneous()) {
+ if ((tree.type != null &&
+ tree.type.isErroneous()) || inLambda) {
return;
}
List<Type> prevCaught = caught;
List<Type> prevThrown = thrown;
ListBuffer<FlowPendingExit> prevPending = pendingExits;
+ inLambda = true;
try {
pendingExits = ListBuffer.lb();
caught = List.of(syms.throwableType);
thrown = List.nil();
scan(tree.body);
- tree.inferredThrownTypes = thrown;
+ inferredThrownTypes = thrown;
} finally {
pendingExits = prevPending;
caught = prevCaught;
thrown = prevThrown;
+ inLambda = false;
}
}
+ @Override
+ public void visitClassDef(JCClassDecl tree) {
+ //skip
+ }
}
/**
@@ -1348,11 +1363,13 @@
* depends on the results of the liveliness analyzer. This pass is also used to mark
* effectively-final local variables/parameters.
*/
- class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
+
+ public abstract static class AbstractAssignAnalyzer<P extends AbstractAssignAnalyzer.AbstractAssignPendingExit>
+ extends BaseAnalyzer<P> {
/** The set of definitely assigned variables.
*/
- final Bits inits;
+ protected final Bits inits;
/** The set of definitely unassigned variables.
*/
@@ -1378,7 +1395,7 @@
/** A mapping from addresses to variable symbols.
*/
- JCVariableDecl[] vardecls;
+ protected JCVariableDecl[] vardecls;
/** The current class being defined.
*/
@@ -1390,11 +1407,11 @@
/** The next available variable sequence number.
*/
- int nextadr;
+ protected int nextadr;
/** The first variable sequence number in a block that can return.
*/
- int returnadr;
+ protected int returnadr;
/** The list of unreferenced automatic resources.
*/
@@ -1406,35 +1423,46 @@
/** The starting position of the analysed tree */
int startPos;
- AssignAnalyzer() {
- inits = new Bits();
+ final Symtab syms;
+
+ protected Names names;
+
+ public static class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit {
+
+ final Bits inits;
+ final Bits uninits;
+ final Bits exit_inits = new Bits(true);
+ final Bits exit_uninits = new Bits(true);
+
+ public AbstractAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
+ super(tree);
+ this.inits = inits;
+ this.uninits = uninits;
+ this.exit_inits.assign(inits);
+ this.exit_uninits.assign(uninits);
+ }
+
+ @Override
+ public void resolveJump(JCTree tree) {
+ inits.andSet(exit_inits);
+ uninits.andSet(exit_uninits);
+ }
+ }
+
+ public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names) {
+ this.inits = inits;
uninits = new Bits();
uninitsTry = new Bits();
initsWhenTrue = new Bits(true);
initsWhenFalse = new Bits(true);
uninitsWhenTrue = new Bits(true);
uninitsWhenFalse = new Bits(true);
- }
-
- class AssignPendingExit extends BaseAnalyzer.PendingExit {
-
- final Bits exit_inits = new Bits(true);
- final Bits exit_uninits = new Bits(true);
-
- AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
- super(tree);
- this.exit_inits.assign(inits);
- this.exit_uninits.assign(uninits);
- }
-
- void resolveJump() {
- inits.andSet(exit_inits);
- uninits.andSet(exit_uninits);
- }
+ this.syms = syms;
+ this.names = names;
}
@Override
- void markDead() {
+ protected void markDead(JCTree tree) {
inits.inclRange(returnadr, nextadr);
uninits.inclRange(returnadr, nextadr);
}
@@ -1444,7 +1472,7 @@
/** Do we need to track init/uninit state of this symbol?
* I.e. is symbol either a local or a blank final variable?
*/
- boolean trackable(VarSymbol sym) {
+ protected boolean trackable(VarSymbol sym) {
return
sym.pos >= startPos &&
((sym.owner.kind == MTH ||
@@ -1464,44 +1492,35 @@
}
sym.adr = nextadr;
vardecls[nextadr] = varDecl;
- inits.excl(nextadr);
+ exclVarFromInits(varDecl, nextadr);
uninits.incl(nextadr);
nextadr++;
}
+ protected void exclVarFromInits(JCTree tree, int adr) {
+ inits.excl(adr);
+ }
+
+ protected void assignToInits(JCTree tree, Bits bits) {
+ inits.assign(bits);
+ }
+
+ protected void andSetInits(JCTree tree, Bits bits) {
+ inits.andSet(bits);
+ }
+
+ protected void orSetInits(JCTree tree, Bits bits) {
+ inits.orSet(bits);
+ }
+
/** Record an initialization of a trackable variable.
*/
void letInit(DiagnosticPosition pos, VarSymbol sym) {
if (sym.adr >= firstadr && trackable(sym)) {
- if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
- if (!uninits.isMember(sym.adr)) {
- //assignment targeting an effectively final variable
- //makes the variable lose its status of effectively final
- //if the variable is _not_ definitively unassigned
- sym.flags_field &= ~EFFECTIVELY_FINAL;
- } else {
- uninit(sym);
- }
- }
- else if ((sym.flags() & FINAL) != 0) {
- if ((sym.flags() & PARAMETER) != 0) {
- if ((sym.flags() & UNION) != 0) { //multi-catch parameter
- log.error(pos, "multicatch.parameter.may.not.be.assigned",
- sym);
- }
- else {
- log.error(pos, "final.parameter.may.not.be.assigned",
- sym);
- }
- } else if (!uninits.isMember(sym.adr)) {
- log.error(pos, flowKind.errKey, sym);
- } else {
- uninit(sym);
- }
+ if (uninits.isMember(sym.adr)) {
+ uninit(sym);
}
inits.incl(sym.adr);
- } else if ((sym.flags() & FINAL) != 0) {
- log.error(pos, "var.might.already.be.assigned", sym);
}
}
//where
@@ -1535,12 +1554,14 @@
void checkInit(DiagnosticPosition pos, VarSymbol sym) {
checkInit(pos, sym, "var.might.not.have.been.initialized");
}
- void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
- if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
- trackable(sym) &&
- !inits.isMember(sym.adr)) {
- log.error(pos, errkey, sym);
- inits.incl(sym.adr);
+
+ void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {}
+
+ /** Utility method to reset several Bits instances.
+ */
+ private void resetBits(Bits... bits) {
+ for (Bits b : bits) {
+ b.reset();
}
}
@@ -1558,7 +1579,7 @@
/** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
*/
- void merge() {
+ protected void merge(JCTree tree) {
inits.assign(initsWhenFalse.andSet(initsWhenTrue));
uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
}
@@ -1573,7 +1594,9 @@
void scanExpr(JCTree tree) {
if (tree != null) {
scan(tree);
- if (inits.isReset()) merge();
+ if (inits.isReset()) {
+ merge(tree);
+ }
}
}
@@ -1590,7 +1613,7 @@
*/
void scanCond(JCTree tree) {
if (tree.type.isFalse()) {
- if (inits.isReset()) merge();
+ if (inits.isReset()) merge(tree);
initsWhenTrue.assign(inits);
initsWhenTrue.inclRange(firstadr, nextadr);
uninitsWhenTrue.assign(uninits);
@@ -1598,7 +1621,7 @@
initsWhenFalse.assign(inits);
uninitsWhenFalse.assign(uninits);
} else if (tree.type.isTrue()) {
- if (inits.isReset()) merge();
+ if (inits.isReset()) merge(tree);
initsWhenFalse.assign(inits);
initsWhenFalse.inclRange(firstadr, nextadr);
uninitsWhenFalse.assign(uninits);
@@ -1617,22 +1640,22 @@
/* ------------ Visitor methods for various sorts of trees -------------*/
+ @Override
public void visitClassDef(JCClassDecl tree) {
- if (tree.sym == null) return;
+ if (tree.sym == null) {
+ return;
+ }
JCClassDecl classDefPrev = classDef;
int firstadrPrev = firstadr;
int nextadrPrev = nextadr;
- ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits;
- Lint lintPrev = lint;
+ ListBuffer<P> pendingExitsPrev = pendingExits;
- pendingExits = new ListBuffer<AssignPendingExit>();
+ pendingExits = new ListBuffer<P>();
if (tree.name != names.empty) {
firstadr = nextadr;
}
classDef = tree;
- lint = lint.augment(tree.sym);
-
try {
// define all the static fields
for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
@@ -1640,8 +1663,9 @@
JCVariableDecl def = (JCVariableDecl)l.head;
if ((def.mods.flags & STATIC) != 0) {
VarSymbol sym = def.sym;
- if (trackable(sym))
+ if (trackable(sym)) {
newVar(def);
+ }
}
}
}
@@ -1660,8 +1684,9 @@
JCVariableDecl def = (JCVariableDecl)l.head;
if ((def.mods.flags & STATIC) == 0) {
VarSymbol sym = def.sym;
- if (trackable(sym))
+ if (trackable(sym)) {
newVar(def);
+ }
}
}
}
@@ -1685,21 +1710,25 @@
nextadr = nextadrPrev;
firstadr = firstadrPrev;
classDef = classDefPrev;
- lint = lintPrev;
}
}
+ @Override
public void visitMethodDef(JCMethodDecl tree) {
- if (tree.body == null) return;
+ if (tree.body == null) {
+ return;
+ }
+ /* MemberEnter can generate synthetic methods, ignore them
+ */
+ if ((tree.sym.flags() & SYNTHETIC) != 0) {
+ return;
+ }
final Bits initsPrev = new Bits(inits);
final Bits uninitsPrev = new Bits(uninits);
int nextadrPrev = nextadr;
int firstadrPrev = firstadr;
int returnadrPrev = returnadr;
- Lint lintPrev = lint;
-
- lint = lint.augment(tree.sym);
Assert.check(pendingExits.isEmpty());
@@ -1707,13 +1736,17 @@
boolean isInitialConstructor =
TreeInfo.isInitialConstructor(tree);
- if (!isInitialConstructor)
+ if (!isInitialConstructor) {
firstadr = nextadr;
+ }
for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
JCVariableDecl def = l.head;
scan(def);
- inits.incl(def.sym.adr);
- uninits.excl(def.sym.adr);
+ Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
+ /* If we are executing the code from Gen, then there can be
+ * synthetic or mandated variables, ignore them.
+ */
+ initParam(def);
}
// else we are in an instance initializer block;
// leave caught unchanged.
@@ -1737,39 +1770,42 @@
}
}
}
- List<AssignPendingExit> exits = pendingExits.toList();
- pendingExits = new ListBuffer<AssignPendingExit>();
+ List<P> exits = pendingExits.toList();
+ pendingExits = new ListBuffer<>();
while (exits.nonEmpty()) {
- AssignPendingExit exit = exits.head;
+ P exit = exits.head;
exits = exits.tail;
Assert.check(exit.tree.hasTag(RETURN), exit.tree);
if (isInitialConstructor) {
- inits.assign(exit.exit_inits);
- for (int i = firstadr; i < nextadr; i++)
+ assignToInits(exit.tree, exit.exit_inits);
+ for (int i = firstadr; i < nextadr; i++) {
checkInit(exit.tree.pos(), vardecls[i].sym);
+ }
}
}
} finally {
- inits.assign(initsPrev);
+ assignToInits(tree, initsPrev);
uninits.assign(uninitsPrev);
nextadr = nextadrPrev;
firstadr = firstadrPrev;
returnadr = returnadrPrev;
- lint = lintPrev;
}
}
+ protected void initParam(JCVariableDecl def) {
+ inits.incl(def.sym.adr);
+ uninits.excl(def.sym.adr);
+ }
+
public void visitVarDef(JCVariableDecl tree) {
boolean track = trackable(tree.sym);
- if (track && tree.sym.owner.kind == MTH) newVar(tree);
+ if (track && tree.sym.owner.kind == MTH) {
+ newVar(tree);
+ }
if (tree.init != null) {
- Lint lintPrev = lint;
- lint = lint.augment(tree.sym);
- try{
- scanExpr(tree.init);
- if (track) letInit(tree.pos(), tree.sym);
- } finally {
- lint = lintPrev;
+ scanExpr(tree.init);
+ if (track) {
+ letInit(tree.pos(), tree.sym);
}
}
}
@@ -1780,14 +1816,18 @@
nextadr = nextadrPrev;
}
+ int getLogNumberOfErrors() {
+ return 0;
+ }
+
public void visitDoLoop(JCDoWhileLoop tree) {
- ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+ ListBuffer<P> prevPendingExits = pendingExits;
FlowKind prevFlowKind = flowKind;
flowKind = FlowKind.NORMAL;
final Bits initsSkip = new Bits(true);
final Bits uninitsSkip = new Bits(true);
- pendingExits = new ListBuffer<AssignPendingExit>();
- int prevErrors = log.nerrors;
+ pendingExits = new ListBuffer<P>();
+ int prevErrors = getLogNumberOfErrors();
do {
final Bits uninitsEntry = new Bits(uninits);
uninitsEntry.excludeFrom(nextadr);
@@ -1798,28 +1838,28 @@
initsSkip.assign(initsWhenFalse);
uninitsSkip.assign(uninitsWhenFalse);
}
- if (log.nerrors != prevErrors ||
+ if (getLogNumberOfErrors() != prevErrors ||
flowKind.isFinal() ||
new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
break;
- inits.assign(initsWhenTrue);
+ assignToInits(tree.cond, initsWhenTrue);
uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
flowKind = FlowKind.SPECULATIVE_LOOP;
} while (true);
flowKind = prevFlowKind;
- inits.assign(initsSkip);
+ assignToInits(tree, initsSkip);
uninits.assign(uninitsSkip);
resolveBreaks(tree, prevPendingExits);
}
public void visitWhileLoop(JCWhileLoop tree) {
- ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+ ListBuffer<P> prevPendingExits = pendingExits;
FlowKind prevFlowKind = flowKind;
flowKind = FlowKind.NORMAL;
final Bits initsSkip = new Bits(true);
final Bits uninitsSkip = new Bits(true);
- pendingExits = new ListBuffer<AssignPendingExit>();
- int prevErrors = log.nerrors;
+ pendingExits = new ListBuffer<>();
+ int prevErrors = getLogNumberOfErrors();
final Bits uninitsEntry = new Bits(uninits);
uninitsEntry.excludeFrom(nextadr);
do {
@@ -1828,35 +1868,36 @@
initsSkip.assign(initsWhenFalse) ;
uninitsSkip.assign(uninitsWhenFalse);
}
- inits.assign(initsWhenTrue);
+ assignToInits(tree, initsWhenTrue);
uninits.assign(uninitsWhenTrue);
scan(tree.body);
resolveContinues(tree);
- if (log.nerrors != prevErrors ||
+ if (getLogNumberOfErrors() != prevErrors ||
flowKind.isFinal() ||
- new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
+ new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) {
break;
+ }
uninits.assign(uninitsEntry.andSet(uninits));
flowKind = FlowKind.SPECULATIVE_LOOP;
} while (true);
flowKind = prevFlowKind;
//a variable is DA/DU after the while statement, if it's DA/DU assuming the
//branch is not taken AND if it's DA/DU before any break statement
- inits.assign(initsSkip);
+ assignToInits(tree.body, initsSkip);
uninits.assign(uninitsSkip);
resolveBreaks(tree, prevPendingExits);
}
public void visitForLoop(JCForLoop tree) {
- ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+ ListBuffer<P> prevPendingExits = pendingExits;
FlowKind prevFlowKind = flowKind;
flowKind = FlowKind.NORMAL;
int nextadrPrev = nextadr;
scan(tree.init);
final Bits initsSkip = new Bits(true);
final Bits uninitsSkip = new Bits(true);
- pendingExits = new ListBuffer<AssignPendingExit>();
- int prevErrors = log.nerrors;
+ pendingExits = new ListBuffer<P>();
+ int prevErrors = getLogNumberOfErrors();
do {
final Bits uninitsEntry = new Bits(uninits);
uninitsEntry.excludeFrom(nextadr);
@@ -1866,7 +1907,7 @@
initsSkip.assign(initsWhenFalse);
uninitsSkip.assign(uninitsWhenFalse);
}
- inits.assign(initsWhenTrue);
+ assignToInits(tree.body, initsWhenTrue);
uninits.assign(uninitsWhenTrue);
} else if (!flowKind.isFinal()) {
initsSkip.assign(inits);
@@ -1877,7 +1918,7 @@
scan(tree.body);
resolveContinues(tree);
scan(tree.step);
- if (log.nerrors != prevErrors ||
+ if (getLogNumberOfErrors() != prevErrors ||
flowKind.isFinal() ||
new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
break;
@@ -1887,7 +1928,7 @@
flowKind = prevFlowKind;
//a variable is DA/DU after a for loop, if it's DA/DU assuming the
//branch is not taken AND if it's DA/DU before any break statement
- inits.assign(initsSkip);
+ assignToInits(tree.body, initsSkip);
uninits.assign(uninitsSkip);
resolveBreaks(tree, prevPendingExits);
nextadr = nextadrPrev;
@@ -1896,7 +1937,7 @@
public void visitForeachLoop(JCEnhancedForLoop tree) {
visitVarDef(tree.var);
- ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+ ListBuffer<P> prevPendingExits = pendingExits;
FlowKind prevFlowKind = flowKind;
flowKind = FlowKind.NORMAL;
int nextadrPrev = nextadr;
@@ -1905,14 +1946,14 @@
final Bits uninitsStart = new Bits(uninits);
letInit(tree.pos(), tree.var.sym);
- pendingExits = new ListBuffer<AssignPendingExit>();
- int prevErrors = log.nerrors;
+ pendingExits = new ListBuffer<P>();
+ int prevErrors = getLogNumberOfErrors();
do {
final Bits uninitsEntry = new Bits(uninits);
uninitsEntry.excludeFrom(nextadr);
scan(tree.body);
resolveContinues(tree);
- if (log.nerrors != prevErrors ||
+ if (getLogNumberOfErrors() != prevErrors ||
flowKind.isFinal() ||
new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
break;
@@ -1920,41 +1961,50 @@
flowKind = FlowKind.SPECULATIVE_LOOP;
} while (true);
flowKind = prevFlowKind;
- inits.assign(initsStart);
+ assignToInits(tree.body, initsStart);
uninits.assign(uninitsStart.andSet(uninits));
resolveBreaks(tree, prevPendingExits);
nextadr = nextadrPrev;
}
public void visitLabelled(JCLabeledStatement tree) {
- ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
- pendingExits = new ListBuffer<AssignPendingExit>();
+ ListBuffer<P> prevPendingExits = pendingExits;
+ pendingExits = new ListBuffer<P>();
scan(tree.body);
resolveBreaks(tree, prevPendingExits);
}
public void visitSwitch(JCSwitch tree) {
- ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
- pendingExits = new ListBuffer<AssignPendingExit>();
+ ListBuffer<P> prevPendingExits = pendingExits;
+ pendingExits = new ListBuffer<>();
int nextadrPrev = nextadr;
scanExpr(tree.selector);
final Bits initsSwitch = new Bits(inits);
final Bits uninitsSwitch = new Bits(uninits);
boolean hasDefault = false;
for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
- inits.assign(initsSwitch);
+ assignToInits(l.head, initsSwitch);
uninits.assign(uninits.andSet(uninitsSwitch));
JCCase c = l.head;
- if (c.pat == null)
+ if (c.pat == null) {
hasDefault = true;
- else
+ } else {
scanExpr(c.pat);
+ }
+ if (hasDefault) {
+ assignToInits(null, initsSwitch);
+ uninits.assign(uninits.andSet(uninitsSwitch));
+ }
scan(c.stats);
addVars(c.stats, initsSwitch, uninitsSwitch);
+ if (!hasDefault) {
+ assignToInits(l.head.stats.last(), initsSwitch);
+ uninits.assign(uninits.andSet(uninitsSwitch));
+ }
// Warn about fall-through if lint switch fallthrough enabled.
}
if (!hasDefault) {
- inits.andSet(initsSwitch);
+ andSetInits(null, initsSwitch);
}
resolveBreaks(tree, prevPendingExits);
nextadr = nextadrPrev;
@@ -1973,11 +2023,17 @@
}
}
+ boolean isEnabled(Lint.LintCategory lc) {
+ return false;
+ }
+
+ void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos, String key, Object ... args) {}
+
public void visitTry(JCTry tree) {
ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
final Bits uninitsTryPrev = new Bits(uninitsTry);
- ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
- pendingExits = new ListBuffer<AssignPendingExit>();
+ ListBuffer<P> prevPendingExits = pendingExits;
+ pendingExits = new ListBuffer<>();
final Bits initsTry = new Bits(inits);
uninitsTry.assign(uninits);
for (JCTree resource : tree.resources) {
@@ -1999,10 +2055,10 @@
int nextadrCatch = nextadr;
if (!resourceVarDecls.isEmpty() &&
- lint.isEnabled(Lint.LintCategory.TRY)) {
+ isEnabled(Lint.LintCategory.TRY)) {
for (JCVariableDecl resVar : resourceVarDecls) {
if (unrefdResources.includes(resVar.sym)) {
- log.warning(Lint.LintCategory.TRY, resVar.pos(),
+ reportWarning(Lint.LintCategory.TRY, resVar.pos(),
"try.resource.not.referenced", resVar.sym);
unrefdResources.remove(resVar.sym);
}
@@ -2018,20 +2074,22 @@
for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
JCVariableDecl param = l.head.param;
- inits.assign(initsCatchPrev);
+ assignToInits(tree.body, initsCatchPrev);
uninits.assign(uninitsCatchPrev);
scan(param);
- inits.incl(param.sym.adr);
- uninits.excl(param.sym.adr);
+ /* If this is a TWR and we are executing the code from Gen,
+ * then there can be synthetic variables, ignore them.
+ */
+ initParam(param);
scan(l.head.body);
initsEnd.andSet(inits);
uninitsEnd.andSet(uninits);
nextadr = nextadrCatch;
}
if (tree.finalizer != null) {
- inits.assign(initsTry);
+ assignToInits(tree.finalizer, initsTry);
uninits.assign(uninitsTry);
- ListBuffer<AssignPendingExit> exits = pendingExits;
+ ListBuffer<P> exits = pendingExits;
pendingExits = prevPendingExits;
scan(tree.finalizer);
if (!tree.finallyCanCompleteNormally) {
@@ -2041,19 +2099,19 @@
// FIX: this doesn't preserve source order of exits in catch
// versus finally!
while (exits.nonEmpty()) {
- AssignPendingExit exit = exits.next();
+ P exit = exits.next();
if (exit.exit_inits != null) {
exit.exit_inits.orSet(inits);
exit.exit_uninits.andSet(uninits);
}
pendingExits.append(exit);
}
- inits.orSet(initsEnd);
+ orSetInits(tree, initsEnd);
}
} else {
- inits.assign(initsEnd);
+ assignToInits(tree, initsEnd);
uninits.assign(uninitsEnd);
- ListBuffer<AssignPendingExit> exits = pendingExits;
+ ListBuffer<P> exits = pendingExits;
pendingExits = prevPendingExits;
while (exits.nonEmpty()) pendingExits.append(exits.next());
}
@@ -2064,7 +2122,7 @@
scanCond(tree.cond);
final Bits initsBeforeElse = new Bits(initsWhenFalse);
final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
- inits.assign(initsWhenTrue);
+ assignToInits(tree.cond, initsWhenTrue);
uninits.assign(uninitsWhenTrue);
if (tree.truepart.type.hasTag(BOOLEAN) &&
tree.falsepart.type.hasTag(BOOLEAN)) {
@@ -2077,7 +2135,7 @@
final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
- inits.assign(initsBeforeElse);
+ assignToInits(tree.truepart, initsBeforeElse);
uninits.assign(uninitsBeforeElse);
scanCond(tree.falsepart);
initsWhenTrue.andSet(initsAfterThenWhenTrue);
@@ -2088,10 +2146,10 @@
scanExpr(tree.truepart);
final Bits initsAfterThen = new Bits(inits);
final Bits uninitsAfterThen = new Bits(uninits);
- inits.assign(initsBeforeElse);
+ assignToInits(tree.truepart, initsBeforeElse);
uninits.assign(uninitsBeforeElse);
scanExpr(tree.falsepart);
- inits.andSet(initsAfterThen);
+ andSetInits(tree.falsepart, initsAfterThen);
uninits.andSet(uninitsAfterThen);
}
}
@@ -2100,39 +2158,46 @@
scanCond(tree.cond);
final Bits initsBeforeElse = new Bits(initsWhenFalse);
final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
- inits.assign(initsWhenTrue);
+ assignToInits(tree.cond, initsWhenTrue);
uninits.assign(uninitsWhenTrue);
scan(tree.thenpart);
if (tree.elsepart != null) {
final Bits initsAfterThen = new Bits(inits);
final Bits uninitsAfterThen = new Bits(uninits);
- inits.assign(initsBeforeElse);
+ assignToInits(tree.thenpart, initsBeforeElse);
uninits.assign(uninitsBeforeElse);
scan(tree.elsepart);
- inits.andSet(initsAfterThen);
+ andSetInits(tree.elsepart, initsAfterThen);
uninits.andSet(uninitsAfterThen);
} else {
- inits.andSet(initsBeforeElse);
+ andSetInits(tree.thenpart, initsBeforeElse);
uninits.andSet(uninitsBeforeElse);
}
}
+ protected P createNewPendingExit(JCTree tree, Bits inits, Bits uninits) {
+ return null;
+ }
+
+ @Override
public void visitBreak(JCBreak tree) {
- recordExit(tree, new AssignPendingExit(tree, inits, uninits));
+ recordExit(tree, createNewPendingExit(tree, inits, uninits));
}
+ @Override
public void visitContinue(JCContinue tree) {
- recordExit(tree, new AssignPendingExit(tree, inits, uninits));
+ recordExit(tree, createNewPendingExit(tree, inits, uninits));
}
+ @Override
public void visitReturn(JCReturn tree) {
scanExpr(tree.expr);
- recordExit(tree, new AssignPendingExit(tree, inits, uninits));
+ recordExit(tree, createNewPendingExit(tree, inits, uninits));
}
public void visitThrow(JCThrow tree) {
scanExpr(tree.expr);
- markDead();
+ markDead(tree.expr);
}
public void visitApply(JCMethodInvocation tree) {
@@ -2151,10 +2216,10 @@
final Bits prevUninits = new Bits(uninits);
final Bits prevInits = new Bits(inits);
int returnadrPrev = returnadr;
- ListBuffer<AssignPendingExit> prevPending = pendingExits;
+ ListBuffer<P> prevPending = pendingExits;
try {
returnadr = nextadr;
- pendingExits = new ListBuffer<AssignPendingExit>();
+ pendingExits = new ListBuffer<P>();
for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
JCVariableDecl def = l.head;
scan(def);
@@ -2170,7 +2235,7 @@
finally {
returnadr = returnadrPrev;
uninits.assign(prevUninits);
- inits.assign(prevInits);
+ assignToInits(tree, prevInits);
pendingExits = prevPending;
}
}
@@ -2186,11 +2251,11 @@
scanCond(tree.cond);
uninitsExit.andSet(uninitsWhenTrue);
if (tree.detail != null) {
- inits.assign(initsWhenFalse);
+ assignToInits(tree, initsWhenFalse);
uninits.assign(uninitsWhenFalse);
scanExpr(tree.detail);
}
- inits.assign(initsExit);
+ assignToInits(tree, initsExit);
uninits.assign(uninitsExit);
}
@@ -2236,7 +2301,7 @@
scanCond(tree.lhs);
final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
- inits.assign(initsWhenTrue);
+ assignToInits(tree.lhs, initsWhenTrue);
uninits.assign(uninitsWhenTrue);
scanCond(tree.rhs);
initsWhenFalse.andSet(initsWhenFalseLeft);
@@ -2246,7 +2311,7 @@
scanCond(tree.lhs);
final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
- inits.assign(initsWhenFalse);
+ assignToInits(tree.lhs, initsWhenFalse);
uninits.assign(uninitsWhenFalse);
scanCond(tree.rhs);
initsWhenTrue.andSet(initsWhenTrueLeft);
@@ -2284,14 +2349,12 @@
/** Perform definite assignment/unassignment analysis on a tree.
*/
- public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
- analyzeTree(env, env.tree, make);
- }
+ public void analyzeTree(Env<?> env) {
+ analyzeTree(env, env.tree);
+ }
- public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
+ public void analyzeTree(Env<?> env, JCTree tree) {
try {
- attrEnv = env;
- Flow.this.make = make;
startPos = tree.pos().getStartPosition();
if (vardecls == null)
@@ -2301,7 +2364,7 @@
vardecls[i] = null;
firstadr = 0;
nextadr = 0;
- pendingExits = new ListBuffer<AssignPendingExit>();
+ pendingExits = new ListBuffer<>();
this.classDef = null;
unrefdResources = new Scope(env.enclClass.sym);
scan(tree);
@@ -2310,18 +2373,160 @@
startPos = -1;
resetBits(inits, uninits, uninitsTry, initsWhenTrue,
initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
- if (vardecls != null) for (int i=0; i<vardecls.length; i++)
- vardecls[i] = null;
+ if (vardecls != null) {
+ for (int i=0; i<vardecls.length; i++)
+ vardecls[i] = null;
+ }
firstadr = 0;
nextadr = 0;
pendingExits = null;
- Flow.this.make = null;
this.classDef = null;
unrefdResources = null;
}
}
}
+ public static class AssignAnalyzer
+ extends AbstractAssignAnalyzer<AssignAnalyzer.AssignPendingExit> {
+
+ Log log;
+ Lint lint;
+
+ public static class AssignPendingExit
+ extends AbstractAssignAnalyzer.AbstractAssignPendingExit {
+
+ public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
+ super(tree, inits, uninits);
+ }
+ }
+
+ public AssignAnalyzer(Log log, Symtab syms, Lint lint, Names names) {
+ super(new Bits(), syms, names);
+ this.log = log;
+ this.lint = lint;
+ }
+
+ @Override
+ protected AssignPendingExit createNewPendingExit(JCTree tree,
+ Bits inits, Bits uninits) {
+ return new AssignPendingExit(tree, inits, uninits);
+ }
+
+ /** Record an initialization of a trackable variable.
+ */
+ @Override
+ void letInit(DiagnosticPosition pos, VarSymbol sym) {
+ if (sym.adr >= firstadr && trackable(sym)) {
+ if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
+ if (!uninits.isMember(sym.adr)) {
+ //assignment targeting an effectively final variable
+ //makes the variable lose its status of effectively final
+ //if the variable is _not_ definitively unassigned
+ sym.flags_field &= ~EFFECTIVELY_FINAL;
+ } else {
+ uninit(sym);
+ }
+ }
+ else if ((sym.flags() & FINAL) != 0) {
+ if ((sym.flags() & PARAMETER) != 0) {
+ if ((sym.flags() & UNION) != 0) { //multi-catch parameter
+ log.error(pos, "multicatch.parameter.may.not.be.assigned", sym);
+ }
+ else {
+ log.error(pos, "final.parameter.may.not.be.assigned",
+ sym);
+ }
+ } else if (!uninits.isMember(sym.adr)) {
+ log.error(pos, flowKind.errKey, sym);
+ } else {
+ uninit(sym);
+ }
+ }
+ inits.incl(sym.adr);
+ } else if ((sym.flags() & FINAL) != 0) {
+ log.error(pos, "var.might.already.be.assigned", sym);
+ }
+ }
+
+ @Override
+ void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
+ if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
+ trackable(sym) &&
+ !inits.isMember(sym.adr)) {
+ log.error(pos, errkey, sym);
+ inits.incl(sym.adr);
+ }
+ }
+
+ @Override
+ void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos,
+ String key, Object ... args) {
+ log.warning(lc, pos, key, args);
+ }
+
+ @Override
+ int getLogNumberOfErrors() {
+ return log.nerrors;
+ }
+
+ @Override
+ boolean isEnabled(Lint.LintCategory lc) {
+ return lint.isEnabled(lc);
+ }
+
+ @Override
+ public void visitClassDef(JCClassDecl tree) {
+ if (tree.sym == null) {
+ return;
+ }
+
+ Lint lintPrev = lint;
+ lint = lint.augment(tree.sym);
+ try {
+ super.visitClassDef(tree);
+ } finally {
+ lint = lintPrev;
+ }
+ }
+
+ @Override
+ public void visitMethodDef(JCMethodDecl tree) {
+ if (tree.body == null) {
+ return;
+ }
+
+ /* MemberEnter can generate synthetic methods ignore them
+ */
+ if ((tree.sym.flags() & SYNTHETIC) != 0) {
+ return;
+ }
+
+ Lint lintPrev = lint;
+ lint = lint.augment(tree.sym);
+ try {
+ super.visitMethodDef(tree);
+ } finally {
+ lint = lintPrev;
+ }
+ }
+
+ @Override
+ public void visitVarDef(JCVariableDecl tree) {
+ if (tree.init == null) {
+ super.visitVarDef(tree);
+ } else {
+ Lint lintPrev = lint;
+ lint = lint.augment(tree.sym);
+ try{
+ super.visitVarDef(tree);
+ } finally {
+ lint = lintPrev;
+ }
+ }
+ }
+
+ }
+
/**
* This pass implements the last step of the dataflow analysis, namely
* the effectively-final analysis check. This checks that every local variable
@@ -2334,7 +2539,7 @@
JCTree currentTree; //local class or lambda
@Override
- void markDead() {
+ void markDead(JCTree tree) {
//do nothing
}
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Sat Sep 14 20:43:34 2013 +0100
@@ -40,17 +40,17 @@
import com.sun.tools.javac.comp.Infer.GraphSolver.InferenceGraph.Node;
import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
-
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
+import com.sun.tools.javac.util.GraphUtils.TarjanNode;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.EnumMap;
import java.util.EnumSet;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
import static com.sun.tools.javac.code.TypeTag.*;
@@ -114,6 +114,12 @@
}
@Override
+ InapplicableMethodException setMessage() {
+ //no message to set
+ return this;
+ }
+
+ @Override
InapplicableMethodException setMessage(JCDiagnostic diag) {
messages = messages.append(diag);
return this;
@@ -1006,10 +1012,24 @@
* and (ii) tell th engine when we are done fixing inference variables
*/
interface GraphStrategy {
+
+ /**
+ * A NodeNotFoundException is thrown whenever an inference strategy fails
+ * to pick the next node to solve in the inference graph.
+ */
+ public static class NodeNotFoundException extends RuntimeException {
+ private static final long serialVersionUID = 0;
+
+ InferenceGraph graph;
+
+ public NodeNotFoundException(InferenceGraph graph) {
+ this.graph = graph;
+ }
+ }
/**
* Pick the next node (leaf) to solve in the graph
*/
- Node pickNode(InferenceGraph g);
+ Node pickNode(InferenceGraph g) throws NodeNotFoundException;
/**
* Is this the last step?
*/
@@ -1022,7 +1042,10 @@
*/
abstract class LeafSolver implements GraphStrategy {
public Node pickNode(InferenceGraph g) {
- Assert.check(!g.nodes.isEmpty(), "No nodes to solve!");
+ if (g.nodes.isEmpty()) {
+ //should not happen
+ throw new NodeNotFoundException(g);
+ };
return g.nodes.get(0);
}
@@ -1069,6 +1092,7 @@
*/
abstract class BestLeafSolver extends LeafSolver {
+ /** list of ivars of which at least one must be solved */
List<Type> varsToSolve;
BestLeafSolver(List<Type> varsToSolve) {
@@ -1076,54 +1100,66 @@
}
/**
- * Computes the minimum path that goes from a given node to any of the nodes
- * containing a variable in {@code varsToSolve}. For any given path, the cost
- * is computed as the total number of type-variables that should be eagerly
- * instantiated across that path.
+ * Computes a path that goes from a given node to the leafs in the graph.
+ * Typically this will start from a node containing a variable in
+ * {@code varsToSolve}. For any given path, the cost is computed as the total
+ * number of type-variables that should be eagerly instantiated across that path.
*/
- int computeMinPath(InferenceGraph g, Node n) {
- return computeMinPath(g, n, List.<Node>nil(), 0);
+ Pair<List<Node>, Integer> computeTreeToLeafs(Node n) {
+ Pair<List<Node>, Integer> cachedPath = treeCache.get(n);
+ if (cachedPath == null) {
+ //cache miss
+ if (n.isLeaf()) {
+ //if leaf, stop
+ cachedPath = new Pair<List<Node>, Integer>(List.of(n), n.data.length());
+ } else {
+ //if non-leaf, proceed recursively
+ Pair<List<Node>, Integer> path = new Pair<List<Node>, Integer>(List.of(n), n.data.length());
+ for (Node n2 : n.getAllDependencies()) {
+ if (n2 == n) continue;
+ Pair<List<Node>, Integer> subpath = computeTreeToLeafs(n2);
+ path = new Pair<List<Node>, Integer>(
+ path.fst.prependList(subpath.fst),
+ path.snd + subpath.snd);
+ }
+ cachedPath = path;
+ }
+ //save results in cache
+ treeCache.put(n, cachedPath);
+ }
+ return cachedPath;
}
- int computeMinPath(InferenceGraph g, Node n, List<Node> path, int cost) {
- if (path.contains(n)) return Integer.MAX_VALUE;
- List<Node> path2 = path.prepend(n);
- int cost2 = cost + n.data.size();
- if (!Collections.disjoint(n.data, varsToSolve)) {
- return cost2;
- } else {
- int bestPath = Integer.MAX_VALUE;
- for (Node n2 : g.nodes) {
- if (n2.deps.contains(n)) {
- int res = computeMinPath(g, n2, path2, cost2);
- if (res < bestPath) {
- bestPath = res;
- }
- }
- }
- return bestPath;
- }
- }
+ /** cache used to avoid redundant computation of tree costs */
+ final Map<Node, Pair<List<Node>, Integer>> treeCache =
+ new HashMap<Node, Pair<List<Node>, Integer>>();
+
+ /** constant value used to mark non-existent paths */
+ final Pair<List<Node>, Integer> noPath =
+ new Pair<List<Node>, Integer>(null, Integer.MAX_VALUE);
/**
* Pick the leaf that minimize cost
*/
@Override
public Node pickNode(final InferenceGraph g) {
- final Map<Node, Integer> leavesMap = new HashMap<Node, Integer>();
+ treeCache.clear(); //graph changes at every step - cache must be cleared
+ Pair<List<Node>, Integer> bestPath = noPath;
for (Node n : g.nodes) {
- if (n.isLeaf(n)) {
- leavesMap.put(n, computeMinPath(g, n));
+ if (!Collections.disjoint(n.data, varsToSolve)) {
+ Pair<List<Node>, Integer> path = computeTreeToLeafs(n);
+ //discard all paths containing at least a node in the
+ //closure computed above
+ if (path.snd < bestPath.snd) {
+ bestPath = path;
+ }
}
}
- Assert.check(!leavesMap.isEmpty(), "No nodes to solve!");
- TreeSet<Node> orderedLeaves = new TreeSet<Node>(new Comparator<Node>() {
- public int compare(Node n1, Node n2) {
- return leavesMap.get(n1) - leavesMap.get(n2);
- }
- });
- orderedLeaves.addAll(leavesMap.keySet());
- return orderedLeaves.first();
+ if (bestPath == noPath) {
+ //no path leads there
+ throw new NodeNotFoundException(g);
+ }
+ return bestPath.fst.head;
}
}
@@ -1321,6 +1357,33 @@
}
/**
+ * There are two kinds of dependencies between inference variables. The basic
+ * kind of dependency (or bound dependency) arises when a variable mention
+ * another variable in one of its bounds. There's also a more subtle kind
+ * of dependency that arises when a variable 'might' lead to better constraints
+ * on another variable (this is typically the case with variables holding up
+ * stuck expressions).
+ */
+ enum DependencyKind implements GraphUtils.DependencyKind {
+
+ /** bound dependency */
+ BOUND("dotted"),
+ /** stuck dependency */
+ STUCK("dashed");
+
+ final String dotSyle;
+
+ private DependencyKind(String dotSyle) {
+ this.dotSyle = dotSyle;
+ }
+
+ @Override
+ public String getDotStyle() {
+ return dotSyle;
+ }
+ }
+
+ /**
* This is the graph inference solver - the solver organizes all inference variables in
* a given inference context by bound dependencies - in the general case, such dependencies
* would lead to a cyclic directed graph (hence the name); the dependency info is used to build
@@ -1331,10 +1394,12 @@
class GraphSolver {
InferenceContext inferenceContext;
+ Map<Type, Set<Type>> stuckDeps;
Warner warn;
- GraphSolver(InferenceContext inferenceContext, Warner warn) {
+ GraphSolver(InferenceContext inferenceContext, Map<Type, Set<Type>> stuckDeps, Warner warn) {
this.inferenceContext = inferenceContext;
+ this.stuckDeps = stuckDeps;
this.warn = warn;
}
@@ -1345,7 +1410,7 @@
*/
void solve(GraphStrategy sstrategy) {
checkWithinBounds(inferenceContext, warn); //initial propagation of bounds
- InferenceGraph inferenceGraph = new InferenceGraph();
+ InferenceGraph inferenceGraph = new InferenceGraph(stuckDeps);
while (!sstrategy.done()) {
InferenceGraph.Node nodeToSolve = sstrategy.pickNode(inferenceGraph);
List<Type> varsToSolve = List.from(nodeToSolve.data);
@@ -1390,64 +1455,172 @@
*/
class Node extends GraphUtils.TarjanNode<ListBuffer<Type>> {
- Set<Node> deps;
+ /** map listing all dependencies (grouped by kind) */
+ EnumMap<DependencyKind, Set<Node>> deps;
Node(Type ivar) {
super(ListBuffer.of(ivar));
- this.deps = new HashSet<Node>();
+ this.deps = new EnumMap<DependencyKind, Set<Node>>(DependencyKind.class);
+ }
+
+ @Override
+ public GraphUtils.DependencyKind[] getSupportedDependencyKinds() {
+ return DependencyKind.values();
}
@Override
- public Iterable<? extends Node> getDependencies() {
- return deps;
+ public String getDependencyName(GraphUtils.Node<ListBuffer<Type>> to, GraphUtils.DependencyKind dk) {
+ if (dk == DependencyKind.STUCK) return "";
+ else {
+ StringBuilder buf = new StringBuilder();
+ String sep = "";
+ for (Type from : data) {
+ UndetVar uv = (UndetVar)inferenceContext.asFree(from);
+ for (Type bound : uv.getBounds(InferenceBound.values())) {
+ if (bound.containsAny(List.from(to.data))) {
+ buf.append(sep);
+ buf.append(bound);
+ sep = ",";
+ }
+ }
+ }
+ return buf.toString();
+ }
+ }
+
+ @Override
+ public Iterable<? extends Node> getAllDependencies() {
+ return getDependencies(DependencyKind.values());
}
@Override
- public String printDependency(GraphUtils.Node<ListBuffer<Type>> to) {
- StringBuilder buf = new StringBuilder();
- String sep = "";
- for (Type from : data) {
- UndetVar uv = (UndetVar)inferenceContext.asFree(from);
- for (Type bound : uv.getBounds(InferenceBound.values())) {
- if (bound.containsAny(List.from(to.data))) {
- buf.append(sep);
- buf.append(bound);
- sep = ",";
- }
+ public Iterable<? extends TarjanNode<ListBuffer<Type>>> getDependenciesByKind(GraphUtils.DependencyKind dk) {
+ return getDependencies((DependencyKind)dk);
+ }
+
+ /**
+ * Retrieves all dependencies with given kind(s).
+ */
+ protected Set<Node> getDependencies(DependencyKind... depKinds) {
+ Set<Node> buf = new LinkedHashSet<Node>();
+ for (DependencyKind dk : depKinds) {
+ Set<Node> depsByKind = deps.get(dk);
+ if (depsByKind != null) {
+ buf.addAll(depsByKind);
}
}
- return buf.toString();
+ return buf;
+ }
+
+ /**
+ * Adds dependency with given kind.
+ */
+ protected void addDependency(DependencyKind dk, Node depToAdd) {
+ Set<Node> depsByKind = deps.get(dk);
+ if (depsByKind == null) {
+ depsByKind = new LinkedHashSet<Node>();
+ deps.put(dk, depsByKind);
+ }
+ depsByKind.add(depToAdd);
+ }
+
+ /**
+ * Add multiple dependencies of same given kind.
+ */
+ protected void addDependencies(DependencyKind dk, Set<Node> depsToAdd) {
+ for (Node n : depsToAdd) {
+ addDependency(dk, n);
+ }
+ }
+
+ /**
+ * Remove a dependency, regardless of its kind.
+ */
+ protected Set<DependencyKind> removeDependency(Node n) {
+ Set<DependencyKind> removedKinds = new HashSet<>();
+ for (DependencyKind dk : DependencyKind.values()) {
+ Set<Node> depsByKind = deps.get(dk);
+ if (depsByKind == null) continue;
+ if (depsByKind.remove(n)) {
+ removedKinds.add(dk);
+ }
+ }
+ return removedKinds;
}
- boolean isLeaf(Node n) {
- //no deps, or only one self dep
- return (n.deps.isEmpty() ||
- n.deps.size() == 1 && n.deps.contains(n));
+ /**
+ * Compute closure of a give node, by recursively walking
+ * through all its dependencies (of given kinds)
+ */
+ protected Set<Node> closure(DependencyKind... depKinds) {
+ boolean progress = true;
+ Set<Node> closure = new HashSet<Node>();
+ closure.add(this);
+ while (progress) {
+ progress = false;
+ for (Node n1 : new HashSet<Node>(closure)) {
+ progress = closure.addAll(n1.getDependencies(depKinds));
+ }
+ }
+ return closure;
}
- void mergeWith(List<? extends Node> nodes) {
+ /**
+ * Is this node a leaf? This means either the node has no dependencies,
+ * or it just has self-dependencies.
+ */
+ protected boolean isLeaf() {
+ //no deps, or only one self dep
+ Set<Node> allDeps = getDependencies(DependencyKind.BOUND, DependencyKind.STUCK);
+ if (allDeps.isEmpty()) return true;
+ for (Node n : allDeps) {
+ if (n != this) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Merge this node with another node, acquiring its dependencies.
+ * This routine is used to merge all cyclic node together and
+ * form an acyclic graph.
+ */
+ protected void mergeWith(List<? extends Node> nodes) {
for (Node n : nodes) {
Assert.check(n.data.length() == 1, "Attempt to merge a compound node!");
data.appendList(n.data);
- deps.addAll(n.deps);
+ for (DependencyKind dk : DependencyKind.values()) {
+ addDependencies(dk, n.getDependencies(dk));
+ }
}
//update deps
- Set<Node> deps2 = new HashSet<Node>();
- for (Node d : deps) {
- if (data.contains(d.data.first())) {
- deps2.add(this);
- } else {
- deps2.add(d);
+ EnumMap<DependencyKind, Set<Node>> deps2 = new EnumMap<DependencyKind, Set<Node>>(DependencyKind.class);
+ for (DependencyKind dk : DependencyKind.values()) {
+ for (Node d : getDependencies(dk)) {
+ Set<Node> depsByKind = deps2.get(dk);
+ if (depsByKind == null) {
+ depsByKind = new LinkedHashSet<Node>();
+ deps2.put(dk, depsByKind);
+ }
+ if (data.contains(d.data.first())) {
+ depsByKind.add(this);
+ } else {
+ depsByKind.add(d);
+ }
}
}
deps = deps2;
}
- void graphChanged(Node from, Node to) {
- if (deps.contains(from)) {
- deps.remove(from);
+ /**
+ * Notify all nodes that something has changed in the graph
+ * topology.
+ */
+ private void graphChanged(Node from, Node to) {
+ for (DependencyKind dk : removeDependency(from)) {
if (to != null) {
- deps.add(to);
+ addDependency(dk, to);
}
}
}
@@ -1456,8 +1629,21 @@
/** the nodes in the inference graph */
ArrayList<Node> nodes;
- InferenceGraph() {
- initNodes();
+ InferenceGraph(Map<Type, Set<Type>> optDeps) {
+ initNodes(optDeps);
+ }
+
+ /**
+ * Basic lookup helper for retrieving a graph node given an inference
+ * variable type.
+ */
+ public Node findNode(Type t) {
+ for (Node n : nodes) {
+ if (n.data.contains(t)) {
+ return n;
+ }
+ }
+ return null;
}
/**
@@ -1484,24 +1670,32 @@
* Create the graph nodes. First a simple node is created for every inference
* variables to be solved. Then Tarjan is used to found all connected components
* in the graph. For each component containing more than one node, a super node is
- * created, effectively replacing the original cyclic nodes.
+ * created, effectively replacing the original cyclic nodes.
*/
- void initNodes() {
+ void initNodes(Map<Type, Set<Type>> stuckDeps) {
+ //add nodes
nodes = new ArrayList<Node>();
for (Type t : inferenceContext.restvars()) {
nodes.add(new Node(t));
}
+ //add dependencies
for (Node n_i : nodes) {
Type i = n_i.data.first();
+ Set<Type> optDepsByNode = stuckDeps.get(i);
for (Node n_j : nodes) {
Type j = n_j.data.first();
UndetVar uv_i = (UndetVar)inferenceContext.asFree(i);
if (Type.containsAny(uv_i.getBounds(InferenceBound.values()), List.of(j))) {
- //update i's deps
- n_i.deps.add(n_j);
+ //update i's bound dependencies
+ n_i.addDependency(DependencyKind.BOUND, n_j);
+ }
+ if (optDepsByNode != null && optDepsByNode.contains(j)) {
+ //update i's stuck dependencies
+ n_i.addDependency(DependencyKind.STUCK, n_j);
}
}
}
+ //merge cyclic nodes
ArrayList<Node> acyclicNodes = new ArrayList<Node>();
for (List<? extends Node> conSubGraph : GraphUtils.tarjan(nodes)) {
if (conSubGraph.length() > 1) {
@@ -1631,8 +1825,8 @@
return filterVars(new Filter<UndetVar>() {
public boolean accepts(UndetVar uv) {
return uv.getBounds(InferenceBound.UPPER)
- .diff(uv.getDeclaredBounds())
- .appendList(uv.getBounds(InferenceBound.EQ, InferenceBound.LOWER)).nonEmpty();
+ .diff(uv.getDeclaredBounds())
+ .appendList(uv.getBounds(InferenceBound.EQ, InferenceBound.LOWER)).nonEmpty();
}
});
}
@@ -1822,11 +2016,15 @@
}
}
+ private void solve(GraphStrategy ss, Warner warn) {
+ solve(ss, new HashMap<Type, Set<Type>>(), warn);
+ }
+
/**
* Solve with given graph strategy.
*/
- private void solve(GraphStrategy ss, Warner warn) {
- GraphSolver s = new GraphSolver(this, warn);
+ private void solve(GraphStrategy ss, Map<Type, Set<Type>> stuckDeps, Warner warn) {
+ GraphSolver s = new GraphSolver(this, stuckDeps, warn);
s.solve(ss);
}
@@ -1855,18 +2053,12 @@
/**
* Solve at least one variable in given list.
*/
- public void solveAny(List<Type> varsToSolve, Warner warn) {
- checkWithinBounds(this, warn); //propagate bounds
- List<Type> boundedVars = boundedVars().intersect(restvars()).intersect(varsToSolve);
- if (boundedVars.isEmpty()) {
- throw inferenceException.setMessage("cyclic.inference",
- freeVarsIn(varsToSolve));
- }
- solve(new BestLeafSolver(boundedVars) {
+ public void solveAny(List<Type> varsToSolve, Map<Type, Set<Type>> optDeps, Warner warn) {
+ solve(new BestLeafSolver(varsToSolve.intersect(restvars())) {
public boolean done() {
return instvars().intersect(varsToSolve).nonEmpty();
}
- }, warn);
+ }, optDeps, warn);
}
/**
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Sat Sep 14 20:43:34 2013 +0100
@@ -1745,6 +1745,11 @@
// Just erase the type var
ret = new VarSymbol(sym.flags(), name,
types.erasure(sym.type), sym.owner);
+
+ /* this information should also be kept for LVT generation at Gen
+ * a Symbol with pos < startPos won't be tracked.
+ */
+ ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
break;
case CAPTURED_VAR:
ret = new VarSymbol(SYNTHETIC | FINAL, name, types.erasure(sym.type), translatedSym) {
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java Sat Sep 14 20:43:34 2013 +0100
@@ -49,7 +49,6 @@
import static com.sun.tools.javac.code.TypeTag.*;
import static com.sun.tools.javac.jvm.ByteCodes.*;
import static com.sun.tools.javac.tree.JCTree.Tag.*;
-import javax.lang.model.type.TypeKind;
/** This pass translates away some syntactic sugar: inner classes,
* class literals, assertions, foreach loops, etc.
@@ -1480,7 +1479,12 @@
* @param owner The class in which the definitions go.
*/
List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner) {
- long flags = FINAL | SYNTHETIC;
+ return freevarDefs(pos, freevars, owner, 0);
+ }
+
+ List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner,
+ long additionalFlags) {
+ long flags = FINAL | SYNTHETIC | additionalFlags;
if (owner.kind == TYP &&
target.usePrivateSyntheticFields())
flags |= PRIVATE;
@@ -1543,7 +1547,7 @@
(owner.isConstructor() && c.isInner() &&
!c.isPrivate() && !c.isStatic());
long flags =
- FINAL | (isMandated ? MANDATED : SYNTHETIC);
+ FINAL | (isMandated ? MANDATED : SYNTHETIC) | PARAMETER;
VarSymbol outerThis = makeOuterThisVarSymbol(owner, flags);
owner.extraParams = owner.extraParams.prepend(outerThis);
return makeOuterThisVarDecl(pos, outerThis);
@@ -1627,7 +1631,8 @@
JCTree makeTwrTry(JCTry tree) {
make_at(tree.pos());
twrVars = twrVars.dup();
- JCBlock twrBlock = makeTwrBlock(tree.resources, tree.body, 0);
+ JCBlock twrBlock = makeTwrBlock(tree.resources, tree.body,
+ tree.finallyCanCompleteNormally, 0);
if (tree.catchers.isEmpty() && tree.finalizer == null)
result = translate(twrBlock);
else
@@ -1636,7 +1641,8 @@
return result;
}
- private JCBlock makeTwrBlock(List<JCTree> resources, JCBlock block, int depth) {
+ private JCBlock makeTwrBlock(List<JCTree> resources, JCBlock block,
+ boolean finallyCanCompleteNormally, int depth) {
if (resources.isEmpty())
return block;
@@ -1692,17 +1698,20 @@
make.at(TreeInfo.endPos(block));
JCBlock finallyClause = makeTwrFinallyClause(primaryException, expr);
make.at(oldPos);
- JCTry outerTry = make.Try(makeTwrBlock(resources.tail, block, depth + 1),
+ JCTry outerTry = make.Try(makeTwrBlock(resources.tail, block,
+ finallyCanCompleteNormally, depth + 1),
List.<JCCatch>of(catchClause),
finallyClause);
+ outerTry.finallyCanCompleteNormally = finallyCanCompleteNormally;
stats.add(outerTry);
- return make.Block(0L, stats.toList());
+ JCBlock newBlock = make.Block(0L, stats.toList());
+ return newBlock;
}
private JCBlock makeTwrFinallyClause(Symbol primaryException, JCExpression resource) {
// primaryException.addSuppressed(catchException);
VarSymbol catchException =
- new VarSymbol(0, make.paramName(2),
+ new VarSymbol(SYNTHETIC, make.paramName(2),
syms.throwableType,
currentMethodSym);
JCStatement addSuppressionStatement =
@@ -1717,6 +1726,7 @@
JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(addSuppressionStatement));
List<JCCatch> catchClauses = List.<JCCatch>of(make.Catch(catchExceptionDecl, catchBlock));
JCTry tryTree = make.Try(tryBlock, catchClauses, null);
+ tryTree.finallyCanCompleteNormally = true;
// if (primaryException != null) {try...} else resourceClose;
JCIf closeIfStatement = make.If(makeNonNullCheck(make.Ident(primaryException)),
@@ -2017,7 +2027,7 @@
// catchParam := ClassNotFoundException e1
VarSymbol catchParam =
- new VarSymbol(0, make.paramName(1),
+ new VarSymbol(SYNTHETIC, make.paramName(1),
syms.classNotFoundExceptionType,
classDollarSym);
@@ -2705,7 +2715,7 @@
JCVariableDecl otdef = null;
if (currentClass.hasOuterInstance())
otdef = outerThisDef(tree.pos, m);
- List<JCVariableDecl> fvdefs = freevarDefs(tree.pos, fvs, m);
+ List<JCVariableDecl> fvdefs = freevarDefs(tree.pos, fvs, m, PARAMETER);
// Recursively translate result type, parameters and thrown list.
tree.restype = translate(tree.restype);
@@ -3364,18 +3374,18 @@
*/
private void visitArrayForeachLoop(JCEnhancedForLoop tree) {
make_at(tree.expr.pos());
- VarSymbol arraycache = new VarSymbol(0,
+ VarSymbol arraycache = new VarSymbol(SYNTHETIC,
names.fromString("arr" + target.syntheticNameChar()),
tree.expr.type,
currentMethodSym);
JCStatement arraycachedef = make.VarDef(arraycache, tree.expr);
- VarSymbol lencache = new VarSymbol(0,
+ VarSymbol lencache = new VarSymbol(SYNTHETIC,
names.fromString("len" + target.syntheticNameChar()),
syms.intType,
currentMethodSym);
JCStatement lencachedef = make.
VarDef(lencache, make.Select(make.Ident(arraycache), syms.lengthVar));
- VarSymbol index = new VarSymbol(0,
+ VarSymbol index = new VarSymbol(SYNTHETIC,
names.fromString("i" + target.syntheticNameChar()),
syms.intType,
currentMethodSym);
@@ -3457,7 +3467,7 @@
names.iterator,
eType,
List.<Type>nil());
- VarSymbol itvar = new VarSymbol(0, names.fromString("i" + target.syntheticNameChar()),
+ VarSymbol itvar = new VarSymbol(SYNTHETIC, names.fromString("i" + target.syntheticNameChar()),
types.erasure(types.asSuper(iterator.type.getReturnType(), syms.iteratorType.tsym)),
currentMethodSym);
@@ -3830,19 +3840,32 @@
@Override
public void visitTry(JCTry tree) {
- /* special case of try without catchers and with finally emtpy.
- * Don't give it a try, translate only the body.
- */
- if (tree.resources.isEmpty()) {
- if (tree.catchers.isEmpty() &&
- tree.finalizer.getStatements().isEmpty()) {
+ if (tree.resources.nonEmpty()) {
+ result = makeTwrTry(tree);
+ return;
+ }
+
+ boolean hasBody = tree.body.getStatements().nonEmpty();
+ boolean hasCatchers = tree.catchers.nonEmpty();
+ boolean hasFinally = tree.finalizer != null &&
+ tree.finalizer.getStatements().nonEmpty();
+
+ if (!hasCatchers && !hasFinally) {
+ result = translate(tree.body);
+ return;
+ }
+
+ if (!hasBody) {
+ if (hasFinally) {
+ result = translate(tree.finalizer);
+ } else {
result = translate(tree.body);
- } else {
- super.visitTry(tree);
}
- } else {
- result = makeTwrTry(tree);
+ return;
}
+
+ // no optimizations possible
+ super.visitTry(tree);
}
/**************************************************************************
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Sat Sep 14 20:43:34 2013 +0100
@@ -84,6 +84,7 @@
private final Source source;
private final Target target;
private final DeferredLintHandler deferredLintHandler;
+ private final Lint lint;
public static MemberEnter instance(Context context) {
MemberEnter instance = context.get(memberEnterKey);
@@ -109,6 +110,7 @@
source = Source.instance(context);
target = Target.instance(context);
deferredLintHandler = DeferredLintHandler.instance(context);
+ lint = Lint.instance(context);
allowTypeAnnos = source.allowTypeAnnotations();
}
@@ -506,9 +508,10 @@
}
// process package annotations
- annotateLater(tree.packageAnnotations, env, tree.packge);
+ annotateLater(tree.packageAnnotations, env, tree.packge, null);
- DeferredLintHandler prevLintHandler = chk.setDeferredLintHandler(DeferredLintHandler.immediateHandler);
+ DiagnosticPosition prevLintPos = deferredLintHandler.immediate();
+ Lint prevLint = chk.setLint(lint);
try {
// Import-on-demand java.lang.
@@ -517,7 +520,8 @@
// Process all import clauses.
memberEnter(tree.defs, env);
} finally {
- chk.setDeferredLintHandler(prevLintHandler);
+ chk.setLint(prevLint);
+ deferredLintHandler.setPos(prevLintPos);
}
}
@@ -564,8 +568,7 @@
Env<AttrContext> localEnv = methodEnv(tree, env);
- DeferredLintHandler prevLintHandler =
- chk.setDeferredLintHandler(deferredLintHandler.setPos(tree.pos()));
+ DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos());
try {
// Compute the method type
m.type = signature(m, tree.typarams, tree.params,
@@ -573,7 +576,7 @@
tree.thrown,
localEnv);
} finally {
- chk.setDeferredLintHandler(prevLintHandler);
+ deferredLintHandler.setPos(prevLintPos);
}
if (types.isSignaturePolymorphic(m)) {
@@ -597,10 +600,10 @@
if (chk.checkUnique(tree.pos(), m, enclScope)) {
enclScope.enter(m);
}
- annotateLater(tree.mods.annotations, localEnv, m);
+ annotateLater(tree.mods.annotations, localEnv, m, tree.pos());
// Visit the signature of the method. Note that
// TypeAnnotate doesn't descend into the body.
- typeAnnotate(tree, localEnv, m);
+ typeAnnotate(tree, localEnv, m, tree.pos());
if (tree.defaultValue != null)
annotateDefaultValueLater(tree.defaultValue, localEnv, m);
@@ -630,15 +633,14 @@
localEnv = env.dup(tree, env.info.dup());
localEnv.info.staticLevel++;
}
- DeferredLintHandler prevLintHandler =
- chk.setDeferredLintHandler(deferredLintHandler.setPos(tree.pos()));
+ DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos());
try {
if (TreeInfo.isEnumInit(tree)) {
attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
} else {
// Make sure type annotations are processed.
// But we don't have a symbol to attach them to yet - use null.
- typeAnnotate(tree.vartype, env, null);
+ typeAnnotate(tree.vartype, env, null, tree.pos());
attr.attribType(tree.vartype, localEnv);
if (tree.nameexpr != null) {
attr.attribExpr(tree.nameexpr, localEnv);
@@ -658,7 +660,7 @@
}
}
} finally {
- chk.setDeferredLintHandler(prevLintHandler);
+ deferredLintHandler.setPos(prevLintPos);
}
if ((tree.mods.flags & VARARGS) != 0) {
@@ -680,15 +682,15 @@
needsLazyConstValue(tree.init)) {
Env<AttrContext> initEnv = getInitEnv(tree, env);
initEnv.info.enclVar = v;
- v.setLazyConstValue(initEnv(tree, initEnv), attr, tree.init);
+ v.setLazyConstValue(initEnv(tree, initEnv), attr, tree);
}
}
if (chk.checkUnique(tree.pos(), v, enclScope)) {
chk.checkTransparentVar(tree.pos(), v, enclScope);
enclScope.enter(v);
}
- annotateLater(tree.mods.annotations, localEnv, v);
- typeAnnotate(tree.vartype, env, v);
+ annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
+ typeAnnotate(tree.vartype, env, v, tree.pos());
annotate.flush();
v.pos = tree.pos;
}
@@ -720,6 +722,11 @@
}
@Override
+ public void visitNewArray(JCNewArray that) {
+ result = false;
+ }
+
+ @Override
public void visitLambda(JCLambda that) {
result = false;
}
@@ -730,6 +737,11 @@
}
@Override
+ public void visitApply(JCMethodInvocation that) {
+ result = false;
+ }
+
+ @Override
public void visitSelect(JCFieldAccess tree) {
tree.selected.accept(this);
}
@@ -820,7 +832,8 @@
/** Queue annotations for later processing. */
void annotateLater(final List<JCAnnotation> annotations,
final Env<AttrContext> localEnv,
- final Symbol s) {
+ final Symbol s,
+ final DiagnosticPosition deferPos) {
if (annotations.isEmpty()) {
return;
}
@@ -837,6 +850,11 @@
public void enterAnnotation() {
Assert.check(s.kind == PCK || s.annotationsPendingCompletion());
JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
+ DiagnosticPosition prevLintPos =
+ deferPos != null
+ ? deferredLintHandler.setPos(deferPos)
+ : deferredLintHandler.immediate();
+ Lint prevLint = deferPos != null ? null : chk.setLint(lint);
try {
if (s.hasAnnotations() &&
annotations.nonEmpty())
@@ -845,6 +863,9 @@
kindName(s), s);
actualEnterAnnotations(annotations, localEnv, s);
} finally {
+ if (prevLint != null)
+ chk.setLint(prevLint);
+ deferredLintHandler.setPos(prevLintPos);
log.useSource(prev);
}
}
@@ -964,6 +985,7 @@
isFirst = false;
JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
+ DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos());
try {
// Save class environment for later member enter (2) processing.
halfcompleted.append(env);
@@ -985,9 +1007,9 @@
Env<AttrContext> baseEnv = baseEnv(tree, env);
if (tree.extending != null)
- typeAnnotate(tree.extending, baseEnv, sym);
+ typeAnnotate(tree.extending, baseEnv, sym, tree.pos());
for (JCExpression impl : tree.implementing)
- typeAnnotate(impl, baseEnv, sym);
+ typeAnnotate(impl, baseEnv, sym, tree.pos());
annotate.flush();
// Determine supertype.
@@ -1048,7 +1070,7 @@
attr.attribAnnotationTypes(tree.mods.annotations, baseEnv);
if (hasDeprecatedAnnotation(tree.mods.annotations))
c.flags_field |= DEPRECATED;
- annotateLater(tree.mods.annotations, baseEnv, c);
+ annotateLater(tree.mods.annotations, baseEnv, c, tree.pos());
// class type parameters use baseEnv but everything uses env
chk.checkNonCyclicDecl(tree);
@@ -1056,7 +1078,7 @@
attr.attribTypeVariables(tree.typarams, baseEnv);
// Do this here, where we have the symbol.
for (JCTypeParameter tp : tree.typarams)
- typeAnnotate(tp, baseEnv, sym);
+ typeAnnotate(tp, baseEnv, sym, tree.pos());
annotate.flush();
// Add default constructor if needed.
@@ -1126,6 +1148,7 @@
} catch (CompletionFailure ex) {
chk.completionError(tree.pos(), ex);
} finally {
+ deferredLintHandler.setPos(prevLintPos);
log.useSource(prev);
}
@@ -1186,9 +1209,9 @@
}
}
- public void typeAnnotate(final JCTree tree, final Env<AttrContext> env, final Symbol sym) {
+ public void typeAnnotate(final JCTree tree, final Env<AttrContext> env, final Symbol sym, DiagnosticPosition deferPos) {
if (allowTypeAnnos) {
- tree.accept(new TypeAnnotate(env, sym));
+ tree.accept(new TypeAnnotate(env, sym, deferPos));
}
}
@@ -1199,10 +1222,12 @@
private class TypeAnnotate extends TreeScanner {
private Env<AttrContext> env;
private Symbol sym;
+ private DiagnosticPosition deferPos;
- public TypeAnnotate(final Env<AttrContext> env, final Symbol sym) {
+ public TypeAnnotate(final Env<AttrContext> env, final Symbol sym, DiagnosticPosition deferPos) {
this.env = env;
this.sym = sym;
+ this.deferPos = deferPos;
}
void annotateTypeLater(final List<JCAnnotation> annotations) {
@@ -1210,6 +1235,8 @@
return;
}
+ final DiagnosticPosition deferPos = this.deferPos;
+
annotate.normal(new Annotate.Annotator() {
@Override
public String toString() {
@@ -1218,9 +1245,16 @@
@Override
public void enterAnnotation() {
JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
+ DiagnosticPosition prevLintPos = null;
+
+ if (deferPos != null) {
+ prevLintPos = deferredLintHandler.setPos(deferPos);
+ }
try {
actualEnterTypeAnnotations(annotations, env, sym);
} finally {
+ if (prevLintPos != null)
+ deferredLintHandler.setPos(prevLintPos);
log.useSource(prev);
}
}
@@ -1262,13 +1296,19 @@
@Override
public void visitVarDef(final JCVariableDecl tree) {
- if (sym != null && sym.kind == Kinds.VAR) {
- // Don't visit a parameter once when the sym is the method
- // and once when the sym is the parameter.
- scan(tree.mods);
- scan(tree.vartype);
+ DiagnosticPosition prevPos = deferPos;
+ deferPos = tree.pos();
+ try {
+ if (sym != null && sym.kind == Kinds.VAR) {
+ // Don't visit a parameter once when the sym is the method
+ // and once when the sym is the parameter.
+ scan(tree.mods);
+ scan(tree.vartype);
+ }
+ scan(tree.init);
+ } finally {
+ deferPos = prevPos;
}
- scan(tree.init);
}
@Override
@@ -1532,7 +1572,7 @@
* parameters from baseInit.
*/
initParams = List.nil();
- VarSymbol param = new VarSymbol(0, make.paramName(0), argtypes.head, init);
+ VarSymbol param = new VarSymbol(PARAMETER, make.paramName(0), argtypes.head, init);
initParams = initParams.append(param);
argTypesList = argTypesList.tail;
}
@@ -1541,7 +1581,7 @@
initParams = (initParams == null) ? List.<VarSymbol>nil() : initParams;
List<VarSymbol> baseInitParams = baseInit.params;
while (baseInitParams.nonEmpty() && argTypesList.nonEmpty()) {
- VarSymbol param = new VarSymbol(baseInitParams.head.flags(),
+ VarSymbol param = new VarSymbol(baseInitParams.head.flags() | PARAMETER,
baseInitParams.head.name, argTypesList.head, init);
initParams = initParams.append(param);
baseInitParams = baseInitParams.tail;
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Sat Sep 14 20:43:34 2013 +0100
@@ -568,8 +568,10 @@
currentResolutionContext,
warn);
- currentResolutionContext.methodCheck.argumentsAcceptable(env, currentResolutionContext.deferredAttrContext(m, infer.emptyContext, resultInfo, warn),
+ DeferredAttr.DeferredAttrContext dc = currentResolutionContext.deferredAttrContext(m, infer.emptyContext, resultInfo, warn);
+ currentResolutionContext.methodCheck.argumentsAcceptable(env, dc,
argtypes, mt.getParameterTypes(), warn);
+ dc.complete();
return mt;
}
@@ -1053,7 +1055,8 @@
DeferredType dt = (DeferredType) actual;
DeferredType.SpeculativeCache.Entry e = dt.speculativeCache.get(deferredAttrContext.msym, deferredAttrContext.phase);
return (e == null || e.speculativeTree == deferredAttr.stuckTree)
- ? false : mostSpecific(found, req, e.speculativeTree, warn);
+ ? super.compatible(found, req, warn) :
+ mostSpecific(found, req, e.speculativeTree, warn);
default:
return standaloneMostSpecific(found, req, actual, warn);
}
@@ -1125,13 +1128,15 @@
@Override
public void visitReference(JCMemberReference tree) {
if (types.isFunctionalInterface(t.tsym) &&
- types.isFunctionalInterface(s.tsym) &&
- types.asSuper(t, s.tsym) == null &&
- types.asSuper(s, t.tsym) == null) {
+ types.isFunctionalInterface(s.tsym)) {
Type desc_t = types.findDescriptorType(t);
Type desc_s = types.findDescriptorType(s);
- if (types.isSameTypes(desc_t.getParameterTypes(), desc_s.getParameterTypes())) {
- if (!desc_s.getReturnType().hasTag(VOID)) {
+ if (types.isSameTypes(desc_t.getParameterTypes(),
+ inferenceContext().asFree(desc_s.getParameterTypes()))) {
+ if (types.asSuper(t, s.tsym) != null ||
+ types.asSuper(s, t.tsym) != null) {
+ result &= MostSpecificCheckContext.super.compatible(t, s, warn);
+ } else if (!desc_s.getReturnType().hasTag(VOID)) {
//perform structural comparison
Type ret_t = desc_t.getReturnType();
Type ret_s = desc_s.getReturnType();
@@ -1141,25 +1146,24 @@
} else {
return;
}
- } else {
- result &= false;
}
} else {
- result &= MostSpecificCheckContext.super.compatible(t, s, warn);
+ result &= false;
}
}
@Override
public void visitLambda(JCLambda tree) {
if (types.isFunctionalInterface(t.tsym) &&
- types.isFunctionalInterface(s.tsym) &&
- types.asSuper(t, s.tsym) == null &&
- types.asSuper(s, t.tsym) == null) {
+ types.isFunctionalInterface(s.tsym)) {
Type desc_t = types.findDescriptorType(t);
Type desc_s = types.findDescriptorType(s);
- if (tree.paramKind == JCLambda.ParameterKind.EXPLICIT
- || types.isSameTypes(desc_t.getParameterTypes(), desc_s.getParameterTypes())) {
- if (!desc_s.getReturnType().hasTag(VOID)) {
+ if (types.isSameTypes(desc_t.getParameterTypes(),
+ inferenceContext().asFree(desc_s.getParameterTypes()))) {
+ if (types.asSuper(t, s.tsym) != null ||
+ types.asSuper(s, t.tsym) != null) {
+ result &= MostSpecificCheckContext.super.compatible(t, s, warn);
+ } else if (!desc_s.getReturnType().hasTag(VOID)) {
//perform structural comparison
Type ret_t = desc_t.getReturnType();
Type ret_s = desc_s.getReturnType();
@@ -1167,11 +1171,9 @@
} else {
return;
}
- } else {
- result &= false;
}
} else {
- result &= MostSpecificCheckContext.super.compatible(t, s, warn);
+ result &= false;
}
}
//where
@@ -1521,7 +1523,8 @@
currentResolutionContext = prevResolutionContext;
}
}
- private List<Type> adjustArgs(List<Type> args, Symbol msym, int length, boolean allowVarargs) {
+
+ List<Type> adjustArgs(List<Type> args, Symbol msym, int length, boolean allowVarargs) {
if ((msym.flags() & VARARGS) != 0 && allowVarargs) {
Type varargsElem = types.elemtype(args.last());
if (varargsElem == null) {
@@ -2241,33 +2244,33 @@
public List<Type> getArgumentTypes(ResolveError errSym, Symbol accessedSym, Name name, List<Type> argtypes) {
return (syms.operatorNames.contains(name)) ?
argtypes :
- Type.map(argtypes, new ResolveDeferredRecoveryMap(accessedSym));
- }
-
- class ResolveDeferredRecoveryMap extends DeferredAttr.RecoveryDeferredTypeMap {
-
- public ResolveDeferredRecoveryMap(Symbol msym) {
- deferredAttr.super(AttrMode.SPECULATIVE, msym, currentResolutionContext.step);
- }
-
- @Override
- protected Type typeOf(DeferredType dt) {
- Type res = super.typeOf(dt);
- if (!res.isErroneous()) {
- switch (TreeInfo.skipParens(dt.tree).getTag()) {
- case LAMBDA:
- case REFERENCE:
- return dt;
- case CONDEXPR:
- return res == Type.recoveryType ?
- dt : res;
- }
- }
- return res;
- }
+ Type.map(argtypes, new ResolveDeferredRecoveryMap(AttrMode.SPECULATIVE, accessedSym, currentResolutionContext.step));
}
};
+ class ResolveDeferredRecoveryMap extends DeferredAttr.RecoveryDeferredTypeMap {
+
+ public ResolveDeferredRecoveryMap(AttrMode mode, Symbol msym, MethodResolutionPhase step) {
+ deferredAttr.super(mode, msym, step);
+ }
+
+ @Override
+ protected Type typeOf(DeferredType dt) {
+ Type res = super.typeOf(dt);
+ if (!res.isErroneous()) {
+ switch (TreeInfo.skipParens(dt.tree).getTag()) {
+ case LAMBDA:
+ case REFERENCE:
+ return dt;
+ case CONDEXPR:
+ return res == Type.recoveryType ?
+ dt : res;
+ }
+ }
+ return res;
+ }
+ }
+
/** Check that sym is not an abstract method.
*/
void checkNonAbstract(DiagnosticPosition pos, Symbol sym) {
@@ -2543,22 +2546,26 @@
@Override
Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
if (sym.kind >= AMBIGUOUS) {
- final JCDiagnostic details = sym.kind == WRONG_MTH ?
- ((InapplicableSymbolError)sym).errCandidate().snd :
- null;
- sym = new InapplicableSymbolError(sym.kind, "diamondError", currentResolutionContext) {
- @Override
- JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos,
- Symbol location, Type site, Name name, List<Type> argtypes, List<Type> typeargtypes) {
- String key = details == null ?
- "cant.apply.diamond" :
- "cant.apply.diamond.1";
- return diags.create(dkind, log.currentSource(), pos, key,
- diags.fragment("diamond", site.tsym), details);
- }
- };
- sym = accessMethod(sym, pos, site, names.init, true, argtypes, typeargtypes);
- env.info.pendingResolutionPhase = currentResolutionContext.step;
+ if (sym.kind != WRONG_MTH && sym.kind != WRONG_MTHS) {
+ sym = super.access(env, pos, location, sym);
+ } else {
+ final JCDiagnostic details = sym.kind == WRONG_MTH ?
+ ((InapplicableSymbolError)sym).errCandidate().snd :
+ null;
+ sym = new InapplicableSymbolError(sym.kind, "diamondError", currentResolutionContext) {
+ @Override
+ JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos,
+ Symbol location, Type site, Name name, List<Type> argtypes, List<Type> typeargtypes) {
+ String key = details == null ?
+ "cant.apply.diamond" :
+ "cant.apply.diamond.1";
+ return diags.create(dkind, log.currentSource(), pos, key,
+ diags.fragment("diamond", site.tsym), details);
+ }
+ };
+ sym = accessMethod(sym, pos, site, names.init, true, argtypes, typeargtypes);
+ env.info.pendingResolutionPhase = currentResolutionContext.step;
+ }
}
return sym;
}});
@@ -3969,16 +3976,6 @@
static {
String argMismatchRegex = MethodCheckDiag.ARG_MISMATCH.regex();
- rewriters.put(new Template(argMismatchRegex, new Template("(.*)(bad.arg.types.in.lambda)", skip, skip)),
- new DiagnosticRewriter() {
- @Override
- public JCDiagnostic rewriteDiagnostic(JCDiagnostic.Factory diags,
- DiagnosticPosition preferedPos, DiagnosticSource preferredSource,
- DiagnosticType preferredKind, JCDiagnostic d) {
- return (JCDiagnostic)((JCDiagnostic)d.getArgs()[0]).getArgs()[1];
- }
- });
-
rewriters.put(new Template(argMismatchRegex, skip),
new DiagnosticRewriter() {
@Override
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Sat Sep 14 20:43:34 2013 +0100
@@ -310,7 +310,7 @@
Type.MethodType mType = (Type.MethodType)bridgeType;
List<Type> argTypes = mType.argtypes;
while (implParams.nonEmpty() && argTypes.nonEmpty()) {
- VarSymbol param = new VarSymbol(implParams.head.flags() | SYNTHETIC,
+ VarSymbol param = new VarSymbol(implParams.head.flags() | SYNTHETIC | PARAMETER,
implParams.head.name, argTypes.head, bridge);
param.setAttributes(implParams.head);
bridgeParams = bridgeParams.append(param);
@@ -833,7 +833,7 @@
}
public void visitReference(JCMemberReference tree) {
- tree.expr = translate(tree.expr, null);
+ tree.expr = translate(tree.expr, erasure(tree.expr.type));
tree.type = erasure(tree.type);
result = tree;
}
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Sat Sep 14 20:43:34 2013 +0100
@@ -72,7 +72,7 @@
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
-public class ClassReader implements Completer {
+public class ClassReader {
/** The context key for the class reader. */
protected static final Context.Key<ClassReader> classReaderKey =
new Context.Key<ClassReader>();
@@ -234,6 +234,17 @@
*/
Set<Name> warnedAttrs = new HashSet<Name>();
+ /**
+ * Completer that delegates to the complete-method of this class.
+ */
+ private final Completer thisCompleter = new Completer() {
+ @Override
+ public void complete(Symbol sym) throws CompletionFailure {
+ ClassReader.this.complete(sym);
+ }
+ };
+
+
/** Get the ClassReader instance for this invocation. */
public static ClassReader instance(Context context) {
ClassReader instance = context.get(classReaderKey);
@@ -264,8 +275,8 @@
}
packages.put(names.empty, syms.rootPackage);
- syms.rootPackage.completer = this;
- syms.unnamedPackage.completer = this;
+ syms.rootPackage.completer = thisCompleter;
+ syms.unnamedPackage.completer = thisCompleter;
}
/** Construct a new class reader, optionally treated as the
@@ -727,12 +738,14 @@
ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
startSbp,
sbp - startSbp));
- if (outer == Type.noType)
- outer = t.erasure(types);
- else
- outer = new ClassType(outer, List.<Type>nil(), t);
- sbp = startSbp;
- return outer;
+
+ try {
+ return (outer == Type.noType) ?
+ t.erasure(types) :
+ new ClassType(outer, List.<Type>nil(), t);
+ } finally {
+ sbp = startSbp;
+ }
}
case '<': // generic arguments
@@ -797,6 +810,13 @@
continue;
case '.':
+ //we have seen an enclosing non-generic class
+ if (outer != Type.noType) {
+ t = enterClass(names.fromUtf(signatureBuffer,
+ startSbp,
+ sbp - startSbp));
+ outer = new ClassType(outer, List.<Type>nil(), t);
+ }
signatureBuffer[sbp++] = (byte)'$';
continue;
case '/':
@@ -2310,7 +2330,7 @@
ClassSymbol c = new ClassSymbol(0, name, owner);
if (owner.kind == PCK)
Assert.checkNull(classes.get(c.flatname), c);
- c.completer = this;
+ c.completer = thisCompleter;
return c;
}
@@ -2380,7 +2400,7 @@
/** Completion for classes to be loaded. Before a class is loaded
* we make sure its enclosing class (if any) is loaded.
*/
- public void complete(Symbol sym) throws CompletionFailure {
+ private void complete(Symbol sym) throws CompletionFailure {
if (sym.kind == TYP) {
ClassSymbol c = (ClassSymbol)sym;
c.members_field = new Scope.ErrorScope(c); // make sure it's always defined
@@ -2601,7 +2621,7 @@
p = new PackageSymbol(
Convert.shortName(fullname),
enterPackage(Convert.packagePart(fullname)));
- p.completer = this;
+ p.completer = thisCompleter;
packages.put(fullname, p);
}
return p;
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Sat Sep 14 20:43:34 2013 +0100
@@ -37,7 +37,6 @@
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Attribute.RetentionPolicy;
-import com.sun.tools.javac.code.Attribute.TypeCompound;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.code.Types.UniqueType;
@@ -55,7 +54,6 @@
import static com.sun.tools.javac.main.Option.*;
import static javax.tools.StandardLocation.CLASS_OUTPUT;
-
/** This class provides operations to map an internal symbol table graph
* rooted in a ClassSymbol into a classfile.
*
@@ -1180,25 +1178,26 @@
if (code.varBufferSize > 0) {
int alenIdx = writeAttr(names.LocalVariableTable);
- databuf.appendChar(code.varBufferSize);
-
+ databuf.appendChar(code.getLVTSize());
for (int i=0; i<code.varBufferSize; i++) {
Code.LocalVar var = code.varBuffer[i];
- // write variable info
- Assert.check(var.start_pc >= 0
- && var.start_pc <= code.cp);
- databuf.appendChar(var.start_pc);
- Assert.check(var.length >= 0
- && (var.start_pc + var.length) <= code.cp);
- databuf.appendChar(var.length);
- VarSymbol sym = var.sym;
- databuf.appendChar(pool.put(sym.name));
- Type vartype = sym.erasure(types);
- if (needsLocalVariableTypeEntry(sym.type))
- nGenericVars++;
- databuf.appendChar(pool.put(typeSig(vartype)));
- databuf.appendChar(var.reg);
+ for (Code.LocalVar.Range r: var.aliveRanges) {
+ // write variable info
+ Assert.check(r.start_pc >= 0
+ && r.start_pc <= code.cp);
+ databuf.appendChar(r.start_pc);
+ Assert.check(r.length >= 0
+ && (r.start_pc + r.length) <= code.cp);
+ databuf.appendChar(r.length);
+ VarSymbol sym = var.sym;
+ databuf.appendChar(pool.put(sym.name));
+ Type vartype = sym.erasure(types);
+ databuf.appendChar(pool.put(typeSig(vartype)));
+ databuf.appendChar(var.reg);
+ if (needsLocalVariableTypeEntry(var.sym.type))
+ nGenericVars++;
+ }
}
endAttr(alenIdx);
acount++;
@@ -1214,13 +1213,15 @@
VarSymbol sym = var.sym;
if (!needsLocalVariableTypeEntry(sym.type))
continue;
- count++;
- // write variable info
- databuf.appendChar(var.start_pc);
- databuf.appendChar(var.length);
- databuf.appendChar(pool.put(sym.name));
- databuf.appendChar(pool.put(typeSig(sym.type)));
- databuf.appendChar(var.reg);
+ for (Code.LocalVar.Range r : var.aliveRanges) {
+ // write variable info
+ databuf.appendChar(r.start_pc);
+ databuf.appendChar(r.length);
+ databuf.appendChar(pool.put(sym.name));
+ databuf.appendChar(pool.put(typeSig(sym.type)));
+ databuf.appendChar(var.reg);
+ count++;
+ }
}
Assert.check(count == nGenericVars);
endAttr(alenIdx);
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java Sat Sep 14 20:43:34 2013 +0100
@@ -28,6 +28,7 @@
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Types.UniqueType;
+import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@@ -181,6 +182,8 @@
final MethodSymbol meth;
+ final LVTRanges lvtRanges;
+
/** Construct a code object, given the settings of the fatcode,
* debugging info switches and the CharacterRangeTable.
*/
@@ -193,7 +196,8 @@
CRTable crt,
Symtab syms,
Types types,
- Pool pool) {
+ Pool pool,
+ LVTRanges lvtRanges) {
this.meth = meth;
this.fatcode = fatcode;
this.lineMap = lineMap;
@@ -215,6 +219,7 @@
state = new State();
lvar = new LocalVar[20];
this.pool = pool;
+ this.lvtRanges = lvtRanges;
}
@@ -305,9 +310,19 @@
/** The current output code pointer.
*/
- public int curPc() {
- if (pendingJumps != null) resolvePending();
- if (pendingStatPos != Position.NOPOS) markStatBegin();
+ public int curCP() {
+ /*
+ * This method has side-effects because calling it can indirectly provoke
+ * extra code generation, like goto instructions, depending on the context
+ * where it's called.
+ * Use with care or even better avoid using it.
+ */
+ if (pendingJumps != null) {
+ resolvePending();
+ }
+ if (pendingStatPos != Position.NOPOS) {
+ markStatBegin();
+ }
fixedPc = true;
return cp;
}
@@ -1175,7 +1190,7 @@
/** Declare an entry point; return current code pointer
*/
public int entryPoint() {
- int pc = curPc();
+ int pc = curCP();
alive = true;
pendingStackMap = needStackMap;
return pc;
@@ -1185,7 +1200,7 @@
* return current code pointer
*/
public int entryPoint(State state) {
- int pc = curPc();
+ int pc = curCP();
alive = true;
this.state = state.dup();
Assert.check(state.stacksize <= max_stack);
@@ -1198,7 +1213,7 @@
* return current code pointer
*/
public int entryPoint(State state, Type pushed) {
- int pc = curPc();
+ int pc = curCP();
alive = true;
this.state = state.dup();
Assert.check(state.stacksize <= max_stack);
@@ -1238,7 +1253,7 @@
/** Emit a stack map entry. */
public void emitStackMap() {
- int pc = curPc();
+ int pc = curCP();
if (!needStackMap) return;
@@ -1482,6 +1497,9 @@
chain.pc + 3 == target && target == cp && !fixedPc) {
// If goto the next instruction, the jump is not needed:
// compact the code.
+ if (varDebugInfo) {
+ adjustAliveRanges(cp, -3);
+ }
cp = cp - 3;
target = target - 3;
if (chain.next == null) {
@@ -1781,8 +1799,7 @@
sym = sym.clone(sym.owner);
sym.type = newtype;
LocalVar newlv = lvar[i] = new LocalVar(sym);
- // should the following be initialized to cp?
- newlv.start_pc = lv.start_pc;
+ newlv.aliveRanges = lv.aliveRanges;
}
}
}
@@ -1870,8 +1887,36 @@
static class LocalVar {
final VarSymbol sym;
final char reg;
- char start_pc = Character.MAX_VALUE;
- char length = Character.MAX_VALUE;
+
+ class Range {
+ char start_pc = Character.MAX_VALUE;
+ char length = Character.MAX_VALUE;
+
+ Range() {}
+
+ Range(char start) {
+ this.start_pc = start;
+ }
+
+ Range(char start, char length) {
+ this.start_pc = start;
+ this.length = length;
+ }
+
+ boolean closed() {
+ return start_pc != Character.MAX_VALUE && length != Character.MAX_VALUE;
+ }
+
+ @Override
+ public String toString() {
+ int currentStartPC = start_pc;
+ int currentLength = length;
+ return "startpc = " + currentStartPC + " length " + currentLength;
+ }
+ }
+
+ java.util.List<Range> aliveRanges = new java.util.ArrayList<>();
+
LocalVar(VarSymbol v) {
this.sym = v;
this.reg = (char)v.adr;
@@ -1879,9 +1924,78 @@
public LocalVar dup() {
return new LocalVar(sym);
}
+
+ Range firstRange() {
+ return aliveRanges.isEmpty() ? null : aliveRanges.get(0);
+ }
+
+ Range lastRange() {
+ return aliveRanges.isEmpty() ? null : aliveRanges.get(aliveRanges.size() - 1);
+ }
+
+ @Override
public String toString() {
- return "" + sym + " in register " + ((int)reg) + " starts at pc=" + ((int)start_pc) + " length=" + ((int)length);
+ if (aliveRanges == null) {
+ return "empty local var";
+ }
+ StringBuilder sb = new StringBuilder().append(sym)
+ .append(" in register ").append((int)reg).append(" \n");
+ for (Range r : aliveRanges) {
+ sb.append(" starts at pc=").append(Integer.toString(((int)r.start_pc)))
+ .append(" length=").append(Integer.toString(((int)r.length)))
+ .append("\n");
+ }
+ return sb.toString();
+ }
+
+ public void openRange(char start) {
+ if (!hasOpenRange()) {
+ aliveRanges.add(new Range(start));
+ }
}
+
+ public void closeRange(char end) {
+ if (isLastRangeInitialized()) {
+ Range range = lastRange();
+ if (range != null) {
+ if (range.length == Character.MAX_VALUE) {
+ range.length = end;
+ }
+ }
+ } else {
+ if (!aliveRanges.isEmpty()) {
+ aliveRanges.remove(aliveRanges.size() - 1);
+ }
+ }
+ }
+
+ public boolean hasOpenRange() {
+ if (aliveRanges.isEmpty()) {
+ return false;
+ }
+ Range range = lastRange();
+ return range.length == Character.MAX_VALUE;
+ }
+
+ public boolean isLastRangeInitialized() {
+ if (aliveRanges.isEmpty()) {
+ return false;
+ }
+ Range range = lastRange();
+ return range.start_pc != Character.MAX_VALUE;
+ }
+
+ public Range getWidestRange() {
+ if (aliveRanges.isEmpty()) {
+ return new Range();
+ } else {
+ Range firstRange = firstRange();
+ Range lastRange = lastRange();
+ char length = (char)(lastRange.length + (lastRange.start_pc - firstRange.start_pc));
+ return new Range(firstRange.start_pc, length);
+ }
+ }
+
};
/** Local variables, indexed by register. */
@@ -1892,11 +2006,60 @@
int adr = v.adr;
lvar = ArrayUtils.ensureCapacity(lvar, adr+1);
Assert.checkNull(lvar[adr]);
- if (pendingJumps != null) resolvePending();
+ if (pendingJumps != null) {
+ resolvePending();
+ }
lvar[adr] = new LocalVar(v);
state.defined.excl(adr);
}
+
+ public void closeAliveRanges(JCTree tree) {
+ closeAliveRanges(tree, cp);
+ }
+
+ public void closeAliveRanges(JCTree tree, int closingCP) {
+ List<VarSymbol> locals = lvtRanges.getVars(meth, tree);
+ for (LocalVar localVar: lvar) {
+ for (VarSymbol aliveLocal : locals) {
+ if (localVar == null) {
+ return;
+ }
+ if (localVar.sym == aliveLocal && localVar.lastRange() != null) {
+ char length = (char)(closingCP - localVar.lastRange().start_pc);
+ if (length > 0 && length < Character.MAX_VALUE) {
+ localVar.closeRange(length);
+ }
+ }
+ }
+ }
+ }
+
+ void adjustAliveRanges(int oldCP, int delta) {
+ for (LocalVar localVar: lvar) {
+ if (localVar == null) {
+ return;
+ }
+ for (LocalVar.Range range: localVar.aliveRanges) {
+ if (range.closed() && range.start_pc + range.length >= oldCP) {
+ range.length += delta;
+ }
+ }
+ }
+ }
+
+ /**
+ * Calculates the size of the LocalVariableTable.
+ */
+ public int getLVTSize() {
+ int result = varBufferSize;
+ for (int i = 0; i < varBufferSize; i++) {
+ LocalVar var = varBuffer[i];
+ result += var.aliveRanges.size() - 1;
+ }
+ return result;
+ }
+
/** Set the current variable defined state. */
public void setDefined(Bits newDefined) {
if (alive && newDefined != state.defined) {
@@ -1922,8 +2085,7 @@
} else {
state.defined.incl(adr);
if (cp < Character.MAX_VALUE) {
- if (v.start_pc == Character.MAX_VALUE)
- v.start_pc = (char)cp;
+ v.openRange((char)cp);
}
}
}
@@ -1933,15 +2095,15 @@
state.defined.excl(adr);
if (adr < lvar.length &&
lvar[adr] != null &&
- lvar[adr].start_pc != Character.MAX_VALUE) {
+ lvar[adr].isLastRangeInitialized()) {
LocalVar v = lvar[adr];
- char length = (char)(curPc() - v.start_pc);
+ char length = (char)(curCP() - v.lastRange().start_pc);
if (length > 0 && length < Character.MAX_VALUE) {
lvar[adr] = v.dup();
- v.length = length;
+ v.closeRange(length);
putVar(v);
} else {
- v.start_pc = Character.MAX_VALUE;
+ v.lastRange().start_pc = Character.MAX_VALUE;
}
}
}
@@ -1951,10 +2113,10 @@
LocalVar v = lvar[adr];
if (v != null) {
lvar[adr] = null;
- if (v.start_pc != Character.MAX_VALUE) {
- char length = (char)(curPc() - v.start_pc);
+ if (v.isLastRangeInitialized()) {
+ char length = (char)(curCP() - v.lastRange().start_pc);
if (length < Character.MAX_VALUE) {
- v.length = length;
+ v.closeRange(length);
putVar(v);
fillLocalVarPosition(v);
}
@@ -1968,8 +2130,9 @@
return;
for (Attribute.TypeCompound ta : lv.sym.getRawTypeAttributes()) {
TypeAnnotationPosition p = ta.position;
- p.lvarOffset = new int[] { (int)lv.start_pc };
- p.lvarLength = new int[] { (int)lv.length };
+ LocalVar.Range widestRange = lv.getWidestRange();
+ p.lvarOffset = new int[] { (int)widestRange.start_pc };
+ p.lvarLength = new int[] { (int)widestRange.length };
p.lvarIndex = new int[] { (int)lv.reg };
p.isValidOffset = true;
}
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java Sat Sep 14 20:43:34 2013 +0100
@@ -24,6 +24,7 @@
*/
package com.sun.tools.javac.jvm;
+
import java.util.*;
import com.sun.tools.javac.util.*;
@@ -95,10 +96,14 @@
return instance;
}
- /* Constant pool, reset by genClass.
+ /** Constant pool, reset by genClass.
*/
private Pool pool;
+ /** LVTRanges info.
+ */
+ private LVTRanges lvtRanges;
+
protected Gen(Context context) {
context.put(genKey, this);
@@ -128,6 +133,9 @@
options.isUnset(G_CUSTOM)
? options.isSet(G)
: options.isSet(G_CUSTOM, "vars");
+ if (varDebugInfo) {
+ lvtRanges = LVTRanges.instance(context);
+ }
genCrt = options.isSet(XJCOV);
debugCode = options.isSet("debugcode");
allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic");
@@ -423,7 +431,7 @@
*/
void endFinalizerGap(Env<GenContext> env) {
if (env.info.gaps != null && env.info.gaps.length() % 2 == 1)
- env.info.gaps.append(code.curPc());
+ env.info.gaps.append(code.curCP());
}
/** Mark end of all gaps in catch-all ranges for finalizers of environments
@@ -743,10 +751,10 @@
genStat(tree, env);
return;
}
- int startpc = code.curPc();
+ int startpc = code.curCP();
genStat(tree, env);
if (tree.hasTag(Tag.BLOCK)) crtFlags |= CRT_BLOCK;
- code.crt.put(tree, crtFlags, startpc, code.curPc());
+ code.crt.put(tree, crtFlags, startpc, code.curCP());
}
/** Derived visitor method: generate code for a statement.
@@ -781,9 +789,9 @@
if (trees.length() == 1) { // mark one statement with the flags
genStat(trees.head, env, crtFlags | CRT_STATEMENT);
} else {
- int startpc = code.curPc();
+ int startpc = code.curCP();
genStats(trees, env);
- code.crt.put(trees, crtFlags, startpc, code.curPc());
+ code.crt.put(trees, crtFlags, startpc, code.curCP());
}
}
@@ -806,9 +814,9 @@
*/
public CondItem genCond(JCTree tree, int crtFlags) {
if (!genCrt) return genCond(tree, false);
- int startpc = code.curPc();
+ int startpc = code.curCP();
CondItem item = genCond(tree, (crtFlags & CRT_FLOW_CONTROLLER) != 0);
- code.crt.put(tree, crtFlags, startpc, code.curPc());
+ code.crt.put(tree, crtFlags, startpc, code.curCP());
return item;
}
@@ -971,7 +979,6 @@
// definition.
Env<GenContext> localEnv = env.dup(tree);
localEnv.enclMethod = tree;
-
// The expected type of every return statement in this method
// is the method's return type.
this.pt = tree.sym.erasure(types).getReturnType();
@@ -1045,7 +1052,7 @@
code.crt.put(tree.body,
CRT_BLOCK,
startpcCrt,
- code.curPc());
+ code.curCP());
code.endScopes(0);
@@ -1087,10 +1094,12 @@
: null,
syms,
types,
- pool);
+ pool,
+ varDebugInfo ? lvtRanges : null);
items = new Items(pool, code, syms, types);
- if (code.debugCode)
+ if (code.debugCode) {
System.err.println(meth + " for body " + tree);
+ }
// If method is not static, create a new local variable address
// for `this'.
@@ -1111,7 +1120,7 @@
}
// Get ready to generate code for method body.
- int startpcCrt = genCrt ? code.curPc() : 0;
+ int startpcCrt = genCrt ? code.curCP() : 0;
code.entryPoint();
// Suppress initial stackmap
@@ -1189,14 +1198,30 @@
Chain loopDone = c.jumpFalse();
code.resolve(c.trueJumps);
genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
+ if (varDebugInfo) {
+ checkLoopLocalVarRangeEnding(loop, body,
+ LoopLocalVarRangeEndingPoint.BEFORE_STEPS);
+ }
code.resolve(loopEnv.info.cont);
genStats(step, loopEnv);
+ if (varDebugInfo) {
+ checkLoopLocalVarRangeEnding(loop, body,
+ LoopLocalVarRangeEndingPoint.AFTER_STEPS);
+ }
code.resolve(code.branch(goto_), startpc);
code.resolve(loopDone);
} else {
genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
+ if (varDebugInfo) {
+ checkLoopLocalVarRangeEnding(loop, body,
+ LoopLocalVarRangeEndingPoint.BEFORE_STEPS);
+ }
code.resolve(loopEnv.info.cont);
genStats(step, loopEnv);
+ if (varDebugInfo) {
+ checkLoopLocalVarRangeEnding(loop, body,
+ LoopLocalVarRangeEndingPoint.AFTER_STEPS);
+ }
CondItem c;
if (cond != null) {
code.statBegin(cond.pos);
@@ -1210,6 +1235,44 @@
code.resolve(loopEnv.info.exit);
}
+ private enum LoopLocalVarRangeEndingPoint {
+ BEFORE_STEPS,
+ AFTER_STEPS,
+ }
+
+ /**
+ * Checks whether we have reached an alive range ending point for local
+ * variables after a loop.
+ *
+ * Local variables alive range ending point for loops varies depending
+ * on the loop type. The range can be closed before or after the code
+ * for the steps sentences has been generated.
+ *
+ * - While loops has no steps so in that case the range is closed just
+ * after the body of the loop.
+ *
+ * - For-like loops may have steps so as long as the steps sentences
+ * can possibly contain non-synthetic local variables, the alive range
+ * for local variables must be closed after the steps in this case.
+ */
+ private void checkLoopLocalVarRangeEnding(JCTree loop, JCTree body,
+ LoopLocalVarRangeEndingPoint endingPoint) {
+ if (varDebugInfo && lvtRanges.containsKey(code.meth, body)) {
+ switch (endingPoint) {
+ case BEFORE_STEPS:
+ if (!loop.hasTag(FORLOOP)) {
+ code.closeAliveRanges(body);
+ }
+ break;
+ case AFTER_STEPS:
+ if (loop.hasTag(FORLOOP)) {
+ code.closeAliveRanges(body);
+ }
+ break;
+ }
+ }
+ }
+
public void visitForeachLoop(JCEnhancedForLoop tree) {
throw new AssertionError(); // should have been removed by Lower.
}
@@ -1223,7 +1286,7 @@
public void visitSwitch(JCSwitch tree) {
int limit = code.nextreg;
Assert.check(!tree.selector.type.hasTag(CLASS));
- int startpcCrt = genCrt ? code.curPc() : 0;
+ int startpcCrt = genCrt ? code.curCP() : 0;
Item sel = genExpr(tree.selector, syms.intType);
List<JCCase> cases = tree.cases;
if (cases.isEmpty()) {
@@ -1231,13 +1294,13 @@
sel.load().drop();
if (genCrt)
code.crt.put(TreeInfo.skipParens(tree.selector),
- CRT_FLOW_CONTROLLER, startpcCrt, code.curPc());
+ CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
} else {
// We are seeing a nonempty switch.
sel.load();
if (genCrt)
code.crt.put(TreeInfo.skipParens(tree.selector),
- CRT_FLOW_CONTROLLER, startpcCrt, code.curPc());
+ CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
Env<GenContext> switchEnv = env.dup(tree, new GenContext());
switchEnv.info.isSwitch = true;
@@ -1278,10 +1341,10 @@
?
tableswitch : lookupswitch;
- int startpc = code.curPc(); // the position of the selector operation
+ int startpc = code.curCP(); // the position of the selector operation
code.emitop0(opcode);
code.align(4);
- int tableBase = code.curPc(); // the start of the jump table
+ int tableBase = code.curCP(); // the start of the jump table
int[] offsets = null; // a table of offsets for a lookupswitch
code.emit4(-1); // leave space for default offset
if (opcode == tableswitch) {
@@ -1323,6 +1386,9 @@
// Generate code for the statements in this case.
genStats(c.stats, switchEnv, CRT_FLOW_TARGET);
+ if (varDebugInfo && lvtRanges.containsKey(code.meth, c.stats.last())) {
+ code.closeAliveRanges(c.stats.last());
+ }
}
// Resolve all breaks.
@@ -1402,7 +1468,7 @@
void gen() {
genLast();
Assert.check(syncEnv.info.gaps.length() % 2 == 0);
- syncEnv.info.gaps.append(code.curPc());
+ syncEnv.info.gaps.append(code.curCP());
}
void genLast() {
if (code.isAlive()) {
@@ -1441,10 +1507,10 @@
jsrState);
}
Assert.check(tryEnv.info.gaps.length() % 2 == 0);
- tryEnv.info.gaps.append(code.curPc());
+ tryEnv.info.gaps.append(code.curCP());
} else {
Assert.check(tryEnv.info.gaps.length() % 2 == 0);
- tryEnv.info.gaps.append(code.curPc());
+ tryEnv.info.gaps.append(code.curCP());
genLast();
}
}
@@ -1467,10 +1533,10 @@
*/
void genTry(JCTree body, List<JCCatch> catchers, Env<GenContext> env) {
int limit = code.nextreg;
- int startpc = code.curPc();
+ int startpc = code.curCP();
Code.State stateTry = code.state.dup();
genStat(body, env, CRT_BLOCK);
- int endpc = code.curPc();
+ int endpc = code.curCP();
boolean hasFinalizer =
env.info.finalize != null &&
env.info.finalize.hasFinalizer();
@@ -1478,82 +1544,77 @@
code.statBegin(TreeInfo.endPos(body));
genFinalizer(env);
code.statBegin(TreeInfo.endPos(env.tree));
- Chain exitChain;
- if (startpc != endpc) {
- exitChain = code.branch(goto_);
- } else {
- exitChain = code.branch(dontgoto);
+ Chain exitChain = code.branch(goto_);
+ if (varDebugInfo && lvtRanges.containsKey(code.meth, body)) {
+ code.closeAliveRanges(body);
}
endFinalizerGap(env);
- if (startpc != endpc) {
- for (List<JCCatch> l = catchers; l.nonEmpty(); l = l.tail) {
- // start off with exception on stack
- code.entryPoint(stateTry, l.head.param.sym.type);
- genCatch(l.head, env, startpc, endpc, gaps);
- genFinalizer(env);
- if (hasFinalizer || l.tail.nonEmpty()) {
- code.statBegin(TreeInfo.endPos(env.tree));
- exitChain = Code.mergeChains(exitChain,
- code.branch(goto_));
- }
- endFinalizerGap(env);
+ if (startpc != endpc) for (List<JCCatch> l = catchers; l.nonEmpty(); l = l.tail) {
+ // start off with exception on stack
+ code.entryPoint(stateTry, l.head.param.sym.type);
+ genCatch(l.head, env, startpc, endpc, gaps);
+ genFinalizer(env);
+ if (hasFinalizer || l.tail.nonEmpty()) {
+ code.statBegin(TreeInfo.endPos(env.tree));
+ exitChain = Code.mergeChains(exitChain,
+ code.branch(goto_));
}
+ endFinalizerGap(env);
+ }
+ if (hasFinalizer) {
+ // Create a new register segement to avoid allocating
+ // the same variables in finalizers and other statements.
+ code.newRegSegment();
+
+ // Add a catch-all clause.
+
+ // start off with exception on stack
+ int catchallpc = code.entryPoint(stateTry, syms.throwableType);
- if (hasFinalizer) {
- // Create a new register segement to avoid allocating
- // the same variables in finalizers and other statements.
- code.newRegSegment();
-
- // Add a catch-all clause.
-
- // start off with exception on stack
- int catchallpc = code.entryPoint(stateTry, syms.throwableType);
+ // Register all exception ranges for catch all clause.
+ // The range of the catch all clause is from the beginning
+ // of the try or synchronized block until the present
+ // code pointer excluding all gaps in the current
+ // environment's GenContext.
+ int startseg = startpc;
+ while (env.info.gaps.nonEmpty()) {
+ int endseg = env.info.gaps.next().intValue();
+ registerCatch(body.pos(), startseg, endseg,
+ catchallpc, 0);
+ startseg = env.info.gaps.next().intValue();
+ }
+ code.statBegin(TreeInfo.finalizerPos(env.tree));
+ code.markStatBegin();
- // Register all exception ranges for catch all clause.
- // The range of the catch all clause is from the beginning
- // of the try or synchronized block until the present
- // code pointer excluding all gaps in the current
- // environment's GenContext.
- int startseg = startpc;
- while (env.info.gaps.nonEmpty()) {
- int endseg = env.info.gaps.next().intValue();
- registerCatch(body.pos(), startseg, endseg,
- catchallpc, 0);
- startseg = env.info.gaps.next().intValue();
- }
+ Item excVar = makeTemp(syms.throwableType);
+ excVar.store();
+ genFinalizer(env);
+ excVar.load();
+ registerCatch(body.pos(), startseg,
+ env.info.gaps.next().intValue(),
+ catchallpc, 0);
+ code.emitop0(athrow);
+ code.markDead();
+
+ // If there are jsr's to this finalizer, ...
+ if (env.info.cont != null) {
+ // Resolve all jsr's.
+ code.resolve(env.info.cont);
+
+ // Mark statement line number
code.statBegin(TreeInfo.finalizerPos(env.tree));
code.markStatBegin();
- Item excVar = makeTemp(syms.throwableType);
- excVar.store();
- genFinalizer(env);
- excVar.load();
- registerCatch(body.pos(), startseg,
- env.info.gaps.next().intValue(),
- catchallpc, 0);
- code.emitop0(athrow);
- code.markDead();
-
- // If there are jsr's to this finalizer, ...
- if (env.info.cont != null) {
- // Resolve all jsr's.
- code.resolve(env.info.cont);
+ // Save return address.
+ LocalItem retVar = makeTemp(syms.throwableType);
+ retVar.store();
- // Mark statement line number
- code.statBegin(TreeInfo.finalizerPos(env.tree));
- code.markStatBegin();
-
- // Save return address.
- LocalItem retVar = makeTemp(syms.throwableType);
- retVar.store();
+ // Generate finalizer code.
+ env.info.finalize.genLast();
- // Generate finalizer code.
- env.info.finalize.genLast();
-
- // Return.
- code.emitop1w(ret, retVar.reg);
- code.markDead();
- }
+ // Return.
+ code.emitop1w(ret, retVar.reg);
+ code.markDead();
}
}
// Resolve all breaks.
@@ -1581,7 +1642,7 @@
int catchType = makeRef(tree.pos(), subCatch.type);
int end = gaps.head.intValue();
registerCatch(tree.pos(),
- startpc, end, code.curPc(),
+ startpc, end, code.curCP(),
catchType);
if (subCatch.type.isAnnotated()) {
// All compounds share the same position, simply update the
@@ -1597,7 +1658,7 @@
for (JCExpression subCatch : subClauses) {
int catchType = makeRef(tree.pos(), subCatch.type);
registerCatch(tree.pos(),
- startpc, endpc, code.curPc(),
+ startpc, endpc, code.curCP(),
catchType);
if (subCatch.type.isAnnotated()) {
// All compounds share the same position, simply update the
@@ -1740,11 +1801,19 @@
code.resolve(c.trueJumps);
genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET);
thenExit = code.branch(goto_);
+ if (varDebugInfo && lvtRanges.containsKey(code.meth, tree.thenpart)) {
+ code.closeAliveRanges(tree.thenpart,
+ thenExit != null && tree.elsepart == null ? thenExit.pc : code.cp);
+ }
}
if (elseChain != null) {
code.resolve(elseChain);
- if (tree.elsepart != null)
+ if (tree.elsepart != null) {
genStat(tree.elsepart, env,CRT_STATEMENT | CRT_FLOW_TARGET);
+ if (varDebugInfo && lvtRanges.containsKey(code.meth, tree.elsepart)) {
+ code.closeAliveRanges(tree.elsepart);
+ }
+ }
}
code.resolve(thenExit);
code.endScopes(limit);
@@ -1838,20 +1907,20 @@
Chain elseChain = c.jumpFalse();
if (!c.isFalse()) {
code.resolve(c.trueJumps);
- int startpc = genCrt ? code.curPc() : 0;
+ int startpc = genCrt ? code.curCP() : 0;
genExpr(tree.truepart, pt).load();
code.state.forceStackTop(tree.type);
if (genCrt) code.crt.put(tree.truepart, CRT_FLOW_TARGET,
- startpc, code.curPc());
+ startpc, code.curCP());
thenExit = code.branch(goto_);
}
if (elseChain != null) {
code.resolve(elseChain);
- int startpc = genCrt ? code.curPc() : 0;
+ int startpc = genCrt ? code.curCP() : 0;
genExpr(tree.falsepart, pt).load();
code.state.forceStackTop(tree.type);
if (genCrt) code.crt.put(tree.falsepart, CRT_FLOW_TARGET,
- startpc, code.curPc());
+ startpc, code.curCP());
}
code.resolve(thenExit);
result = items.makeStackItem(pt);
@@ -2431,6 +2500,19 @@
new Env<GenContext>(cdef, new GenContext());
localEnv.toplevel = env.toplevel;
localEnv.enclClass = cdef;
+
+ /* We must not analyze synthetic methods
+ */
+ if (varDebugInfo && (cdef.sym.flags() & SYNTHETIC) == 0) {
+ try {
+ LVTAssignAnalyzer lvtAssignAnalyzer = LVTAssignAnalyzer.make(
+ lvtRanges, syms, names);
+ lvtAssignAnalyzer.analyzeTree(localEnv);
+ } catch (Throwable e) {
+ throw e;
+ }
+ }
+
for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
genDef(l.head, localEnv);
}
@@ -2515,4 +2597,311 @@
cont = Code.mergeChains(c, cont);
}
}
+
+ static class LVTAssignAnalyzer
+ extends Flow.AbstractAssignAnalyzer<LVTAssignAnalyzer.LVTAssignPendingExit> {
+
+ final LVTBits lvtInits;
+ final LVTRanges lvtRanges;
+
+ /* This class is anchored to a context dependent tree. The tree can
+ * vary inside the same instruction for example in the switch instruction
+ * the same FlowBits instance can be anchored to the whole tree, or
+ * to a given case. The aim is to always anchor the bits to the tree
+ * capable of closing a DA range.
+ */
+ static class LVTBits extends Bits {
+
+ enum BitsOpKind {
+ INIT,
+ CLEAR,
+ INCL_BIT,
+ EXCL_BIT,
+ ASSIGN,
+ AND_SET,
+ OR_SET,
+ DIFF_SET,
+ XOR_SET,
+ INCL_RANGE,
+ EXCL_RANGE,
+ }
+
+ JCTree currentTree;
+ LVTAssignAnalyzer analyzer;
+ private int[] oldBits = null;
+ BitsState stateBeforeOp;
+
+ LVTBits() {
+ super(false);
+ }
+
+ LVTBits(int[] bits, BitsState initState) {
+ super(bits, initState);
+ }
+
+ @Override
+ public void clear() {
+ generalOp(null, -1, BitsOpKind.CLEAR);
+ }
+
+ @Override
+ protected void internalReset() {
+ super.internalReset();
+ oldBits = null;
+ }
+
+ @Override
+ public Bits assign(Bits someBits) {
+ // bits can be null
+ oldBits = bits;
+ stateBeforeOp = currentState;
+ super.assign(someBits);
+ changed();
+ return this;
+ }
+
+ @Override
+ public void excludeFrom(int start) {
+ generalOp(null, start, BitsOpKind.EXCL_RANGE);
+ }
+
+ @Override
+ public void excl(int x) {
+ Assert.check(x >= 0);
+ generalOp(null, x, BitsOpKind.EXCL_BIT);
+ }
+
+ @Override
+ public Bits andSet(Bits xs) {
+ return generalOp(xs, -1, BitsOpKind.AND_SET);
+ }
+
+ @Override
+ public Bits orSet(Bits xs) {
+ return generalOp(xs, -1, BitsOpKind.OR_SET);
+ }
+
+ @Override
+ public Bits diffSet(Bits xs) {
+ return generalOp(xs, -1, BitsOpKind.DIFF_SET);
+ }
+
+ @Override
+ public Bits xorSet(Bits xs) {
+ return generalOp(xs, -1, BitsOpKind.XOR_SET);
+ }
+
+ private Bits generalOp(Bits xs, int i, BitsOpKind opKind) {
+ Assert.check(currentState != BitsState.UNKNOWN);
+ oldBits = dupBits();
+ stateBeforeOp = currentState;
+ switch (opKind) {
+ case AND_SET:
+ super.andSet(xs);
+ break;
+ case OR_SET:
+ super.orSet(xs);
+ break;
+ case XOR_SET:
+ super.xorSet(xs);
+ break;
+ case DIFF_SET:
+ super.diffSet(xs);
+ break;
+ case CLEAR:
+ super.clear();
+ break;
+ case EXCL_BIT:
+ super.excl(i);
+ break;
+ case EXCL_RANGE:
+ super.excludeFrom(i);
+ break;
+ }
+ changed();
+ return this;
+ }
+
+ /* The tree we need to anchor the bits instance to.
+ */
+ LVTBits at(JCTree tree) {
+ this.currentTree = tree;
+ return this;
+ }
+
+ /* If the instance should be changed but the tree is not a closing
+ * tree then a reset is needed or the former tree can mistakingly be
+ * used.
+ */
+ LVTBits resetTree() {
+ this.currentTree = null;
+ return this;
+ }
+
+ /** This method will be called after any operation that causes a change to
+ * the bits. Subclasses can thus override it in order to extract information
+ * from the changes produced to the bits by the given operation.
+ */
+ public void changed() {
+ if (currentTree != null &&
+ stateBeforeOp != BitsState.UNKNOWN &&
+ trackTree(currentTree)) {
+ List<VarSymbol> locals =
+ analyzer.lvtRanges
+ .getVars(analyzer.currentMethod, currentTree);
+ locals = locals != null ?
+ locals : List.<VarSymbol>nil();
+ for (JCVariableDecl vardecl : analyzer.vardecls) {
+ //once the first is null, the rest will be so.
+ if (vardecl == null) {
+ break;
+ }
+ if (trackVar(vardecl.sym) && bitChanged(vardecl.sym.adr)) {
+ locals = locals.prepend(vardecl.sym);
+ }
+ }
+ if (!locals.isEmpty()) {
+ analyzer.lvtRanges.setEntry(analyzer.currentMethod,
+ currentTree, locals);
+ }
+ }
+ }
+
+ boolean bitChanged(int x) {
+ boolean isMemberOfBits = isMember(x);
+ int[] tmp = bits;
+ bits = oldBits;
+ boolean isMemberOfOldBits = isMember(x);
+ bits = tmp;
+ return (!isMemberOfBits && isMemberOfOldBits);
+ }
+
+ boolean trackVar(VarSymbol var) {
+ return (var.owner.kind == MTH &&
+ (var.flags() & (PARAMETER | HASINIT)) == 0 &&
+ analyzer.trackable(var));
+ }
+
+ boolean trackTree(JCTree tree) {
+ switch (tree.getTag()) {
+ // of course a method closes the alive range of a local variable.
+ case METHODDEF:
+ // for while loops we want only the body
+ case WHILELOOP:
+ return false;
+ }
+ return true;
+ }
+
+ }
+
+ public class LVTAssignPendingExit extends Flow.AssignAnalyzer.AssignPendingExit {
+
+ LVTAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
+ super(tree, inits, uninits);
+ }
+
+ @Override
+ public void resolveJump(JCTree tree) {
+ lvtInits.at(tree);
+ super.resolveJump(tree);
+ }
+ }
+
+ private LVTAssignAnalyzer(LVTRanges lvtRanges, Symtab syms, Names names) {
+ super(new LVTBits(), syms, names);
+ lvtInits = (LVTBits)inits;
+ this.lvtRanges = lvtRanges;
+ }
+
+ public static LVTAssignAnalyzer make(LVTRanges lvtRanges, Symtab syms, Names names) {
+ LVTAssignAnalyzer result = new LVTAssignAnalyzer(lvtRanges, syms, names);
+ result.lvtInits.analyzer = result;
+ return result;
+ }
+
+ @Override
+ protected void markDead(JCTree tree) {
+ lvtInits.at(tree).inclRange(returnadr, nextadr);
+ super.markDead(tree);
+ }
+
+ @Override
+ protected void merge(JCTree tree) {
+ lvtInits.at(tree);
+ super.merge(tree);
+ }
+
+ boolean isSyntheticOrMandated(Symbol sym) {
+ return (sym.flags() & (SYNTHETIC | MANDATED)) != 0;
+ }
+
+ @Override
+ protected boolean trackable(VarSymbol sym) {
+ if (isSyntheticOrMandated(sym)) {
+ //fast check to avoid tracking synthetic or mandated variables
+ return false;
+ }
+ return super.trackable(sym);
+ }
+
+ @Override
+ protected void initParam(JCVariableDecl def) {
+ if (!isSyntheticOrMandated(def.sym)) {
+ super.initParam(def);
+ }
+ }
+
+ @Override
+ protected void assignToInits(JCTree tree, Bits bits) {
+ lvtInits.at(tree);
+ lvtInits.assign(bits);
+ }
+
+ @Override
+ protected void andSetInits(JCTree tree, Bits bits) {
+ lvtInits.at(tree);
+ lvtInits.andSet(bits);
+ }
+
+ @Override
+ protected void orSetInits(JCTree tree, Bits bits) {
+ lvtInits.at(tree);
+ lvtInits.orSet(bits);
+ }
+
+ @Override
+ protected void exclVarFromInits(JCTree tree, int adr) {
+ lvtInits.at(tree);
+ lvtInits.excl(adr);
+ }
+
+ @Override
+ protected LVTAssignPendingExit createNewPendingExit(JCTree tree, Bits inits, Bits uninits) {
+ return new LVTAssignPendingExit(tree, inits, uninits);
+ }
+
+ MethodSymbol currentMethod;
+
+ @Override
+ public void visitMethodDef(JCMethodDecl tree) {
+ if ((tree.sym.flags() & (SYNTHETIC | GENERATEDCONSTR)) != 0) {
+ return;
+ }
+ if (tree.name.equals(names.clinit)) {
+ return;
+ }
+ boolean enumClass = (tree.sym.owner.flags() & ENUM) != 0;
+ if (enumClass &&
+ (tree.name.equals(names.valueOf) ||
+ tree.name.equals(names.values) ||
+ tree.name.equals(names.init))) {
+ return;
+ }
+ currentMethod = tree.sym;
+ super.visitMethodDef(tree);
+ }
+
+ }
+
}
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Items.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Items.java Sat Sep 14 20:43:34 2013 +0100
@@ -789,18 +789,18 @@
Chain jumpTrue() {
if (tree == null) return Code.mergeChains(trueJumps, code.branch(opcode));
// we should proceed further in -Xjcov mode only
- int startpc = code.curPc();
+ int startpc = code.curCP();
Chain c = Code.mergeChains(trueJumps, code.branch(opcode));
- code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curPc());
+ code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curCP());
return c;
}
Chain jumpFalse() {
if (tree == null) return Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
// we should proceed further in -Xjcov mode only
- int startpc = code.curPc();
+ int startpc = code.curCP();
Chain c = Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
- code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curPc());
+ code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curCP());
return c;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/LVTRanges.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,129 @@
+/*
+ * 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. 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 com.sun.tools.javac.jvm;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.WeakHashMap;
+
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+
+/** This class contains a one to many relation between a tree and a set of variables.
+ * The relation implies that the given tree closes the DA (definite assignment)
+ * range for the set of variables.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.</b>
+ */
+public class LVTRanges {
+ /** The context key for the LVT ranges. */
+ protected static final Context.Key<LVTRanges> lvtRangesKey = new Context.Key<>();
+
+ /** Get the LVTRanges instance for this context. */
+ public static LVTRanges instance(Context context) {
+ LVTRanges instance = context.get(lvtRangesKey);
+ if (instance == null) {
+ instance = new LVTRanges(context);
+ }
+ return instance;
+ }
+
+ private static final long serialVersionUID = 1812267524140424433L;
+
+ protected Context context;
+
+ protected Map<MethodSymbol, Map<JCTree, List<VarSymbol>>>
+ aliveRangeClosingTrees = new WeakHashMap<>();
+
+ public LVTRanges(Context context) {
+ this.context = context;
+ context.put(lvtRangesKey, this);
+ }
+
+ public List<VarSymbol> getVars(MethodSymbol method, JCTree tree) {
+ Map<JCTree, List<VarSymbol>> varMap = aliveRangeClosingTrees.get(method);
+ return (varMap != null) ? varMap.get(tree) : null;
+ }
+
+ public boolean containsKey(MethodSymbol method, JCTree tree) {
+ Map<JCTree, List<VarSymbol>> varMap = aliveRangeClosingTrees.get(method);
+ if (varMap == null) {
+ return false;
+ }
+ return varMap.containsKey(tree);
+ }
+
+ public void setEntry(MethodSymbol method, JCTree tree, List<VarSymbol> vars) {
+ Map<JCTree, List<VarSymbol>> varMap = aliveRangeClosingTrees.get(method);
+ if (varMap != null) {
+ varMap.put(tree, vars);
+ } else {
+ varMap = new WeakHashMap<>();
+ varMap.put(tree, vars);
+ aliveRangeClosingTrees.put(method, varMap);
+ }
+ }
+
+ public List<VarSymbol> removeEntry(MethodSymbol method, JCTree tree) {
+ Map<JCTree, List<VarSymbol>> varMap = aliveRangeClosingTrees.get(method);
+ if (varMap != null) {
+ List<VarSymbol> result = varMap.remove(tree);
+ if (varMap.isEmpty()) {
+ aliveRangeClosingTrees.remove(method);
+ }
+ return result;
+ }
+ return null;
+ }
+
+ /* This method should be used for debugging LVT related issues.
+ */
+ @Override
+ public String toString() {
+ String result = "";
+ for (Entry<MethodSymbol, Map<JCTree, List<VarSymbol>>> mainEntry: aliveRangeClosingTrees.entrySet()) {
+ result += "Method: \n" + mainEntry.getKey().flatName() + "\n";
+ int i = 1;
+ for (Entry<JCTree, List<VarSymbol>> treeEntry: mainEntry.getValue().entrySet()) {
+ result += " Tree " + i + ": \n" + treeEntry.getKey().toString() + "\n";
+ result += " Variables closed:\n";
+ for (VarSymbol var: treeEntry.getValue()) {
+ result += " " + var.toString();
+ }
+ result += "\n";
+ i++;
+ }
+ }
+ return result;
+ }
+
+}
--- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Sat Sep 14 20:43:34 2013 +0100
@@ -80,7 +80,7 @@
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
-public class JavaCompiler implements ClassReader.SourceCompleter {
+public class JavaCompiler {
/** The context key for the compiler. */
protected static final Context.Key<JavaCompiler> compilerKey =
new Context.Key<JavaCompiler>();
@@ -311,6 +311,17 @@
protected JavaCompiler delegateCompiler;
/**
+ * SourceCompleter that delegates to the complete-method of this class.
+ */
+ protected final ClassReader.SourceCompleter thisCompleter =
+ new ClassReader.SourceCompleter() {
+ @Override
+ public void complete(ClassSymbol sym) throws CompletionFailure {
+ JavaCompiler.this.complete(sym);
+ }
+ };
+
+ /**
* Command line options.
*/
protected Options options;
@@ -374,7 +385,7 @@
types = Types.instance(context);
taskListener = MultiTaskListener.instance(context);
- reader.sourceCompleter = this;
+ reader.sourceCompleter = thisCompleter;
options = Options.instance(context);
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Sat Sep 14 20:43:34 2013 +0100
@@ -742,11 +742,6 @@
compiler.misc.incompatible.arg.types.in.mref=\
incompatible parameter types in method reference
-# 0: list of type, 1: message segment
-compiler.misc.bad.arg.types.in.lambda=\
- cannot type-check lambda expression with inferred parameter types\n\
- inferred types: {0}
-
compiler.err.new.not.allowed.in.annotation=\
''new'' not allowed in an annotation
@@ -1397,6 +1392,10 @@
compiler.warn.missing.SVUID=\
serializable class {0} has no definition of serialVersionUID
+# 0: symbol, 1: symbol, 2: symbol, 3: symbol
+compiler.warn.potentially.ambiguous.overload=\
+ {0} in {1} is potentially ambiguous with {2} in {3}
+
# 0: message segment
compiler.warn.override.varargs.missing=\
{0}; overridden method has no ''...''
@@ -1916,10 +1915,6 @@
inferred: {0}\n\
equality constraints(s): {1}
-# 0: list of type
-compiler.misc.cyclic.inference=\
- Cannot instantiate inference variables {0} because of an inference loop
-
# 0: symbol
compiler.misc.diamond=\
{0}<>
@@ -1932,6 +1927,10 @@
compiler.misc.diamond.and.explicit.params=\
cannot use ''<>'' with explicit type parameters for constructor
+# 0: unused
+compiler.misc.mref.infer.and.explicit.params=\
+ cannot use raw constructor reference with explicit type parameters for constructor
+
# 0: type, 1: list of type
compiler.misc.explicit.param.do.not.conform.to.bounds=\
explicit type argument {0} does not conform to declared bound(s) {1}
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java Sat Sep 14 20:43:34 2013 +0100
@@ -1596,7 +1596,6 @@
public List<JCVariableDecl> params;
public JCTree body;
public boolean canCompleteNormally = true;
- public List<Type> inferredThrownTypes;
public ParameterKind paramKind;
public JCLambda(List<JCVariableDecl> params,
@@ -1908,6 +1907,7 @@
* Selects a member expression.
*/
public static class JCMemberReference extends JCFunctionalExpression implements MemberReferenceTree {
+
public ReferenceMode mode;
public ReferenceKind kind;
public Name name;
@@ -1917,6 +1917,12 @@
public Type varargsElement;
public PolyKind refPolyKind;
public boolean ownerAccessible;
+ public OverloadKind overloadKind;
+
+ public enum OverloadKind {
+ OVERLOADED,
+ UNOVERLOADED;
+ }
/**
* Javac-dependent classification for member references, based
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java Sat Sep 14 20:43:34 2013 +0100
@@ -890,7 +890,7 @@
/** Create a value parameter tree from its name, type, and owner.
*/
public JCVariableDecl Param(Name name, Type argtype, Symbol owner) {
- return VarDef(new VarSymbol(0, name, argtype, owner), null);
+ return VarDef(new VarSymbol(PARAMETER, name, argtype, owner), null);
}
/** Create a a list of value parameter trees x0, ..., xn from a list of
--- a/langtools/src/share/classes/com/sun/tools/javac/util/Bits.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/Bits.java Sat Sep 14 20:43:34 2013 +0100
@@ -27,8 +27,6 @@
import java.util.Arrays;
-import static com.sun.tools.javac.util.Bits.BitsOpKind.*;
-
/** A class for extensible, mutable bit sets.
*
* <p><b>This is NOT part of any supported API.
@@ -38,20 +36,6 @@
*/
public class Bits {
- public enum BitsOpKind {
- INIT,
- CLEAR,
- INCL_BIT,
- EXCL_BIT,
- ASSIGN,
- AND_SET,
- OR_SET,
- DIFF_SET,
- XOR_SET,
- INCL_RANGE,
- EXCL_RANGE,
- }
-
// ____________ reset _________
// / UNKNOWN \ <-------- / UNINIT \
// \____________/ | \_________/
@@ -64,11 +48,14 @@
// | |
// -----------
// any
- private enum BitsState {
+ protected enum BitsState {
/* A Bits instance is in UNKNOWN state if it has been explicitly reset.
* It is possible to get to this state from any other by calling the
* reset method. An instance in the UNKNOWN state can pass to the
* NORMAL state after being assigned another Bits instance.
+ *
+ * Bits instances are final fields in Flow so the UNKNOWN state models
+ * the null assignment.
*/
UNKNOWN,
/* A Bits instance is in UNINIT when it is created with the default
@@ -103,13 +90,9 @@
public int[] bits = null;
// This field will store last version of bits after every change.
- public int[] oldBits = null;
-
- public BitsOpKind lastOperation = null;
-
private static final int[] unassignedBits = new int[0];
- private BitsState currentState;
+ protected BitsState currentState;
/** Construct an initially empty set.
*/
@@ -127,27 +110,20 @@
/** Construct a set consisting initially of given bit vector.
*/
- private Bits(int[] bits, BitsState initState) {
+ protected Bits(int[] bits, BitsState initState) {
this.bits = bits;
this.currentState = initState;
switch (initState) {
case UNKNOWN:
- reset(); //this will also set current state;
+ this.bits = null;
break;
case NORMAL:
Assert.check(bits != unassignedBits);
- lastOperation = INIT;
break;
}
}
- /** This method will be called after any operation that causes a change to
- * the bits. Subclasses can thus override it in order to extract information
- * from the changes produced to the bits by the given operation.
- */
- public void changed() {}
-
- private void sizeTo(int len) {
+ protected void sizeTo(int len) {
if (bits.length < len) {
bits = Arrays.copyOf(bits, len);
}
@@ -157,16 +133,18 @@
*/
public void clear() {
Assert.check(currentState != BitsState.UNKNOWN);
- oldBits = bits;
- lastOperation = CLEAR;
- for (int i = 0; i < bits.length; i++) bits[i] = 0;
- changed();
+ for (int i = 0; i < bits.length; i++) {
+ bits[i] = 0;
+ }
currentState = BitsState.NORMAL;
}
public void reset() {
+ internalReset();
+ }
+
+ protected void internalReset() {
bits = null;
- oldBits = null;
currentState = BitsState.UNKNOWN;
}
@@ -175,40 +153,40 @@
}
public Bits assign(Bits someBits) {
- lastOperation = ASSIGN;
- oldBits = bits;
bits = someBits.dup().bits;
- changed();
currentState = BitsState.NORMAL;
return this;
}
/** Return a copy of this set.
*/
- private Bits dup() {
+ public Bits dup() {
Assert.check(currentState != BitsState.UNKNOWN);
Bits tmp = new Bits();
- if (currentState != BitsState.NORMAL) {
- tmp.bits = bits;
- } else {
- tmp.bits = new int[bits.length];
- System.arraycopy(bits, 0, tmp.bits, 0, bits.length);
- }
+ tmp.bits = dupBits();
currentState = BitsState.NORMAL;
return tmp;
}
+ protected int[] dupBits() {
+ int [] result;
+ if (currentState != BitsState.NORMAL) {
+ result = bits;
+ } else {
+ result = new int[bits.length];
+ System.arraycopy(bits, 0, result, 0, bits.length);
+ }
+ return result;
+ }
+
/** Include x in this set.
*/
public void incl(int x) {
Assert.check(currentState != BitsState.UNKNOWN);
- Assert.check(x >= 0);
- oldBits = bits;
- lastOperation = INCL_BIT;
+ Assert.check(x >= 0, "Value of x " + x);
sizeTo((x >>> wordshift) + 1);
bits[x >>> wordshift] = bits[x >>> wordshift] |
(1 << (x & wordmask));
- changed();
currentState = BitsState.NORMAL;
}
@@ -217,14 +195,11 @@
*/
public void inclRange(int start, int limit) {
Assert.check(currentState != BitsState.UNKNOWN);
- oldBits = bits;
- lastOperation = INCL_RANGE;
sizeTo((limit >>> wordshift) + 1);
for (int x = start; x < limit; x++) {
bits[x >>> wordshift] = bits[x >>> wordshift] |
(1 << (x & wordmask));
}
- changed();
currentState = BitsState.NORMAL;
}
@@ -232,13 +207,10 @@
*/
public void excludeFrom(int start) {
Assert.check(currentState != BitsState.UNKNOWN);
- oldBits = bits;
- lastOperation = EXCL_RANGE;
Bits temp = new Bits();
temp.sizeTo(bits.length);
temp.inclRange(0, start);
internalAndSet(temp);
- changed();
currentState = BitsState.NORMAL;
}
@@ -247,12 +219,9 @@
public void excl(int x) {
Assert.check(currentState != BitsState.UNKNOWN);
Assert.check(x >= 0);
- oldBits = bits;
- lastOperation = EXCL_BIT;
sizeTo((x >>> wordshift) + 1);
bits[x >>> wordshift] = bits[x >>> wordshift] &
~(1 << (x & wordmask));
- changed();
currentState = BitsState.NORMAL;
}
@@ -269,15 +238,12 @@
*/
public Bits andSet(Bits xs) {
Assert.check(currentState != BitsState.UNKNOWN);
- oldBits = bits;
- lastOperation = AND_SET;
internalAndSet(xs);
- changed();
currentState = BitsState.NORMAL;
return this;
}
- private void internalAndSet(Bits xs) {
+ protected void internalAndSet(Bits xs) {
Assert.check(currentState != BitsState.UNKNOWN);
sizeTo(xs.bits.length);
for (int i = 0; i < xs.bits.length; i++) {
@@ -289,13 +255,10 @@
*/
public Bits orSet(Bits xs) {
Assert.check(currentState != BitsState.UNKNOWN);
- oldBits = bits;
- lastOperation = OR_SET;
sizeTo(xs.bits.length);
for (int i = 0; i < xs.bits.length; i++) {
bits[i] = bits[i] | xs.bits[i];
}
- changed();
currentState = BitsState.NORMAL;
return this;
}
@@ -304,14 +267,11 @@
*/
public Bits diffSet(Bits xs) {
Assert.check(currentState != BitsState.UNKNOWN);
- oldBits = bits;
- lastOperation = DIFF_SET;
for (int i = 0; i < bits.length; i++) {
if (i < xs.bits.length) {
bits[i] = bits[i] & ~xs.bits[i];
}
}
- changed();
currentState = BitsState.NORMAL;
return this;
}
@@ -320,13 +280,10 @@
*/
public Bits xorSet(Bits xs) {
Assert.check(currentState != BitsState.UNKNOWN);
- oldBits = bits;
- lastOperation = XOR_SET;
sizeTo(xs.bits.length);
for (int i = 0; i < xs.bits.length; i++) {
bits[i] = bits[i] ^ xs.bits[i];
}
- changed();
currentState = BitsState.NORMAL;
return this;
}
@@ -336,7 +293,9 @@
*/
private static int trailingZeroBits(int x) {
Assert.check(wordlen == 32);
- if (x == 0) return 32;
+ if (x == 0) {
+ return 32;
+ }
int n = 1;
if ((x & 0xffff) == 0) { n += 16; x >>>= 16; }
if ((x & 0x00ff) == 0) { n += 8; x >>>= 8; }
@@ -355,24 +314,31 @@
public int nextBit(int x) {
Assert.check(currentState != BitsState.UNKNOWN);
int windex = x >>> wordshift;
- if (windex >= bits.length) return -1;
+ if (windex >= bits.length) {
+ return -1;
+ }
int word = bits[windex] & ~((1 << (x & wordmask))-1);
while (true) {
- if (word != 0)
+ if (word != 0) {
return (windex << wordshift) + trailingZeroBits(word);
+ }
windex++;
- if (windex >= bits.length) return -1;
+ if (windex >= bits.length) {
+ return -1;
+ }
word = bits[windex];
}
}
/** a string representation of this set.
*/
+ @Override
public String toString() {
- if (bits.length > 0) {
+ if (bits != null && bits.length > 0) {
char[] digits = new char[bits.length * wordlen];
- for (int i = 0; i < bits.length * wordlen; i++)
+ for (int i = 0; i < bits.length * wordlen; i++) {
digits[i] = isMember(i) ? '1' : '0';
+ }
return new String(digits);
} else {
return "[]";
@@ -396,6 +362,8 @@
System.out.println("found " + i);
count ++;
}
- if (count != 125) throw new Error();
+ if (count != 125) {
+ throw new Error();
+ }
}
}
--- a/langtools/src/share/classes/com/sun/tools/javac/util/GraphUtils.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/GraphUtils.java Sat Sep 14 20:43:34 2013 +0100
@@ -33,6 +33,18 @@
public class GraphUtils {
/**
+ * Basic interface for defining various dependency kinds. All dependency kinds
+ * must at least support basic capabilities to tell the DOT engine how to render them.
+ */
+ public interface DependencyKind {
+ /**
+ * Returns the DOT representation (to be used in a {@code style} attribute
+ * that's most suited for this dependency kind.
+ */
+ String getDotStyle();
+ }
+
+ /**
* This class is a basic abstract class for representing a node.
* A node is associated with a given data.
*/
@@ -43,9 +55,20 @@
this.data = data;
}
- public abstract Iterable<? extends Node<D>> getDependencies();
+ /**
+ * Get an array of the dependency kinds supported by this node.
+ */
+ public abstract DependencyKind[] getSupportedDependencyKinds();
- public abstract String printDependency(Node<D> to);
+ /**
+ * Get all dependencies, regardless of their kind.
+ */
+ public abstract Iterable<? extends Node<D>> getAllDependencies();
+
+ /**
+ * Get a name for the dependency (of given kind) linking this node to a given node
+ */
+ public abstract String getDependencyName(Node<D> to, DependencyKind dk);
@Override
public String toString() {
@@ -66,7 +89,9 @@
super(data);
}
- public abstract Iterable<? extends TarjanNode<D>> getDependencies();
+ public abstract Iterable<? extends TarjanNode<D>> getAllDependencies();
+
+ public abstract Iterable<? extends TarjanNode<D>> getDependenciesByKind(DependencyKind dk);
public int compareTo(TarjanNode<D> o) {
return (index < o.index) ? -1 : (index == o.index) ? 0 : 1;
@@ -95,7 +120,7 @@
index++;
stack.prepend(v);
v.active = true;
- for (TarjanNode<D> nd: v.getDependencies()) {
+ for (TarjanNode<D> nd: v.getAllDependencies()) {
@SuppressWarnings("unchecked")
N n = (N)nd;
if (n.index == -1) {
@@ -134,9 +159,11 @@
}
//dump arcs
for (TarjanNode<D> from : nodes) {
- for (TarjanNode<D> to : from.getDependencies()) {
- buf.append(String.format("%s -> %s [label = \" %s \"];\n",
- from.hashCode(), to.hashCode(), from.printDependency(to)));
+ for (DependencyKind dk : from.getSupportedDependencyKinds()) {
+ for (TarjanNode<D> to : from.getDependenciesByKind(dk)) {
+ buf.append(String.format("%s -> %s [label = \" %s \" style = %s ];\n",
+ from.hashCode(), to.hashCode(), from.getDependencyName(to, dk), dk.getDotStyle()));
+ }
}
}
buf.append("}\n");
--- a/langtools/src/share/classes/com/sun/tools/javac/util/List.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/List.java Sat Sep 14 20:43:34 2013 +0100
@@ -116,6 +116,19 @@
return buf.toList();
}
+ /**
+ * Create a new list from the first {@code n} elements of this list
+ */
+ public List<A> take(int n) {
+ ListBuffer<A> buf = ListBuffer.lb();
+ int count = 0;
+ for (A el : this) {
+ if (count++ == n) break;
+ buf.append(el);
+ }
+ return buf.toList();
+ }
+
/** Construct a list consisting of given element.
*/
public static <A> List<A> of(A x1) {
--- a/langtools/src/share/classes/com/sun/tools/javadoc/AnnotatedTypeImpl.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/AnnotatedTypeImpl.java Sat Sep 14 20:43:34 2013 +0100
@@ -40,7 +40,7 @@
public class AnnotatedTypeImpl
extends AbstractTypeImpl implements AnnotatedType {
- AnnotatedTypeImpl(DocEnv env, com.sun.tools.javac.code.Type.AnnotatedType type) {
+ AnnotatedTypeImpl(DocEnv env, com.sun.tools.javac.code.Type type) {
super(env, type);
}
@@ -50,7 +50,7 @@
*/
@Override
public AnnotationDesc[] annotations() {
- List<TypeCompound> tas = ((com.sun.tools.javac.code.Type.AnnotatedType)type).typeAnnotations;
+ List<? extends TypeCompound> tas = type.getAnnotationMirrors();
if (tas == null ||
tas.isEmpty()) {
return new AnnotationDesc[0];
@@ -65,7 +65,7 @@
@Override
public com.sun.javadoc.Type underlyingType() {
- return TypeMaker.getType(env, ((com.sun.tools.javac.code.Type.AnnotatedType)type).underlyingType, true, false);
+ return TypeMaker.getType(env, type.unannotatedType(), true, false);
}
@Override
--- a/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java Sat Sep 14 20:43:34 2013 +0100
@@ -289,7 +289,7 @@
}
public boolean isFunctionalInterface() {
- return env.types.isFunctionalInterface(tsym);
+ return env.types.isFunctionalInterface(tsym) && env.source.allowLambda();
}
/**
--- a/langtools/src/share/classes/com/sun/tools/javadoc/DocEnv.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/DocEnv.java Sat Sep 14 20:43:34 2013 +0100
@@ -124,6 +124,11 @@
private boolean silent = false;
/**
+ * The source language version.
+ */
+ protected Source source;
+
+ /**
* Constructor
*
* @param context Context for this javadoc instance.
@@ -144,6 +149,7 @@
// Default. Should normally be reset with setLocale.
this.doclocale = new DocLocale(this, "", breakiterator);
+ source = Source.instance(context);
}
public void setSilent(boolean silent) {
--- a/langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -134,7 +134,7 @@
docenv.setEncoding(encoding);
docenv.docClasses = docClasses;
docenv.legacyDoclet = legacyDoclet;
- javadocReader.sourceCompleter = docClasses ? null : this;
+ javadocReader.sourceCompleter = docClasses ? null : thisCompleter;
ListBuffer<String> names = new ListBuffer<String>();
ListBuffer<JCCompilationUnit> classTrees = new ListBuffer<JCCompilationUnit>();
--- a/langtools/src/share/classes/com/sun/tools/javadoc/TypeMaker.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/TypeMaker.java Sat Sep 14 20:43:34 2013 +0100
@@ -63,10 +63,8 @@
t = env.types.erasure(t);
}
- if (considerAnnotations &&
- t.isAnnotated()) {
- Type.AnnotatedType at = (Type.AnnotatedType) t;
- return new AnnotatedTypeImpl(env, at);
+ if (considerAnnotations && t.isAnnotated()) {
+ return new AnnotatedTypeImpl(env, t);
}
switch (t.getTag()) {
@@ -143,8 +141,7 @@
static String getTypeString(DocEnv env, Type t, boolean full) {
// TODO: should annotations be included here?
if (t.isAnnotated()) {
- Type.AnnotatedType at = (Type.AnnotatedType)t;
- t = at.underlyingType;
+ t = t.unannotatedType();
}
switch (t.getTag()) {
case ARRAY:
--- a/langtools/src/share/classes/com/sun/tools/javadoc/TypeVariableImpl.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/TypeVariableImpl.java Sat Sep 14 20:43:34 2013 +0100
@@ -140,7 +140,7 @@
if (!type.isAnnotated()) {
return new AnnotationDesc[0];
}
- List<TypeCompound> tas = ((com.sun.tools.javac.code.Type.AnnotatedType) type).typeAnnotations;
+ List<? extends TypeCompound> tas = type.getAnnotationMirrors();
AnnotationDesc res[] = new AnnotationDesc[tas.length()];
int i = 0;
for (Attribute.Compound a : tas) {
--- a/langtools/test/com/sun/javadoc/AccessSkipNav/AccessSkipNav.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/com/sun/javadoc/AccessSkipNav/AccessSkipNav.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 4638136
+ * @bug 4638136 7198273
* @summary Add ability to skip over nav bar for accessibility
* @author dkramer
* @run main AccessSkipNav
@@ -42,7 +42,7 @@
*/
public class AccessSkipNav {
- private static final String BUGID = "4638136";
+ private static final String BUGID = "4638136 - 7198273";
private static final String BUGNAME = "AccessSkipNav";
private static final String FS = System.getProperty("file.separator");
private static final String PS = System.getProperty("path.separator");
@@ -86,7 +86,7 @@
// Testing only for the presence of the <a href> and <a name>
// Top navbar <a href>
- { "<a href=\"#skip-navbar_top\" title=\"Skip navigation links\"></a>",
+ { "<a href=\"#skip-navbar_top\" title=\"Skip navigation links\">Skip navigation links</a>",
TMPDEST_DIR1 + "p1" + FS + "C1.html" },
// Top navbar <a name>
@@ -95,7 +95,7 @@
TMPDEST_DIR1 + "p1" + FS + "C1.html" },
// Bottom navbar <a href>
- { "<a href=\"#skip-navbar_bottom\" title=\"Skip navigation links\"></a>",
+ { "<a href=\"#skip-navbar_bottom\" title=\"Skip navigation links\">Skip navigation links</a>",
TMPDEST_DIR1 + "p1" + FS + "C1.html" },
// Bottom navbar <a name>
--- a/langtools/test/com/sun/javadoc/testGeneratedBy/TestGeneratedBy.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/com/sun/javadoc/testGeneratedBy/TestGeneratedBy.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8000418
+ * @bug 8000418 8024288
* @summary Verify that files use a common Generated By string
* @library ../lib/
* @build JavadocTester TestGeneratedBy
@@ -50,32 +50,44 @@
"index.html"
};
- private static final String[] ARGS =
+ private static final String[] STD_ARGS =
new String[] {
"-d", OUTPUT_DIR,
"-sourcepath", SRC_DIR,
"pkg"
};
- private static final String BUG_ID = "8000418";
- private static String[][] getTests() {
+ private static final String[] NO_TIMESTAMP_ARGS =
+ new String[] {
+ "-notimestamp",
+ "-d", OUTPUT_DIR,
+ "-sourcepath", SRC_DIR,
+ "pkg"
+ };
+
+ private static final String BUG_ID = "8000418-8024288";
+
+ private static String[][] getTests(boolean timestamp) {
String version = System.getProperty("java.version");
String[][] tests = new String[FILES.length][];
for (int i = 0; i < FILES.length; i++) {
+ String genBy = "Generated by javadoc";
+ if (timestamp) genBy += " (" + version + ") on ";
tests[i] = new String[] {
- OUTPUT_DIR + FS + FILES[i],
- "Generated by javadoc (" + version + ") on "
+ OUTPUT_DIR + FS + FILES[i], genBy
};
}
return tests;
}
- private static String[][] getNegatedTests() {
+ private static String[][] getNegatedTests(boolean timestamp) {
String[][] tests = new String[FILES.length][];
for (int i = 0; i < FILES.length; i++) {
tests[i] = new String[] {
OUTPUT_DIR + FS + FILES[i],
- "Generated by javadoc (version",
+ (timestamp
+ ? "Generated by javadoc (version"
+ : "Generated by javadoc ("),
"Generated by javadoc on"
};
}
@@ -88,9 +100,10 @@
*/
public static void main(String[] args) {
TestGeneratedBy tester = new TestGeneratedBy();
- int exitCode = run(tester, ARGS, getTests(), getNegatedTests());
+ int ec1 = run(tester, STD_ARGS, getTests(true), getNegatedTests(true));
+ int ec2 = run(tester, NO_TIMESTAMP_ARGS, getTests(false), getNegatedTests(false));
tester.printSummary();
- if (exitCode != 0) {
+ if (ec1 != 0 || ec2 != 0) {
throw new Error("Error found while executing Javadoc");
}
}
--- a/langtools/test/com/sun/javadoc/testLambdaFeature/TestLambdaFeature.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/com/sun/javadoc/testLambdaFeature/TestLambdaFeature.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8004893
+ * @bug 8004893 8022738
* @summary Make sure that the lambda feature changes work fine in
* javadoc.
* @author bpatel
@@ -35,11 +35,15 @@
public class TestLambdaFeature extends JavadocTester {
//Test information.
- private static final String BUG_ID = "8004893";
+ private static final String BUG_ID = "8004893-8022738";
//Javadoc arguments.
private static final String[] ARGS = new String[] {
- "-d", BUG_ID, "-sourcepath", SRC_DIR, "pkg"
+ "-d", BUG_ID, "-sourcepath", SRC_DIR, "pkg", "pkg1"
+ };
+
+ private static final String[] ARGS_1 = new String[] {
+ "-d", BUG_ID + "-2", "-sourcepath", SRC_DIR, "-source", "1.5", "pkg1"
};
//Input for string search tests.
@@ -63,6 +67,11 @@
"<dl>" + NL + "<dt>Functional Interface:</dt>" + NL +
"<dd>This is a functional interface and can therefore be used as " +
"the assignment target for a lambda expression or method " +
+ "reference.</dd>" + NL + "</dl>"},
+ {BUG_ID + FS + "pkg1" + FS + "FuncInf.html",
+ "<dl>" + NL + "<dt>Functional Interface:</dt>" + NL +
+ "<dd>This is a functional interface and can therefore be used as " +
+ "the assignment target for a lambda expression or method " +
"reference.</dd>" + NL + "</dl>"}
};
private static final String[][] NEGATED_TEST = {
@@ -75,6 +84,10 @@
{BUG_ID + FS + "pkg" + FS + "B.html",
"<dl>" + NL + "<dt>Functional Interface:</dt>"}
};
+ private static final String[][] NEGATED_TEST_1 = {
+ {BUG_ID + "-2" + FS + "pkg1" + FS + "FuncInf.html",
+ "<dl>" + NL + "<dt>Functional Interface:</dt>"}
+ };
/**
* The entry point of the test.
@@ -83,6 +96,7 @@
public static void main(String[] args) {
TestLambdaFeature tester = new TestLambdaFeature();
run(tester, ARGS, TEST, NEGATED_TEST);
+ run(tester, ARGS_1, NO_TEST, NEGATED_TEST_1);
tester.printSummary();
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/com/sun/javadoc/testLambdaFeature/pkg1/FuncInf.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,29 @@
+/*
+ * 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 pkg1;
+
+public interface FuncInf<V> {
+
+ V call() throws Exception;
+}
--- a/langtools/test/com/sun/javadoc/testLegacyTaglet/C.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/com/sun/javadoc/testLegacyTaglet/C.java Sat Sep 14 20:43:34 2013 +0100
@@ -25,5 +25,13 @@
/**
* This is an {@underline underline}.
* @todo Finish this class.
+ * @check Check this.
*/
-public class C {}
+public class C {
+
+ /**
+ * @todo Tag in Method.
+ */
+ public void mtd() {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/com/sun/javadoc/testLegacyTaglet/Check.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+import com.sun.tools.doclets.Taglet;
+import com.sun.javadoc.*;
+import java.util.Map;
+
+public class Check implements Taglet {
+
+ private static final String TAG_NAME = "check";
+ private static final String TAG_HEADER = "Check:";
+
+ /**
+ * Return true since the tag can be used in package documentation.
+ *
+ * @return true since the tag can be used in package documentation.
+ */
+ public boolean inPackage() {
+ return true;
+ }
+
+ /**
+ * Return true since the tag can be used in overview documentation.
+ *
+ * @return true since the tag can be used in overview documentation.
+ */
+ public boolean inOverview() {
+ return true;
+ }
+
+ /**
+ * Return true since the tag can be used in type (class/interface)
+ * documentation.
+ *
+ * @return true since the tag can be used in type (class/interface)
+ * documentation.
+ */
+ public boolean inType() {
+ return true;
+ }
+
+ /**
+ * Return true since the tag can be used in constructor documentation.
+ *
+ * @return true since the tag can be used in constructor documentation.
+ */
+ public boolean inConstructor() {
+ return true;
+ }
+
+ /**
+ * Return true since the tag can be used in field documentation.
+ *
+ * @return true since the tag can be used in field documentation.
+ */
+ public boolean inField() {
+ return true;
+ }
+
+ /**
+ * Return true since the tag can be used in method documentation.
+ *
+ * @return true since the tag can be used in method documentation.
+ */
+ public boolean inMethod() {
+ return true;
+ }
+
+ /**
+ * Return false since the tag is not an inline tag.
+ *
+ * @return false since the tag is not an inline tag.
+ */
+ public boolean isInlineTag() {
+ return false;
+ }
+
+ /**
+ * Register this taglet.
+ *
+ * @param tagletMap the map to register this tag to.
+ */
+ @SuppressWarnings("unchecked")
+ public static void register(Map tagletMap) {
+ Check tag = new Check();
+ Taglet t = (Taglet) tagletMap.get(tag.getName());
+ if (t != null) {
+ tagletMap.remove(tag.getName());
+ }
+ tagletMap.put(tag.getName(), tag);
+ }
+
+ /**
+ * Return the name of this custom tag.
+ *
+ * @return the name of this tag.
+ */
+ public String getName() {
+ return TAG_NAME;
+ }
+
+ /**
+ * Given the tag representation of this custom tag, return its string
+ * representation.
+ *
+ * @param tag the tag representation of this custom tag.
+ */
+ public String toString(Tag tag) {
+ return "<dt><span class=\"strong\">" + TAG_HEADER + ":</span></dt><dd>" + tag.text() +
+ "</dd>\n";
+ }
+
+ /**
+ * Given an array of tags representing this custom tag, return its string
+ * representation.
+ *
+ * @param tags the array of tags representing of this custom tag.
+ * @return null to test if the javadoc throws an exception or not.
+ */
+ public String toString(Tag[] tags) {
+ return null;
+ }
+}
--- a/langtools/test/com/sun/javadoc/testLegacyTaglet/TestLegacyTaglet.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/com/sun/javadoc/testLegacyTaglet/TestLegacyTaglet.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -23,32 +23,33 @@
/*
* @test
- * @bug 4638723
+ * @bug 4638723 8015882
* @summary Test to ensure that the refactored version of the standard
* doclet still works with Taglets that implement the 1.4.0 interface.
* @author jamieh
* @library ../lib/
- * @compile ../lib/JavadocTester.java
- * @compile TestLegacyTaglet.java
- * @compile ToDoTaglet.java
- * @compile UnderlineTaglet.java
+ * @compile ../lib/JavadocTester.java TestLegacyTaglet.java ToDoTaglet.java UnderlineTaglet.java Check.java
* @run main TestLegacyTaglet
*/
public class TestLegacyTaglet extends JavadocTester {
- private static final String BUG_ID = "4638723";
+ private static final String BUG_ID = "4638723-8015882";
private static final String[] ARGS =
new String[] {"-d", BUG_ID, "-sourcepath", SRC_DIR,
- "-tagletpath", SRC_DIR, "-taglet", "ToDoTaglet",
+ "-tagletpath", SRC_DIR, "-taglet", "ToDoTaglet", "-taglet", "Check",
"-taglet", "UnderlineTaglet", SRC_DIR + FS + "C.java"};
private static final String[][] TEST = new String[][] {
{BUG_ID + FS + "C.html", "This is an <u>underline</u>"},
{BUG_ID + FS + "C.html",
"<DT><B>To Do:</B><DD><table cellpadding=2 cellspacing=0><tr>" +
- "<td bgcolor=\"yellow\">Finish this class.</td></tr></table></DD>"}};
+ "<td bgcolor=\"yellow\">Finish this class.</td></tr></table></DD>"},
+ {BUG_ID + FS + "C.html",
+ "<DT><B>To Do:</B><DD><table cellpadding=2 cellspacing=0><tr>" +
+ "<td bgcolor=\"yellow\">Tag in Method.</td></tr></table></DD>"}
+ };
private static final String[][] NEGATED_TEST = NO_TEST;
@@ -59,6 +60,9 @@
public static void main(String[] args) {
TestLegacyTaglet tester = new TestLegacyTaglet();
run(tester, ARGS, TEST, NEGATED_TEST);
+ if (tester.getErrorOutput().contains("NullPointerException")) {
+ throw new AssertionError("javadoc threw NullPointerException");
+ }
tester.printSummary();
}
--- a/langtools/test/com/sun/javadoc/testNavigation/TestNavigation.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/com/sun/javadoc/testNavigation/TestNavigation.java Sat Sep 14 20:43:34 2013 +0100
@@ -23,13 +23,12 @@
/*
* @test
- * @bug 4131628 4664607 7025314
+ * @bug 4131628 4664607 7025314 8023700 7198273
* @summary Make sure the Next/Prev Class links iterate through all types.
* Make sure the navagation is 2 columns, not 3.
* @author jamieh
* @library ../lib/
- * @build JavadocTester
- * @build TestNavigation
+ * @build JavadocTester TestNavigation
* @run main TestNavigation
*/
@@ -45,23 +44,23 @@
//Input for string search tests.
private static final String[][] TEST = {
- {BUG_ID + FS + "pkg" + FS + "A.html", "<li>Prev Class</li>"},
+ {BUG_ID + FS + "pkg" + FS + "A.html", "<li>Prev Class</li>"},
{BUG_ID + FS + "pkg" + FS + "A.html",
- "<a href=\"../pkg/C.html\" title=\"class in pkg\"><span class=\"strong\">Next Class</span></a>"},
+ "<a href=\"../pkg/C.html\" title=\"class in pkg\"><span class=\"strong\">Next Class</span></a>"},
{BUG_ID + FS + "pkg" + FS + "C.html",
- "<a href=\"../pkg/A.html\" title=\"annotation in pkg\"><span class=\"strong\">Prev Class</span></a>"},
+ "<a href=\"../pkg/A.html\" title=\"annotation in pkg\"><span class=\"strong\">Prev Class</span></a>"},
{BUG_ID + FS + "pkg" + FS + "C.html",
- "<a href=\"../pkg/E.html\" title=\"enum in pkg\"><span class=\"strong\">Next Class</span></a>"},
+ "<a href=\"../pkg/E.html\" title=\"enum in pkg\"><span class=\"strong\">Next Class</span></a>"},
{BUG_ID + FS + "pkg" + FS + "E.html",
- "<a href=\"../pkg/C.html\" title=\"class in pkg\"><span class=\"strong\">Prev Class</span></a>"},
+ "<a href=\"../pkg/C.html\" title=\"class in pkg\"><span class=\"strong\">Prev Class</span></a>"},
{BUG_ID + FS + "pkg" + FS + "E.html",
- "<a href=\"../pkg/I.html\" title=\"interface in pkg\"><span class=\"strong\">Next Class</span></a>"},
+ "<a href=\"../pkg/I.html\" title=\"interface in pkg\"><span class=\"strong\">Next Class</span></a>"},
{BUG_ID + FS + "pkg" + FS + "I.html",
- "<a href=\"../pkg/E.html\" title=\"enum in pkg\"><span class=\"strong\">Prev Class</span></a>"},
- {BUG_ID + FS + "pkg" + FS + "I.html", "<li>Next Class</li>"},
+ "<a href=\"../pkg/E.html\" title=\"enum in pkg\"><span class=\"strong\">Prev Class</span></a>"},
+ {BUG_ID + FS + "pkg" + FS + "I.html", "<li>Next Class</li>"},
// Test for 4664607
{BUG_ID + FS + "pkg" + FS + "I.html",
- "<a href=\"#skip-navbar_top\" title=\"Skip navigation links\"></a><a name=\"navbar_top_firstrow\">" + NL +
+ "<div class=\"skipNav\"><a href=\"#skip-navbar_top\" title=\"Skip navigation links\">Skip navigation links</a></div>" + NL + "<a name=\"navbar_top_firstrow\">" + NL +
"<!-- -->" + NL + "</a>"}
};
private static final String[][] NEGATED_TEST = NO_TEST;
--- a/langtools/test/com/sun/javadoc/testProfiles/TestProfiles.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/com/sun/javadoc/testProfiles/TestProfiles.java Sat Sep 14 20:43:34 2013 +0100
@@ -23,9 +23,9 @@
/*
* @test
- * @bug 8006124 8009684 8016921
+ * @bug 8006124 8009684 8016921 8023700
* @summary Test javadoc support for profiles.
- * @author Bhavesh Patel
+ * @author Bhavesh Patel, Evgeniya Stepanova
* @library ../lib/
* @build JavadocTester TestProfiles
* @run main TestProfiles
@@ -38,8 +38,9 @@
private static final String PACKAGE_BUG_ID = BUG_ID + "-2";
//Javadoc arguments.
private static final String[] ARGS1 = new String[]{
- "-d", PROFILE_BUG_ID, "-sourcepath", SRC_DIR, "-Xprofilespath", SRC_DIR + FS
- + "profile-rtjar-includes.txt", "pkg1", "pkg2", "pkg3", "pkg4", "pkg5"
+ "-d", PROFILE_BUG_ID, "-sourcepath", SRC_DIR, "-Xprofilespath",
+ SRC_DIR + FS + "profile-rtjar-includes.txt", "pkg1", "pkg2",
+ "pkg3", "pkg4", "pkg5", "pkgDeprecated"
};
private static final String[] ARGS2 = new String[]{
"-d", PACKAGE_BUG_ID, "-sourcepath", SRC_DIR, "pkg1", "pkg2", "pkg3", "pkg4", "pkg5"
@@ -49,7 +50,7 @@
// Tests for profile-overview-frame.html listing all profiles.
{PROFILE_BUG_ID + FS + "profile-overview-frame.html",
"<span><a href=\"overview-frame.html\" "
- + "target=\"packageListFrame\">All Packages</a></span>"
+ + "target=\"packageListFrame\">All Packages</a></span>"
},
{PROFILE_BUG_ID + FS + "profile-overview-frame.html",
"<li><a href=\"compact1-frame.html\" target=\"packageListFrame\">"
@@ -58,8 +59,8 @@
// Tests for profileName-frame.html listing all packages in a profile.
{PROFILE_BUG_ID + FS + "compact2-frame.html",
"<span><a href=\"overview-frame.html\" target=\"packageListFrame\">"
- + "All Packages</a></span><span><a href=\"profile-overview-frame.html\" "
- + "target=\"packageListFrame\">All Profiles</a></span>"
+ + "All Packages</a></span><span><a href=\"profile-overview-frame.html\" "
+ + "target=\"packageListFrame\">All Profiles</a></span>"
},
{PROFILE_BUG_ID + FS + "compact2-frame.html",
"<li><a href=\"pkg4/compact2-package-frame.html\" "
@@ -74,8 +75,8 @@
},
// Tests for profileName-summary.html listing the summary for a profile.
{PROFILE_BUG_ID + FS + "compact2-summary.html",
- "<li><a href=\"compact1-summary.html\">Prev Profile</a></li>" + NL
- + "<li><a href=\"compact3-summary.html\">Next Profile</a></li>"
+ "<li><a href=\"compact1-summary.html\">Prev Profile</a></li>" + NL
+ + "<li><a href=\"compact3-summary.html\">Next Profile</a></li>"
},
{PROFILE_BUG_ID + FS + "compact2-summary.html",
"<h1 title=\"Profile\" class=\"title\">Profile compact2</h1>"
@@ -87,7 +88,7 @@
// Tests for profileName-package-summary.html listing the summary for a
// package in a profile.
{PROFILE_BUG_ID + FS + "pkg5" + FS + "compact3-package-summary.html",
- "<li><a href=\"../pkg4/compact3-package-summary.html\">Prev Package"
+ "<li><a href=\"../pkg4/compact3-package-summary.html\">Prev Package"
+ "</a></li>"
},
{PROFILE_BUG_ID + FS + "pkg5" + FS + "compact3-package-summary.html",
@@ -96,7 +97,7 @@
//Test for "overview-frame.html" showing the "All Profiles" link.
{PROFILE_BUG_ID + FS + "overview-frame.html",
"<span><a href=\"profile-overview-frame.html\" "
- + "target=\"packageListFrame\">All Profiles</a></span>"
+ + "target=\"packageListFrame\">All Profiles</a></span>"
},
//Test for "className.html" showing the profile information for the type.
{PROFILE_BUG_ID + FS + "pkg2" + FS + "Class1Pkg2.html",
@@ -113,6 +114,49 @@
"target=\"classFrame\">compact2</a></li>" + NL + "<li><a href=\"" +
"compact3-summary.html\" target=\"classFrame\">compact3</a></li>" + NL +
"</ul>"
+ },
+ //Test deprecated class in profiles
+ {PROFILE_BUG_ID + FS + "compact1-summary.html","<td class=\"colFirst\">"
+ + "<a href=\"pkg2/Class1Pkg2.html\" title=\"class in pkg2\">Class1Pkg2</a></td>"
+ + NL + "<td class=\"colLast\">Deprecated"
+ },
+ {PROFILE_BUG_ID + FS + "deprecated-list.html","<td class=\"colOne\">"
+ + "<a href=\"pkg2/Class1Pkg2.html\" title=\"class in pkg2\">pkg2.Class1Pkg2</a>"
+ + NL +"<div class=\"block\"><span class=\"italic\">Class1Pkg2. This class is deprecated</span></div>"
+ },
+ //Test deprecated package in profile
+ {PROFILE_BUG_ID + FS + "deprecated-list.html","<td class=\"colOne\">"
+ + "<a href=\"pkgDeprecated/package-summary.html\">pkgDeprecated</a>"
+ + NL +"<div class=\"block\"><span class=\"italic\">This package is <b>Deprecated</b>."
+ + " Use pkg1.</span></div>"
+ },
+ {PROFILE_BUG_ID + FS + "pkgDeprecated" + FS + "package-summary.html",
+ "<div class=\"deprecatedContent\"><span class=\"strong\">Deprecated.</span>"
+ + NL + "<div class=\"block\"><span class=\"italic\">This package is <b>Deprecated</b>."
+ + " Use pkg1.</span></div>"
+ },
+ // need to add teststring when JDK-8015496 will be fixed
+ //Test exception in profiles
+ {PROFILE_BUG_ID + FS + "compact1-summary.html","<table class=\"packageSummary\" "
+ + "border=\"0\" cellpadding=\"3\" cellspacing=\"0\" "
+ + "summary=\"Exception Summary table, listing exceptions, and an explanation\">"
+ + NL + "<caption><span>Exception Summary</span><span class=\"tabEnd\">"
+ + " </span></caption>" + NL + "<tr>" + NL + "<th class=\"colFirst\" "
+ + "scope=\"col\">Exception</th>" + NL + "<th class=\"colLast\" scope=\"col\">"
+ + "Description</th>" + NL + "</tr>" + NL + "<tbody>" + NL + "<tr class=\"altColor\">"
+ + NL + "<td class=\"colFirst\"><a href=\"pkg2/ClassException.html\""
+ + " title=\"class in pkg2\">ClassException</a></td>"
+ },
+ //Test errors in profiles
+ {PROFILE_BUG_ID + FS + "compact1-summary.html",
+ "<table class=\"packageSummary\" border=\"0\" cellpadding=\"3\" cellspacing=\"0\" "
+ + "summary=\"Error Summary table, listing errors, and an explanation\">"
+ + NL + "<caption><span>Error Summary</span><span class=\"tabEnd\"> "
+ + "</span></caption>" + NL + "<tr>" + NL + "<th class=\"colFirst\""
+ + " scope=\"col\">Error</th>" + NL + "<th class=\"colLast\" "
+ + "scope=\"col\">Description</th>" + NL + "</tr>" + NL + "<tbody>"
+ + NL + "<tr class=\"altColor\">" + NL + "<td class=\"colFirst\">"
+ + "<a href=\"pkg2/ClassError.html\" title=\"class in pkg2\">ClassError</a></td>"
}
};
private static final String[][] PROFILES_NEGATED_TEST = {
@@ -125,6 +169,8 @@
{PROFILE_BUG_ID + FS + "pkg4" + FS + "compact2-package-frame.html",
"<li><a href=\"Anno1Pkg4.html\" title=\"annotation in pkg4\" "
+ "target=\"classFrame\">Anno1Pkg4</a></li>"
+ },
+ {PROFILE_BUG_ID + FS + "compact1-summary.html","<li>Use</li>"
}
};
private static final String[][] PACKAGES_TEST = {
@@ -143,12 +189,12 @@
private static final String[][] PACKAGES_NEGATED_TEST = {
{PACKAGE_BUG_ID + FS + "profile-overview-frame.html",
"<span><a href=\"overview-frame.html\" "
- + "target=\"packageListFrame\">All Packages</a></span>"
+ + "target=\"packageListFrame\">All Packages</a></span>"
},
{PACKAGE_BUG_ID + FS + "compact2-frame.html",
"<span><a href=\"overview-frame.html\" target=\"packageListFrame\">"
- + "All Packages</a></span><span><a href=\"profile-overview-frame.html\" "
- + "target=\"packageListFrame\">All Profiles</a></span>"
+ + "All Packages</a></span><span><a href=\"profile-overview-frame.html\" "
+ + "target=\"packageListFrame\">All Profiles</a></span>"
},
{PACKAGE_BUG_ID + FS + "pkg2" + FS + "compact2-package-frame.html",
"<a href=\"../compact2-summary.html\" target=\"classFrame\">"
@@ -163,7 +209,7 @@
},
{PACKAGE_BUG_ID + FS + "overview-frame.html",
"<span><a href=\"profile-overview-frame.html\" "
- + "target=\"packageListFrame\">All Profiles</a></span>"
+ + "target=\"packageListFrame\">All Profiles</a></span>"
},
{PACKAGE_BUG_ID + FS + "pkg2" + FS + "Class1Pkg2.html",
"<div class=\"subTitle\">compact1, compact2, compact3</div>"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/com/sun/javadoc/testProfiles/TestProfilesConfiguration.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8006124 8009684 8015663 8015496
+ * @summary Test javadoc options support for profiles.
+ * @author Evgeniya Stepanova
+ * @library ../lib/
+ * @build JavadocTester TestProfilesConfiguration
+ * @run main TestProfilesConfiguration
+ */
+public class TestProfilesConfiguration extends JavadocTester {
+
+ //Test information.
+ private static final String BUG_ID = "8006124-8009684";
+ private static final String PROFILE_CONFIGURATION_BUG_ID = BUG_ID + "-3";
+ private static final String NODEPR_NOPKGS_BUG_ID = BUG_ID + "-4";
+ //Javadoc arguments.
+ private static final String[] ARGS3 = new String[]{
+ "-d", PROFILE_CONFIGURATION_BUG_ID, "-sourcepath", SRC_DIR, "-nocomment",
+ "-keywords", "-Xprofilespath", SRC_DIR + FS + "profile-rtjar-includes.txt",
+ "-doctitle", "Simple doctitle", "-use", "pkg3", "pkg1", "pkg2", "pkg4",
+ "pkg5", "-packagesheader", "Simple packages header","pkgDeprecated"
+ };
+ private static final String[] ARGS4 = new String[]{
+ "-d", NODEPR_NOPKGS_BUG_ID, "-sourcepath", SRC_DIR, "-nocomment", "-nodeprecated",
+ "-keywords", "-Xprofilespath", SRC_DIR + FS + "profile-rtjar-includes-nopkgs.txt",
+ "-doctitle", "Simple doctitle", "-use", "-packagesheader", "Simple packages header",
+ "pkg1", "pkg2", "pkg3", "pkg4", "pkg5", "pkgDeprecated"
+ };
+ private static final String[][] NODEPR_NOPKGS_TEST = {
+ {NODEPR_NOPKGS_BUG_ID + FS + "overview-summary.html",
+ "<ul>" + NL + "<li><a href=\"compact2-summary.html\" target=\"classFrame\">" +
+ "compact2</a></li>" + NL + "<li><a href=\"compact3-summary.html\" target=\"" +
+ "classFrame\">compact3</a></li>" + NL + "</ul>"
+ },
+ {NODEPR_NOPKGS_BUG_ID + FS + "profile-overview-frame.html",
+ "<ul title=\"Profiles\">" + NL + "<li><a href=\"compact2-frame.html\" target=\"packageListFrame\">" +
+ "compact2</a></li>" + NL + "<li><a href=\"compact3-frame.html\" target=\"" +
+ "packageListFrame\">compact3</a></li>" + NL + "</ul>"
+ }
+ };
+ private static final String[][] NODEPR_NOPKGS_NEGATED_TEST = {
+ {NODEPR_NOPKGS_BUG_ID + FS + "overview-summary.html",
+ "compact1"
+ }
+ };
+
+ private static final String[][] PROFILES_CONFIGURATION_TEST = {
+ //-use option test string fo profile view page
+ {PROFILE_CONFIGURATION_BUG_ID + FS + "compact1-summary.html","<li>Use</li>"
+ },
+ //-doctitle option test string
+ {PROFILE_CONFIGURATION_BUG_ID + FS + "overview-summary.html",
+ "<div class=\"header\">" + NL + "<h1 class=\"title\">Simple doctitle</h1>"
+ },
+ //-packagesheader option test string fo profiles
+ {PROFILE_CONFIGURATION_BUG_ID + FS + "profile-overview-frame.html",
+ "<h1 title=\"Simple packages header\" class=\"bar\">Simple packages header</h1>"
+ },
+ //-keywords option test string for profiles
+ {PROFILE_CONFIGURATION_BUG_ID + FS + "compact1-summary.html",
+ "<meta name=\"keywords\" content=\"compact1 profile\">"
+ },
+ //Deprecated information on a package
+ {PROFILE_CONFIGURATION_BUG_ID + FS + "compact1-summary.html",
+ "<h3><a href=\"pkgDeprecated/compact1-package-summary.html\" target=\"" +
+ "classFrame\">pkgDeprecated</a></h3>" + NL + "<div class=\"deprecatedContent\">" +
+ "<span class=\"strong\">Deprecated.</span></div>"
+ }
+ };
+ private static final String[][] PROFILES_CONFIGURATION_NEGATED_TEST = {
+ //-nocomments option test string
+ {PROFILE_CONFIGURATION_BUG_ID + FS + "compact1-summary.html",
+ "<div class=\"block\"><i>Class1Pkg2.</i></div>"
+ }
+ };
+
+ /**
+ * The entry point of the test.
+ *
+ * @param args the array of command line arguments.
+ */
+ public static void main(String[] args) {
+ TestProfilesConfiguration tester = new TestProfilesConfiguration();
+ run(tester, ARGS3, PROFILES_CONFIGURATION_TEST,
+ PROFILES_CONFIGURATION_NEGATED_TEST);
+ run(tester, ARGS4, NODEPR_NOPKGS_TEST,
+ NODEPR_NOPKGS_NEGATED_TEST);
+ tester.printSummary();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getBugId() {
+ return BUG_ID;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getBugName() {
+ return getClass().getName();
+ }
+}
--- a/langtools/test/com/sun/javadoc/testProfiles/pkg2/Class1Pkg2.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/com/sun/javadoc/testProfiles/pkg2/Class1Pkg2.java Sat Sep 14 20:43:34 2013 +0100
@@ -24,7 +24,7 @@
package pkg2;
/**
- * Another test class.
+ * @deprecated Class1Pkg2. This class is deprecated
*
* @author Bhavesh Patel
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/com/sun/javadoc/testProfiles/pkg2/ClassError.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,31 @@
+/*
+ * 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 pkg2;
+
+/**
+ * Simple error class.
+ *
+ * @author Evgeniya Stepanova
+ */
+public class ClassError extends Error {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/com/sun/javadoc/testProfiles/pkg2/ClassException.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,31 @@
+/*
+ * 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 pkg2;
+
+/**
+ * Simple exception class.
+ *
+ * @author Evgeniya Stepanova
+ */
+public class ClassException extends Exception {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/com/sun/javadoc/testProfiles/pkgDeprecated/Class1PkgDeprecated.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,36 @@
+/*
+ * 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 pkgDeprecated;
+
+/**
+ * Simple deprecated class of deprecated package.
+ *
+ * @author Evgeniya Stepanova
+ */
+public class Class1PkgDeprecated {
+
+ public void method(int t) {
+ return null;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/com/sun/javadoc/testProfiles/pkgDeprecated/package-info.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+/**
+ * Deprecated package.
+ *
+ * @deprecated This package is <b>Deprecated</b>. Use pkg1.
+ */
+package pkgDeprecated;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/com/sun/javadoc/testProfiles/profile-rtjar-includes-nopkgs.txt Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,41 @@
+PROFILE_1_RTJAR_INCLUDE_PACKAGES :=
+
+PROFILE_1_RTJAR_INCLUDE_TYPES :=
+
+PROFILE_1_RTJAR_EXCLUDE_TYPES :=
+
+PROFILE_1_INCLUDE_METAINF_SERVICES :=
+
+
+PROFILE_2_RTJAR_INCLUDE_PACKAGES := \
+ pkg4 \
+ pkgDeprecated
+
+PROFILE_2_RTJAR_INCLUDE_TYPES :=
+
+PROFILE_2_RTJAR_EXCLUDE_TYPES := \
+ pkg4/Anno1Pkg4.class
+
+PROFILE_2_INCLUDE_METAINF_SERVICES :=
+
+
+PROFILE_3_RTJAR_INCLUDE_PACKAGES := \
+ pkg5
+
+PROFILE_3_RTJAR_INCLUDE_TYPES :=
+
+PROFILE_3_RTJAR_EXCLUDE_TYPES :=
+
+PROFILE_3_INCLUDE_METAINF_SERVICES :=
+
+
+PROFILE_4_RTJAR_INCLUDE_PACKAGES := \
+ pkg1
+
+PROFILE_4_RTJAR_INCLUDE_TYPES :=
+
+PROFILE_4_RTJAR_EXCLUDE_TYPES :=
+
+PROFILE_4_INCLUDE_METAINF_SERVICES :=
+
+
--- a/langtools/test/com/sun/javadoc/testProfiles/profile-rtjar-includes.txt Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/com/sun/javadoc/testProfiles/profile-rtjar-includes.txt Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,6 @@
PROFILE_1_RTJAR_INCLUDE_PACKAGES := \
- pkg2
+ pkg2 \
+ pkgDeprecated
PROFILE_1_RTJAR_INCLUDE_TYPES := \
pkg3/Class1Pkg3.class
--- a/langtools/test/com/sun/javadoc/testStylesheet/TestStylesheet.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/com/sun/javadoc/testStylesheet/TestStylesheet.java Sat Sep 14 20:43:34 2013 +0100
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 4494033 7028815 7052425 8007338
+ * @bug 4494033 7028815 7052425 8007338 8023608
* @summary Run tests on doclet stylesheet.
* @author jamieh
* @library ../lib/
@@ -72,7 +72,46 @@
" overflow:hidden;" + NL +
" padding:0px;" + NL +
" margin:0px;" + NL +
- " white-space:pre;" + NL +
+ "}"},
+ {BUG_ID + FS + "stylesheet.css",
+ ".overviewSummary caption span, .packageSummary caption span, " +
+ ".contentContainer ul.blockList li.blockList caption span, " +
+ ".summary caption span, .classUseContainer caption span, " +
+ ".constantValuesContainer caption span {" + NL +
+ " white-space:nowrap;" + NL +
+ " padding-top:8px;" + NL +
+ " padding-left:8px;" + NL +
+ " display:inline-block;" + NL +
+ " float:left;" + NL +
+ " background-image:url(resources/titlebar.gif);" + NL +
+ "}"},
+ {BUG_ID + FS + "stylesheet.css",
+ ".contentContainer ul.blockList li.blockList caption " +
+ "span.activeTableTab span {" + NL +
+ " white-space:nowrap;" + NL +
+ " padding-top:8px;" + NL +
+ " padding-left:8px;" + NL +
+ " display:inline-block;" + NL +
+ " float:left;" + NL +
+ " background-image:url(resources/activetitlebar.gif);" + NL +
+ "}"},
+ {BUG_ID + FS + "stylesheet.css",
+ ".contentContainer ul.blockList li.blockList caption span.tableTab span {" + NL +
+ " white-space:nowrap;" + NL +
+ " padding-top:8px;" + NL +
+ " padding-left:8px;" + NL +
+ " display:inline-block;" + NL +
+ " float:left;" + NL +
+ " background-image:url(resources/titlebar.gif);" + NL +
+ "}"},
+ {BUG_ID + FS + "stylesheet.css",
+ ".contentContainer ul.blockList li.blockList caption span.tableTab, " +
+ ".contentContainer ul.blockList li.blockList caption span.activeTableTab {" + NL +
+ " padding-top:0px;" + NL +
+ " padding-left:0px;" + NL +
+ " background-image:none;" + NL +
+ " float:none;" + NL +
+ " display:inline-block;" + NL +
"}"},
// Test whether a link to the stylesheet file is inserted properly
// in the class documentation.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/lib/combo/TEST.properties Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,4 @@
+# This file identifies root(s) of the test-ng hierarchy.
+
+
+TestNG.dirs = .
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/lib/combo/tools/javac/combo/Diagnostics.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,82 @@
+/*
+ * 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 tools.javac.combo;
+
+import javax.tools.Diagnostic;
+import javax.tools.JavaFileObject;
+import java.util.ArrayList;
+import java.util.List;
+
+import static java.util.stream.Collectors.toList;
+
+/**
+* A container for compiler diagnostics, separated into errors and warnings,
+ * used by JavacTemplateTestBase.
+ *
+ * @author Brian Goetz
+*/
+public class Diagnostics implements javax.tools.DiagnosticListener<JavaFileObject> {
+
+ protected List<Diagnostic<? extends JavaFileObject>> diags = new ArrayList<>();
+ protected boolean foundErrors = false;
+
+ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ diags.add(diagnostic);
+ foundErrors = foundErrors || diagnostic.getKind() == Diagnostic.Kind.ERROR;
+ }
+
+ /** Were there any errors found? */
+ public boolean errorsFound() {
+ return foundErrors;
+ }
+
+ /** Get all diagnostic keys */
+ public List<String> keys() {
+ return diags.stream()
+ .map(Diagnostic::getCode)
+ .collect(toList());
+ }
+
+ /** Do the diagnostics contain the specified error key? */
+ public boolean containsErrorKey(String key) {
+ return diags.stream()
+ .filter(d -> d.getKind() == Diagnostic.Kind.ERROR)
+ .anyMatch(d -> d.getCode().equals(key));
+ }
+
+ /** Get the error keys */
+ public List<String> errorKeys() {
+ return diags.stream()
+ .filter(d -> d.getKind() == Diagnostic.Kind.ERROR)
+ .map(Diagnostic::getCode)
+ .collect(toList());
+ }
+
+ public String toString() { return keys().toString(); }
+
+ /** Clear all diagnostic state */
+ public void reset() {
+ diags.clear();
+ foundErrors = false;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/lib/combo/tools/javac/combo/JavacTemplateTestBase.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,362 @@
+/*
+ * 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 tools.javac.combo;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+import com.sun.source.util.JavacTask;
+import com.sun.tools.javac.util.Pair;
+import org.testng.ITestResult;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.AfterSuite;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.fail;
+
+/**
+ * Base class for template-driven TestNG javac tests that support on-the-fly
+ * source file generation, compilation, classloading, execution, and separate
+ * compilation.
+ *
+ * <p>Manages a set of templates (which have embedded tags of the form
+ * {@code #\{NAME\}}), source files (which are also templates), and compile
+ * options. Test cases can register templates and source files, cause them to
+ * be compiled, validate whether the set of diagnostic messages output by the
+ * compiler is correct, and optionally load and run the compiled classes.
+ *
+ * @author Brian Goetz
+ */
+@Test
+public abstract class JavacTemplateTestBase {
+ private static final Set<String> suiteErrors = Collections.synchronizedSet(new HashSet<>());
+ private static final AtomicInteger counter = new AtomicInteger();
+ private static final File root = new File("gen");
+ private static final File nullDir = new File("empty");
+
+ protected final Map<String, Template> templates = new HashMap<>();
+ protected final Diagnostics diags = new Diagnostics();
+ protected final List<Pair<String, Template>> sourceFiles = new ArrayList<>();
+ protected final List<String> compileOptions = new ArrayList<>();
+ protected final List<File> classpaths = new ArrayList<>();
+ protected final Template.Resolver defaultResolver = new MapResolver(templates);
+
+ private Template.Resolver currentResolver = defaultResolver;
+
+ /** Add a template with a specified name */
+ protected void addTemplate(String name, Template t) {
+ templates.put(name, t);
+ }
+
+ /** Add a template with a specified name */
+ protected void addTemplate(String name, String s) {
+ templates.put(name, new StringTemplate(s));
+ }
+
+ /** Add a source file */
+ protected void addSourceFile(String name, Template t) {
+ sourceFiles.add(new Pair<>(name, t));
+ }
+
+ /** Add a File to the class path to be used when loading classes; File values
+ * will generally be the result of a previous call to {@link #compile()}.
+ * This enables testing of separate compilation scenarios if the class path
+ * is set up properly.
+ */
+ protected void addClassPath(File path) {
+ classpaths.add(path);
+ }
+
+ /**
+ * Add a set of compilation command-line options
+ */
+ protected void addCompileOptions(String... opts) {
+ Collections.addAll(compileOptions, opts);
+ }
+
+ /** Reset the compile options to the default (empty) value */
+ protected void resetCompileOptions() { compileOptions.clear(); }
+
+ /** Remove all templates */
+ protected void resetTemplates() { templates.clear(); }
+
+ /** Remove accumulated diagnostics */
+ protected void resetDiagnostics() { diags.reset(); }
+
+ /** Remove all source files */
+ protected void resetSourceFiles() { sourceFiles.clear(); }
+
+ /** Remove registered class paths */
+ protected void resetClassPaths() { classpaths.clear(); }
+
+ // Before each test method, reset everything
+ @BeforeMethod
+ public void reset() {
+ resetCompileOptions();
+ resetDiagnostics();
+ resetSourceFiles();
+ resetTemplates();
+ resetClassPaths();
+ }
+
+ // After each test method, if the test failed, capture source files and diagnostics and put them in the log
+ @AfterMethod
+ public void copyErrors(ITestResult result) {
+ if (!result.isSuccess()) {
+ suiteErrors.addAll(diags.errorKeys());
+
+ List<Object> list = new ArrayList<>();
+ Collections.addAll(list, result.getParameters());
+ list.add("Test case: " + getTestCaseDescription());
+ for (Pair<String, Template> e : sourceFiles)
+ list.add("Source file " + e.fst + ": " + e.snd);
+ if (diags.errorsFound())
+ list.add("Compile diagnostics: " + diags.toString());
+ result.setParameters(list.toArray(new Object[list.size()]));
+ }
+ }
+
+ @AfterSuite
+ // After the suite is done, dump any errors to output
+ public void dumpErrors() {
+ if (!suiteErrors.isEmpty())
+ System.err.println("Errors found in test suite: " + suiteErrors);
+ }
+
+ /**
+ * Get a description of this test case; since test cases may be combinatorially
+ * generated, this should include all information needed to describe the test case
+ */
+ protected String getTestCaseDescription() {
+ return this.toString();
+ }
+
+ /** Assert that all previous calls to compile() succeeded */
+ protected void assertCompileSucceeded() {
+ if (diags.errorsFound())
+ fail("Expected successful compilation");
+ }
+
+ /**
+ * If the provided boolean is true, assert all previous compiles succeeded,
+ * otherwise assert that a compile failed.
+ * */
+ protected void assertCompileSucceededIff(boolean b) {
+ if (b)
+ assertCompileSucceeded();
+ else
+ assertCompileFailed();
+ }
+
+ /** Assert that a previous call to compile() failed */
+ protected void assertCompileFailed() {
+ if (!diags.errorsFound())
+ fail("Expected failed compilation");
+ }
+
+ /** Assert that a previous call to compile() failed with a specific error key */
+ protected void assertCompileFailed(String message) {
+ if (!diags.errorsFound())
+ fail("Expected failed compilation: " + message);
+ }
+
+ /** Assert that a previous call to compile() failed with all of the specified error keys */
+ protected void assertCompileErrors(String... keys) {
+ if (!diags.errorsFound())
+ fail("Expected failed compilation");
+ for (String k : keys)
+ if (!diags.containsErrorKey(k))
+ fail("Expected compilation error " + k);
+ }
+
+ /** Convert an object, which may be a Template or a String, into a Template */
+ protected Template asTemplate(Object o) {
+ if (o instanceof Template)
+ return (Template) o;
+ else if (o instanceof String)
+ return new StringTemplate((String) o);
+ else
+ return new StringTemplate(o.toString());
+ }
+
+ /** Compile all registered source files */
+ protected void compile() throws IOException {
+ compile(false);
+ }
+
+ /** Compile all registered source files, optionally generating class files
+ * and returning a File describing the directory to which they were written */
+ protected File compile(boolean generate) throws IOException {
+ List<JavaFileObject> files = new ArrayList<>();
+ for (Pair<String, Template> e : sourceFiles)
+ files.add(new FileAdapter(e.fst, asTemplate(e.snd)));
+ return compile(classpaths, files, generate);
+ }
+
+ /** Compile all registered source files, using the provided list of class paths
+ * for finding required classfiles, optionally generating class files
+ * and returning a File describing the directory to which they were written */
+ protected File compile(List<File> classpaths, boolean generate) throws IOException {
+ List<JavaFileObject> files = new ArrayList<>();
+ for (Pair<String, Template> e : sourceFiles)
+ files.add(new FileAdapter(e.fst, asTemplate(e.snd)));
+ return compile(classpaths, files, generate);
+ }
+
+ private File compile(List<File> classpaths, List<JavaFileObject> files, boolean generate) throws IOException {
+ JavaCompiler systemJavaCompiler = ToolProvider.getSystemJavaCompiler();
+ StandardJavaFileManager fm = systemJavaCompiler.getStandardFileManager(null, null, null);
+ if (classpaths.size() > 0)
+ fm.setLocation(StandardLocation.CLASS_PATH, classpaths);
+ JavacTask ct = (JavacTask) systemJavaCompiler.getTask(null, fm, diags, compileOptions, null, files);
+ if (generate) {
+ File destDir = new File(root, Integer.toString(counter.incrementAndGet()));
+ // @@@ Assert that this directory didn't exist, or start counter at max+1
+ destDir.mkdirs();
+ fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(destDir));
+ ct.generate();
+ return destDir;
+ }
+ else {
+ ct.analyze();
+ return nullDir;
+ }
+ }
+
+ /** Load the given class using the provided list of class paths */
+ protected Class<?> loadClass(String className, File... destDirs) {
+ try {
+ List<URL> list = new ArrayList<>();
+ for (File f : destDirs)
+ list.add(new URL("file:" + f.toString().replace("\\", "/") + "/"));
+ return Class.forName(className, true, new URLClassLoader(list.toArray(new URL[list.size()])));
+ } catch (ClassNotFoundException | MalformedURLException e) {
+ throw new RuntimeException("Error loading class " + className, e);
+ }
+ }
+
+ /** An implementation of Template which is backed by a String */
+ protected class StringTemplate implements Template {
+ protected final String template;
+
+ public StringTemplate(String template) {
+ this.template = template;
+ }
+
+ public String expand(String selector) {
+ return Behavior.expandTemplate(template, currentResolver);
+ }
+
+ public String toString() {
+ return expand("");
+ }
+
+ public StringTemplate with(final String key, final String value) {
+ return new StringTemplateWithResolver(template, new KeyResolver(key, value));
+ }
+
+ }
+
+ /** An implementation of Template which is backed by a String and which
+ * encapsulates a Resolver for resolving embedded tags. */
+ protected class StringTemplateWithResolver extends StringTemplate {
+ private final Resolver localResolver;
+
+ public StringTemplateWithResolver(String template, Resolver localResolver) {
+ super(template);
+ this.localResolver = localResolver;
+ }
+
+ @Override
+ public String expand(String selector) {
+ Resolver saved = currentResolver;
+ currentResolver = new ChainedResolver(currentResolver, localResolver);
+ try {
+ return super.expand(selector);
+ }
+ finally {
+ currentResolver = saved;
+ }
+ }
+
+ @Override
+ public StringTemplate with(String key, String value) {
+ return new StringTemplateWithResolver(template, new ChainedResolver(localResolver, new KeyResolver(key, value)));
+ }
+ }
+
+ /** A Resolver which uses a Map to resolve tags */
+ private class KeyResolver implements Template.Resolver {
+ private final String key;
+ private final String value;
+
+ public KeyResolver(String key, String value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ @Override
+ public Template lookup(String k) {
+ return key.equals(k) ? new StringTemplate(value) : null;
+ }
+ }
+
+ private class FileAdapter extends SimpleJavaFileObject {
+ private final String filename;
+ private final Template template;
+
+ public FileAdapter(String filename, Template template) {
+ super(URI.create("myfo:/" + filename), Kind.SOURCE);
+ this.template = template;
+ this.filename = filename;
+ }
+
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return toString();
+ }
+
+ public String toString() {
+ return Template.Behavior.expandTemplate(template.expand(filename), defaultResolver);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/lib/combo/tools/javac/combo/Template.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,123 @@
+/*
+ * 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 tools.javac.combo;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A template into which tags of the form {@code #\{KEY\}} or
+ * {@code #\{KEY.SUBKEY\}} can be expanded.
+ */
+public interface Template {
+ String expand(String selector);
+
+ interface Resolver {
+ public Template lookup(String key);
+ }
+
+ public static class Behavior {
+ /* Looks for expandable keys. An expandable key can take the form:
+ * #{MAJOR}
+ * #{MAJOR.}
+ * #{MAJOR.MINOR}
+ * where MAJOR can be IDENTIFIER or IDENTIFIER[NUMERIC_INDEX]
+ * and MINOR can be an identifier.
+ *
+ * The ability to have an empty minor is provided on the
+ * assumption that some tests that can be written with this
+ * will find it useful to make a distinction akin to
+ * distinguishing F from F(), where F is a function pointer,
+ * and also cases of #{FOO.#{BAR}}, where BAR expands to an
+ * empty string.
+ *
+ * However, this being a general-purpose framework, the exact
+ * use is left up to the test writers.
+ */
+ private static final Pattern pattern = Pattern.compile("#\\{([A-Z_][A-Z0-9_]*(?:\\[\\d+\\])?)(?:\\.([A-Z0-9_]*))?\\}");
+
+ public static String expandTemplate(String template, final Map<String, Template> vars) {
+ return expandTemplate(template, new MapResolver(vars));
+ }
+
+ public static String expandTemplate(String template, Resolver res) {
+ CharSequence in = template;
+ StringBuffer out = new StringBuffer();
+ while (true) {
+ boolean more = false;
+ Matcher m = pattern.matcher(in);
+ while (m.find()) {
+ String major = m.group(1);
+ String minor = m.group(2);
+ Template key = res.lookup(major);
+ if (key == null)
+ throw new IllegalStateException("Unknown major key " + major);
+
+ String replacement = key.expand(minor == null ? "" : minor);
+ more |= pattern.matcher(replacement).find();
+ m.appendReplacement(out, replacement);
+ }
+ m.appendTail(out);
+ if (!more)
+ return out.toString();
+ else {
+ in = out;
+ out = new StringBuffer();
+ }
+ }
+ }
+
+ }
+}
+
+class MapResolver implements Template.Resolver {
+ private final Map<String, Template> vars;
+
+ public MapResolver(Map<String, Template> vars) {this.vars = vars;}
+
+ public Template lookup(String key) {
+ return vars.get(key);
+ }
+}
+
+class ChainedResolver implements Template.Resolver {
+ private final Template.Resolver upstreamResolver, thisResolver;
+
+ public ChainedResolver(Template.Resolver upstreamResolver, Template.Resolver thisResolver) {
+ this.upstreamResolver = upstreamResolver;
+ this.thisResolver = thisResolver;
+ }
+
+ public Template.Resolver getUpstreamResolver() {
+ return upstreamResolver;
+ }
+
+ @Override
+ public Template lookup(String key) {
+ Template result = thisResolver.lookup(key);
+ if (result == null)
+ result = upstreamResolver.lookup(key);
+ return result;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/lib/combo/tools/javac/combo/TemplateTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,94 @@
+/*
+ * 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 tools.javac.combo;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * TemplateTest
+ */
+@Test
+public class TemplateTest {
+ Map<String, Template> vars = new HashMap<>();
+
+ @BeforeTest
+ void before() { vars.clear(); }
+
+ private void assertTemplate(String expected, String template) {
+ String result = Template.Behavior.expandTemplate(template, vars);
+ assertEquals(result, expected, "for " + template);
+ }
+
+ private String dotIf(String s) {
+ return s == null || s.isEmpty() ? "" : "." + s;
+ }
+
+ public void testTemplateExpansion() {
+ vars.put("A", s -> "a" + dotIf(s));
+ vars.put("B", s -> "b" + dotIf(s));
+ vars.put("C", s -> "#{A}#{B}");
+ vars.put("D", s -> "#{A" + dotIf(s) + "}#{B" + dotIf(s) + "}");
+ vars.put("_D", s -> "d");
+
+ assertTemplate("", "");
+ assertTemplate("foo", "foo");
+ assertTemplate("a", "#{A}");
+ assertTemplate("a", "#{A.}");
+ assertTemplate("a.FOO", "#{A.FOO}");
+ assertTemplate("aa", "#{A}#{A}");
+ assertTemplate("ab", "#{C}");
+ assertTemplate("ab", "#{C.FOO}");
+ assertTemplate("ab", "#{C.}");
+ assertTemplate("a.FOOb.FOO", "#{D.FOO}");
+ assertTemplate("ab", "#{D}");
+ assertTemplate("d", "#{_D}");
+ assertTemplate("#{A", "#{A");
+ }
+
+ public void testIndexedTemplate() {
+ vars.put("A[0]", s -> "a" );
+ vars.put("A[1]", s -> "b" );
+ vars.put("A[2]", s -> "c" );
+ vars.put("X", s -> "0");
+ assertTemplate("a", "#{A[0]}");
+ assertTemplate("b", "#{A[1]}");
+ assertTemplate("c", "#{A[2]}");
+ }
+
+ public void testAngleBrackets() {
+ vars.put("X", s -> "xyz");
+ assertTemplate("List<String> ls = xyz;", "List<String> ls = #{X};");
+ }
+
+ @Test(expectedExceptions = IllegalStateException.class )
+ public void testUnknownKey() {
+ assertTemplate("#{Q}", "#{Q}");
+ }
+}
--- a/langtools/test/tools/javac/Diagnostics/compressed/T8012003c.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/Diagnostics/compressed/T8012003c.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,3 +1,2 @@
T8012003c.java:18:15: compiler.err.report.access: m(), private, P
-- compiler.note.compressed.diags
1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/T8022162/IncorrectSignatureDeterminationForInnerClassesTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8022162
+ * @summary Incorrect signature determination for certain inner class generics
+ * @library /tools/javac/lib
+ * @build ToolBox
+ * @run main IncorrectSignatureDeterminationForInnerClassesTest
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+public class IncorrectSignatureDeterminationForInnerClassesTest {
+
+ private static final String DSrc =
+ "package p1;\n" +
+
+ "public class D<T> {\n" +
+ "}\n" +
+
+ "abstract class Q<T> {\n" +
+ " protected void m(M.E e) {}\n" +
+
+ " public class M extends D<T> {\n" +
+ " public class E {}\n" +
+ " }\n" +
+ "}";
+
+ private static final String HSrc =
+ "package p1;\n" +
+
+ "public class H {\n" +
+ " static class EQ extends Q<Object> {\n" +
+ " private void m2(M.E item) {\n" +
+ " m(item);\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+
+ public static void main(String args[]) throws Exception {
+ new IncorrectSignatureDeterminationForInnerClassesTest().run();
+ }
+
+ void run() throws Exception {
+ compile();
+ }
+
+ void compile() throws Exception {
+ Files.createDirectory(Paths.get("classes"));
+
+ ToolBox.JavaToolArgs javacParams =
+ new ToolBox.JavaToolArgs()
+ .appendArgs("-d", "classes")
+ .setSources(DSrc);
+
+ ToolBox.javac(javacParams);
+
+ // compile class H against the class files for classes D and Q
+ javacParams =
+ new ToolBox.JavaToolArgs()
+ .appendArgs("-d", "classes", "-cp", "classes")
+ .setSources(HSrc);
+ ToolBox.javac(javacParams);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/T8023545/MisleadingErrorMsgDiamondPlusPrivateCtorTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,16 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8023545
+ * @summary Misleading error message when using diamond operator with private constructor
+ * @compile/fail/ref=MisleadingErrorMsgDiamondPlusPrivateCtorTest.out -XDrawDiagnostics MisleadingErrorMsgDiamondPlusPrivateCtorTest.java
+ */
+
+public class MisleadingErrorMsgDiamondPlusPrivateCtorTest {
+ public void foo() {
+ MyClass<Object> foo = new MyClass<>();
+ }
+}
+
+class MyClass<E> {
+ private MyClass() {}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/T8023545/MisleadingErrorMsgDiamondPlusPrivateCtorTest.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,2 @@
+MisleadingErrorMsgDiamondPlusPrivateCtorTest.java:10:31: compiler.err.report.access: <E>MyClass(), private, MyClass
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/T8024039/NoDeadCodeGenerationOnTrySmtTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,124 @@
+/*
+ * 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. 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
+ * @bug 8024039
+ * @summary javac, previous solution for JDK-8022186 was incorrect
+ * @library /tools/javac/lib
+ * @build ToolBox
+ * @run main NoDeadCodeGenerationOnTrySmtTest
+ */
+
+import java.io.File;
+import java.nio.file.Paths;
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.Code_attribute;
+import com.sun.tools.classfile.Code_attribute.Exception_data;
+import com.sun.tools.classfile.Method;
+import com.sun.tools.javac.util.Assert;
+
+public class NoDeadCodeGenerationOnTrySmtTest {
+
+ static final String testSource =
+ "public class Test {\n" +
+ " void m1(int arg) {\n" +
+ " synchronized (new Integer(arg)) {\n" +
+ " {\n" +
+ " label0:\n" +
+ " do {\n" +
+ " break label0;\n" +
+ " } while (arg != 0);\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+
+ " void m2(int arg) {\n" +
+ " synchronized (new Integer(arg)) {\n" +
+ " {\n" +
+ " label0:\n" +
+ " {\n" +
+ " break label0;\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+
+ static final int[][] expectedExceptionTable = {
+ // {from, to, target, type},
+ {11, 13, 16, 0},
+ {16, 19, 16, 0}
+ };
+
+ static final String[] methodsToLookFor = {"m1", "m2"};
+
+ public static void main(String[] args) throws Exception {
+ new NoDeadCodeGenerationOnTrySmtTest().run();
+ }
+
+ void run() throws Exception {
+ compileTestClass();
+ checkClassFile(new File(Paths.get(System.getProperty("user.dir"),
+ "Test.class").toUri()), methodsToLookFor);
+ }
+
+ void compileTestClass() throws Exception {
+ ToolBox.JavaToolArgs javacSuccessArgs =
+ new ToolBox.JavaToolArgs().setSources(testSource);
+ ToolBox.javac(javacSuccessArgs);
+ }
+
+ void checkClassFile(final File cfile, String[] methodsToFind) throws Exception {
+ ClassFile classFile = ClassFile.read(cfile);
+ int numberOfmethodsFound = 0;
+ for (String methodToFind : methodsToFind) {
+ for (Method method : classFile.methods) {
+ if (method.getName(classFile.constant_pool).equals(methodToFind)) {
+ numberOfmethodsFound++;
+ Code_attribute code = (Code_attribute) method.attributes.get("Code");
+ Assert.check(code.exception_table_langth == expectedExceptionTable.length,
+ "The ExceptionTable found has a length different to the expected one");
+ int i = 0;
+ for (Exception_data entry: code.exception_table) {
+ Assert.check(entry.start_pc == expectedExceptionTable[i][0] &&
+ entry.end_pc == expectedExceptionTable[i][1] &&
+ entry.handler_pc == expectedExceptionTable[i][2] &&
+ entry.catch_type == expectedExceptionTable[i][3],
+ "Exception table entry at pos " + i + " differ from expected.");
+ i++;
+ }
+ }
+ }
+ }
+ Assert.check(numberOfmethodsFound == 2, "Some seek methods were not found");
+ }
+
+ void error(String msg) {
+ throw new AssertionError(msg);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/T8024207/FlowCrashTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,23 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8024207
+ * @summary javac crash in Flow$AssignAnalyzer.visitIdent
+ * @compile/fail/ref=FlowCrashTest.out -XDrawDiagnostics FlowCrashTest.java
+ */
+
+import java.util.*;
+import java.util.stream.*;
+
+public class FlowCrashTest {
+ static class ViewId { }
+
+ public void crash() {
+
+ Map<ViewId,String> viewToProfile = null;
+ new TreeMap<>(viewToProfile.entrySet().stream()
+ .collect(Collectors.toMap((vid, prn) -> prn,
+ (vid, prn) -> Arrays.asList(vid),
+ (a, b) -> { a.addAll(b); return a; })));
+
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/T8024207/FlowCrashTest.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,2 @@
+FlowCrashTest.java:18:42: compiler.err.cant.apply.symbols: kindname.method, toMap, @475,@542,@624,{(compiler.misc.inapplicable.method: kindname.method, java.util.stream.Collectors, <T,K,U>toMap(java.util.function.Function<? super T,? extends K>,java.util.function.Function<? super T,? extends U>), (compiler.misc.infer.arg.length.mismatch: T,K,U)),(compiler.misc.inapplicable.method: kindname.method, java.util.stream.Collectors, <T,K,U>toMap(java.util.function.Function<? super T,? extends K>,java.util.function.Function<? super T,? extends U>,java.util.function.BinaryOperator<U>), (compiler.misc.infer.no.conforming.assignment.exists: T,K,U, (compiler.misc.incompatible.arg.types.in.lambda))),(compiler.misc.inapplicable.method: kindname.method, java.util.stream.Collectors, <T,K,U,M>toMap(java.util.function.Function<? super T,? extends K>,java.util.function.Function<? super T,? extends U>,java.util.function.BinaryOperator<U>,java.util.function.Supplier<M>), (compiler.misc.infer.arg.length.mismatch: T,K,U,M))}
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/T8024398/NPETryTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,49 @@
+/*
+ * 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. 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
+ * @bug 8024398
+ * @summary javac, compiler crashes with try with empty body
+ * @compile NPETryTest.java
+ */
+
+public class NPETryTest {
+ void m()
+ {
+ /* This is the statement provoking the error the rest are provided as
+ * additional tests
+ */
+ try {}
+ catch (Exception e) {}
+
+ try {}
+ catch (Exception e) {}
+ finally {}
+
+ try {}
+ finally {}
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/neg/NoDefault.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,9 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8022322
+ * @summary Default methods are not allowed in an annotation.
+ * @compile/fail/ref=NoDefault.out -XDrawDiagnostics NoDefault.java
+ */
+@interface NoDefault {
+ default int m() {return 0;}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/neg/NoDefault.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,3 @@
+NoDefault.java:8:17: compiler.err.mod.not.allowed.here: default
+NoDefault.java:8:21: compiler.err.intf.meth.cant.have.body
+2 errors
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/neg/NoDefaultAbstract.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,9 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8022322
+ * @summary Default methods are not allowed in an annotation.
+ * @compile/fail/ref=NoDefaultAbstract.out -XDrawDiagnostics NoDefaultAbstract.java
+ */
+@interface NoDefaultAbstract {
+ default int m();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/neg/NoDefaultAbstract.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,2 @@
+NoDefaultAbstract.java:8:17: compiler.err.mod.not.allowed.here: default
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/neg/NoStatic.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,10 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8022322
+ * @summary Static methods are not allowed in an annotation.
+ * @compile/fail/ref=NoStatic.out -XDrawDiagnostics NoStatic.java
+ */
+
+@interface NoStatic {
+ static int m() {return 0;}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/neg/NoStatic.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,3 @@
+NoStatic.java:9:16: compiler.err.mod.not.allowed.here: static
+NoStatic.java:9:20: compiler.err.intf.meth.cant.have.body
+2 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/neg/NoStaticAbstract.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,10 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8022322
+ * @summary Static methods are not allowed in an annotation.
+ * @compile/fail/ref=NoStaticAbstract.out -XDrawDiagnostics NoStaticAbstract.java
+ */
+
+@interface NoStaticAbstract {
+ static int m();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/neg/NoStaticAbstract.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,2 @@
+NoStaticAbstract.java:9:16: compiler.err.mod.not.allowed.here: static
+1 error
--- a/langtools/test/tools/javac/defaultMethods/ClassReaderTest/ClassReaderTest.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/ClassReaderTest/ClassReaderTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary check that default methods don't cause ClassReader to complete classes recursively
* @author Maurizio Cimadamore
* @compile pkg/Foo.java
--- a/langtools/test/tools/javac/defaultMethods/Neg01.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Neg01.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
-/*
- * @test /nodynamiccopyright/
+/* @test /nodynamiccopyright/
+ * @bug 7192246
* @summary negative test for ambiguous defaults
* @compile/fail/ref=Neg01.out -XDrawDiagnostics Neg01.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Neg02.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Neg02.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
-/*
- * @test /nodynamiccopyright/
+/* @test /nodynamiccopyright/
+ * @bug 7192246
* @summary check that ill-formed MI hierarchies do not compile
* @compile/fail/ref=Neg02.out -XDrawDiagnostics Neg02.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Neg03.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Neg03.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
-/*
- * @test /nodynamiccopyright/
+/* @test /nodynamiccopyright/
+ * @bug 7192246
* @summary check that re-abstraction works properly
* @compile/fail/ref=Neg03.out -XDrawDiagnostics Neg03.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Neg04.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Neg04.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
-/*
- * @test /nodynamiccopyright/
+/* @test /nodynamiccopyright/
+ * @bug 7192246
* @summary check that default method must have most specific return type
* @compile/fail/ref=Neg04.out -XDrawDiagnostics Neg04.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Neg05.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Neg05.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
-/*
- * @test /nodynamiccopyright/
+/* @test /nodynamiccopyright/
+ * @bug 7192246
* @summary check that abstract methods are compatible with inherited defaults
* @compile/fail/ref=Neg05.out -XDrawDiagnostics Neg05.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Neg06.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Neg06.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
-/*
- * @test /nodynamiccopyright/
+/* @test /nodynamiccopyright/
+ * @bug 7192246
* @summary flow analysis is not run on inlined default bodies
* @compile/fail/ref=Neg06.out -XDrawDiagnostics Neg06.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Neg07.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Neg07.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
-/*
- * @test /nodynamiccopyright/
+/* @test /nodynamiccopyright/
+ * @bug 7192246
* @summary check that default overrides are properly type-checked
* @compile/fail/ref=Neg07.out -XDrawDiagnostics Neg07.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Neg08.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Neg08.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
-/*
- * @test /nodynamiccopyright/
+/* @test /nodynamiccopyright/
+ * @bug 7192246
* @summary check that default overrides are properly type-checked
* @compile/fail/ref=Neg08.out -XDrawDiagnostics Neg08.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Neg09.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Neg09.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
-/*
- * @test /nodynamiccopyright/
+/* @test /nodynamiccopyright/
+ * @bug 7192246
* @summary check that default overrides are properly type-checked
* @compile/fail/ref=Neg09.out -Werror -Xlint:unchecked -XDrawDiagnostics Neg09.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Neg10.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Neg10.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
-/*
- * @test /nodynamiccopyright/
+/* @test /nodynamiccopyright/
+ * @bug 7192246
* @summary check that default overrides are properly type-checked
* @compile/fail/ref=Neg10.out -Werror -Xlint:unchecked -XDrawDiagnostics Neg10.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Neg11.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Neg11.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
-/*
- * @test /nodynamiccopyright/
+/* @test /nodynamiccopyright/
+ * @bug 7192246
* @summary check that default overrides are properly type-checked
* @compile/fail/ref=Neg11.out -XDrawDiagnostics Neg11.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Neg12.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Neg12.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
-/*
- * @test /nodynamiccopyright/
+/* @test /nodynamiccopyright/
+ * @bug 7192246
* @summary check that abstract methods are discarded in overload resolution diags
* @compile/fail/ref=Neg12.out -XDrawDiagnostics Neg12.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Neg13.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Neg13.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
-/*
- * @test /nodynamiccopyright/
+/* @test /nodynamiccopyright/
+ * @bug 7192246
* @summary check that default method overriding object members are flagged as error
* @compile/fail/ref=Neg13.out -XDrawDiagnostics Neg13.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Neg14.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Neg14.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
-/*
- * @test /nodynamiccopyright/
+/* @test /nodynamiccopyright/
+ * @bug 7192246
* @summary check that a class cannot have two sibling interfaces with a default and abstract method
* @compile/fail/ref=Neg14.out -XDrawDiagnostics Neg14.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Neg15.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Neg15.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
-/*
- * @test /nodynamiccopyright/
+/* @test /nodynamiccopyright/
+ * @bug 7192246
* @summary check that level skipping in default super calls is correctly rejected
* @compile/fail/ref=Neg15.out -XDrawDiagnostics Neg15.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Neg16.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Neg16.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
-/*
- * @test /nodynamiccopyright/
+/* @test /nodynamiccopyright/
+ * @bug 7192246
* @summary check that level skipping in default super calls is correctly rejected
* @compile/fail/ref=Neg16.out -XDrawDiagnostics Neg16.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Pos01.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Pos01.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary basic test for default methods
* @author Maurizio Cimadamore
*/
--- a/langtools/test/tools/javac/defaultMethods/Pos02.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Pos02.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary test for explicit resolution of ambiguous default methods
* @author Maurizio Cimadamore
* @compile Pos02.java
--- a/langtools/test/tools/javac/defaultMethods/Pos04.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Pos04.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary test for overriding with default method
* @author Maurizio Cimadamore
* @compile Pos04.java
--- a/langtools/test/tools/javac/defaultMethods/Pos05.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Pos05.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary check that indirectly inherited default methods are discovered during resolution
* @author Maurizio Cimadamore
* @compile Pos05.java
--- a/langtools/test/tools/javac/defaultMethods/Pos06.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Pos06.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary check that well-formed MI hierarchies behaves well w.r.t. method resolution (i.e. no ambiguities)
* @author Maurizio Cimadamore
* @compile Pos06.java
--- a/langtools/test/tools/javac/defaultMethods/Pos07.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Pos07.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary check that compilation order does not matter
* @author Maurizio Cimadamore
* @compile Pos07.java
--- a/langtools/test/tools/javac/defaultMethods/Pos08.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Pos08.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary check that common overrider solves default method conflicts
* @author Maurizio Cimadamore
* @compile Pos08.java
--- a/langtools/test/tools/javac/defaultMethods/Pos10.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Pos10.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary check that type-variables in generic extension decl can be accessed from default impl
* @author Maurizio Cimadamore
* @compile Pos10.java
--- a/langtools/test/tools/javac/defaultMethods/Pos11.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Pos11.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary complex test with conflict resolution via overriding
* @author Brian Goetz
* @compile Pos11.java
--- a/langtools/test/tools/javac/defaultMethods/Pos12.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Pos12.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary check that 'this' can be used from within an extension method
* @compile Pos12.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Pos13.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Pos13.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary qualified 'this' inside default method causes StackOverflowException
* @compile Pos13.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Pos14.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Pos14.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary check that overload resolution selects most specific signature
* @compile Pos14.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Pos15.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Pos15.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary check that overload resolution selects most specific signature
* @compile Pos15.java
*/
--- a/langtools/test/tools/javac/defaultMethods/Pos16.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/Pos16.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary 'class wins' should not short-circuit overload resolution
* @compile Pos16.java
*/
--- a/langtools/test/tools/javac/defaultMethods/TestDefaultBody.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/TestDefaultBody.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary check that code attributed for default methods is correctly generated
*/
--- a/langtools/test/tools/javac/defaultMethods/TestNoBridgeOnDefaults.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/TestNoBridgeOnDefaults.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary check that javac does not generate bridge methods for defaults
*/
--- a/langtools/test/tools/javac/defaultMethods/crossCompile/CrossCompile.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/crossCompile/CrossCompile.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary check that clinit in interface doesn't cause spurious default method diagnostics
* @compile -source 1.4 -target 1.4 Clinit.java
* @compile CrossCompile.java
--- a/langtools/test/tools/javac/defaultMethods/separate/Separate.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/separate/Separate.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
/*
* @test
+ * @bug 7192246
* @summary smoke test for separate compilation of default methods
* @author Maurizio Cimadamore
* @compile pkg1/A.java
--- a/langtools/test/tools/javac/defaultMethods/super/TestDefaultSuperCall.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/defaultMethods/super/TestDefaultSuperCall.java Sat Sep 14 20:43:34 2013 +0100
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8006694
+ * @bug 7192246 8006694
* @summary Automatic test for checking correctness of default super/this resolution
* temporarily workaround combo tests are causing time out in several platforms
* @library ../../lib
--- a/langtools/test/tools/javac/depDocComment/SuppressDeprecation.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/depDocComment/SuppressDeprecation.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,8 +1,8 @@
-SuppressDeprecation.java:130:17: compiler.warn.has.been.deprecated: X, compiler.misc.unnamed.package
SuppressDeprecation.java:82:10: compiler.warn.has.been.deprecated: g(), T
SuppressDeprecation.java:83:14: compiler.warn.has.been.deprecated: g(), T
SuppressDeprecation.java:84:9: compiler.warn.has.been.deprecated: var, T
SuppressDeprecation.java:87:9: compiler.warn.has.been.deprecated: T(), T
SuppressDeprecation.java:90:9: compiler.warn.has.been.deprecated: T(int), T
SuppressDeprecation.java:98:1: compiler.warn.has.been.deprecated: T(), T
+SuppressDeprecation.java:130:17: compiler.warn.has.been.deprecated: X, compiler.misc.unnamed.package
7 warnings
--- a/langtools/test/tools/javac/diags/examples/BadArgTypesInLambda.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/diags/examples/BadArgTypesInLambda.java Sat Sep 14 20:43:34 2013 +0100
@@ -21,9 +21,6 @@
* questions.
*/
-// key: compiler.err.cant.apply.symbol
-// key: compiler.misc.no.conforming.assignment.exists
-// key: compiler.misc.bad.arg.types.in.lambda
// key: compiler.err.prob.found.req
// key: compiler.misc.inconvertible.types
// options: -Xdiags:verbose
--- a/langtools/test/tools/javac/diags/examples/CyclicInference.java Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-// key: compiler.err.prob.found.req
-// key: compiler.misc.cyclic.inference
-
-class CyclicInference {
- interface SAM<X> {
- void m(X x);
- }
-
- <Z> void g(SAM<Z> sz) { }
-
- void test() {
- g(x-> {});
- }
-}
--- a/langtools/test/tools/javac/diags/examples/IncompatibleArgTypesInMethodRef.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/diags/examples/IncompatibleArgTypesInMethodRef.java Sat Sep 14 20:43:34 2013 +0100
@@ -31,6 +31,7 @@
}
void g(String s, Integer i) { }
+ void g(Integer i, String s) { }
<Z> void m(SAM<Z> s) { }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/MrefInferAndExplicitParams.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+// key: compiler.err.invalid.mref
+// key: compiler.misc.mref.infer.and.explicit.params
+
+public class MrefInferAndExplicitParams {
+ static class Foo<X> {}
+
+ interface Supplier<X> {
+ X make();
+ }
+
+ Supplier<Foo<String>> sfs = Foo::<Number>new;
+}
--- a/langtools/test/tools/javac/diags/examples/MrefStat.java.rej Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
---- MrefStat.java
-+++ MrefStat.java
-@@ -0,0 +1,31 @@
-+/*
-+ * 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.
-+ */
-+
-+// key: compiler.note.mref.stat
-+// options: -XDdumpLambdaToMethodStats
-+
-+class MrefStat {
-+ Runnable r = MrefStat::m;
-+
-+ static void m() { }
-+}
--- a/langtools/test/tools/javac/diags/examples/MrefStat1.java.rej Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
---- MrefStat1.java
-+++ MrefStat1.java
-@@ -0,0 +1,34 @@
-+/*
-+ * 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.
-+ */
-+
-+// key: compiler.note.mref.stat.1
-+// options: -XDdumpLambdaToMethodStats
-+
-+class MrefStat1 {
-+
-+ void m() { }
-+
-+ static class Sub extends MrefStat1 {
-+ Runnable r = super::m;
-+ }
-+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/PotentiallyAmbiguousOverload.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+// key: compiler.warn.potentially.ambiguous.overload
+// options: -Xlint:overloads
+
+class PotentiallyAmbiguousOverload {
+ interface F1 {
+ void m(String s);
+ }
+
+ interface F2 {
+ void m(Integer s);
+ }
+
+ void m(F1 f1) { }
+ void m(F2 f2) { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/flow/AliveRanges.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+import java.lang.annotation.*;
+
+@Repeatable(AliveRanges.class)
+@Target({ElementType.METHOD})
+@interface AliveRange {
+ String varName();
+ int bytecodeStart();
+ int bytecodeLength();
+}
+
+@Target({ElementType.METHOD})
+@interface AliveRanges {AliveRange[] value();}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/flow/LVTHarness.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,280 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 7047734
+ * @summary The LVT is not generated correctly during some try/catch scenarios
+ * @library /tools/javac/lib
+ * @build JavacTestingAbstractProcessor LVTHarness
+ * @run main LVTHarness
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+import com.sun.source.util.JavacTask;
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPool;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.Code_attribute;
+import com.sun.tools.classfile.ConstantPool.InvalidIndex;
+import com.sun.tools.classfile.ConstantPool.UnexpectedEntry;
+import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
+import com.sun.tools.classfile.LocalVariableTable_attribute;
+import com.sun.tools.classfile.Method;
+
+import static javax.tools.StandardLocation.*;
+import static com.sun.tools.classfile.LocalVariableTable_attribute.Entry;
+
+public class LVTHarness {
+
+ static int nerrors = 0;
+
+ static final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+ static final StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+
+ public static void main(String[] args) throws Exception {
+ fm.setLocation(SOURCE_PATH,
+ Arrays.asList(new File(System.getProperty("test.src"), "tests")));
+ for (JavaFileObject jfo : fm.list(SOURCE_PATH, "",
+ Collections.singleton(JavaFileObject.Kind.SOURCE), true)) {
+ new LVTHarness(jfo).check();
+ }
+ if (nerrors > 0) {
+ throw new AssertionError("Errors were found");
+ }
+ }
+
+
+ JavaFileObject jfo;
+ Map<ElementKey, AliveRanges> aliveRangeMap =
+ new HashMap<ElementKey, AliveRanges>();
+ Set<String> declaredKeys = new HashSet<>();
+ List<ElementKey> seenAliveRanges = new ArrayList<>();
+
+ protected LVTHarness(JavaFileObject jfo) {
+ this.jfo = jfo;
+ }
+
+ protected void check() throws Exception {
+ JavacTask ct = (JavacTask)comp.getTask(null, fm, null, Arrays.asList("-g"),
+ null, Arrays.asList(jfo));
+ System.err.println("compiling code " + jfo.toString());
+ ct.setProcessors(Collections.singleton(new AliveRangeFinder()));
+ if (!ct.call()) {
+ throw new AssertionError("Error during compilation");
+ }
+
+ checkClassFile(new File(jfo.getName().replace(".java", ".class")));
+
+ //check all candidates have been used up
+ for (Map.Entry<ElementKey, AliveRanges> entry : aliveRangeMap.entrySet()) {
+ if (!seenAliveRanges.contains(entry.getKey())) {
+ error("Redundant @AliveRanges annotation on method " +
+ entry.getKey().elem);
+ }
+ }
+ }
+
+ void checkClassFile(File file)
+ throws IOException, ConstantPoolException, InvalidDescriptor {
+ ClassFile classFile = ClassFile.read(file);
+ ConstantPool constantPool = classFile.constant_pool;
+
+ //lets get all the methods in the class file.
+ for (Method method : classFile.methods) {
+ for (ElementKey elementKey: aliveRangeMap.keySet()) {
+ String methodDesc = method.getName(constantPool) +
+ method.descriptor.getParameterTypes(constantPool);
+ if (methodDesc.equals(elementKey.elem.toString())) {
+ checkMethod(constantPool, method, aliveRangeMap.get(elementKey));
+ seenAliveRanges.add(elementKey);
+ }
+ }
+ }
+ }
+
+ void checkMethod(ConstantPool constantPool, Method method, AliveRanges ranges)
+ throws InvalidIndex, UnexpectedEntry {
+ Code_attribute code = (Code_attribute) method.attributes.get(Attribute.Code);
+ LocalVariableTable_attribute lvt =
+ (LocalVariableTable_attribute) (code.attributes.get(Attribute.LocalVariableTable));
+ List<String> infoFromRanges = convertToStringList(ranges);
+ List<String> infoFromLVT = convertToStringList(constantPool, lvt);
+
+ // infoFromRanges most be contained in infoFromLVT
+ int i = 0;
+ int j = 0;
+ while (i < infoFromRanges.size() && j < infoFromLVT.size()) {
+ int comparison = infoFromRanges.get(i).compareTo(infoFromLVT.get(j));
+ if (comparison == 0) {
+ i++; j++;
+ } else if (comparison > 0) {
+ j++;
+ } else {
+ break;
+ }
+ }
+
+ if (i < infoFromRanges.size()) {
+ error(infoFromLVT, infoFromRanges);
+ }
+ }
+
+ List<String> convertToStringList(AliveRanges ranges) {
+ List<String> result = new ArrayList<>();
+ for (Annotation anno : ranges.value()) {
+ AliveRange range = (AliveRange)anno;
+ String str = formatLocalVariableData(range.varName(),
+ range.bytecodeStart(), range.bytecodeLength());
+ result.add(str);
+ }
+ Collections.sort(result);
+ return result;
+ }
+
+ List<String> convertToStringList(ConstantPool constantPool,
+ LocalVariableTable_attribute lvt) throws InvalidIndex, UnexpectedEntry {
+ List<String> result = new ArrayList<>();
+ for (Entry entry : lvt.local_variable_table) {
+ String str = formatLocalVariableData(constantPool.getUTF8Value(entry.name_index),
+ entry.start_pc, entry.length);
+ result.add(str);
+ }
+ Collections.sort(result);
+ return result;
+ }
+
+ String formatLocalVariableData(String varName, int start, int length) {
+ StringBuilder sb = new StringBuilder()
+ .append("var name: ").append(varName)
+ .append(" start: ").append(start)
+ .append(" length: ").append(length);
+ return sb.toString();
+ }
+
+ protected void error(List<String> infoFromLVT, List<String> infoFromRanges) {
+ nerrors++;
+ System.err.printf("Error occurred while checking file: %s\n", jfo.getName());
+ System.err.println("The range info from the annotations is");
+ printStringListToErrOutput(infoFromRanges);
+ System.err.println();
+ System.err.println("And the range info from the class file is");
+ printStringListToErrOutput(infoFromLVT);
+ System.err.println();
+ }
+
+ void printStringListToErrOutput(List<String> list) {
+ for (String s : list) {
+ System.err.println("\t" + s);
+ }
+ }
+
+ protected void error(String msg) {
+ nerrors++;
+ System.err.printf("Error occurred while checking file: %s\nreason: %s\n",
+ jfo.getName(), msg);
+ }
+
+ class AliveRangeFinder extends JavacTestingAbstractProcessor {
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations,
+ RoundEnvironment roundEnv) {
+ if (roundEnv.processingOver())
+ return true;
+
+ TypeElement aliveRangeAnno = elements.getTypeElement("AliveRanges");
+
+ if (!annotations.contains(aliveRangeAnno)) {
+ error("no @AliveRanges annotation found in test class");
+ }
+
+ for (Element elem: roundEnv.getElementsAnnotatedWith(aliveRangeAnno)) {
+ Annotation annotation = elem.getAnnotation(AliveRanges.class);
+ aliveRangeMap.put(new ElementKey(elem), (AliveRanges)annotation);
+ }
+ return true;
+ }
+ }
+
+ class ElementKey {
+
+ String key;
+ Element elem;
+
+ public ElementKey(Element elem) {
+ this.elem = elem;
+ this.key = computeKey(elem);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof ElementKey) {
+ ElementKey other = (ElementKey)obj;
+ return other.key.equals(key);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return key.hashCode();
+ }
+
+ String computeKey(Element e) {
+ StringBuilder buf = new StringBuilder();
+ while (e != null) {
+ buf.append(e.toString());
+ e = e.getEnclosingElement();
+ }
+ buf.append(jfo.getName());
+ return buf.toString();
+ }
+
+ @Override
+ public String toString() {
+ return "Key{" + key + "}";
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/flow/tests/TestCaseConditional.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,16 @@
+/* /nodynamiccopyright/ */
+
+public class TestCaseConditional {
+
+ @AliveRange(varName="o", bytecodeStart=5, bytecodeLength=33)
+ @AliveRange(varName="oo", bytecodeStart=23, bytecodeLength=15)
+ void m(String[] args) {
+ Boolean o;
+ Boolean oo = ((o = Boolean.TRUE).booleanValue()) ?
+ o = Boolean.TRUE :
+ Boolean.FALSE;
+ oo.hashCode();
+ o = Boolean.FALSE;
+ o.hashCode();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/flow/tests/TestCaseDoLoop.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,15 @@
+/* /nodynamiccopyright/ */
+
+public class TestCaseDoLoop {
+
+ @AliveRange(varName="o", bytecodeStart=3, bytecodeLength=15)
+ @AliveRange(varName="args", bytecodeStart=0, bytecodeLength=18)
+ void m(String[] args) {
+ Object o;
+ do {
+ o = "";
+ o.hashCode();
+ } while (args[0] != null);
+ o = "";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/flow/tests/TestCaseFor.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,27 @@
+/* /nodynamiccopyright/ */
+
+public class TestCaseFor {
+
+ @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=8)
+ @AliveRange(varName="o", bytecodeStart=24, bytecodeLength=1)
+ void m1(String[] args) {
+ Object o;
+ for (int i = 0; i < 5; i++) {
+ o = "";
+ o.hashCode();
+ }
+ o = "";
+ }
+
+ @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=8)
+ @AliveRange(varName="o", bytecodeStart=24, bytecodeLength=1)
+ void m2(String[] args) {
+ Object o;
+ for (int i = 0; i < 5; i++) {
+ o = "";
+ o.hashCode();
+ continue;
+ }
+ o = "";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/flow/tests/TestCaseForEach.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,15 @@
+/* /nodynamiccopyright/ */
+
+public class TestCaseForEach {
+
+ @AliveRange(varName="o", bytecodeStart=25, bytecodeLength=8)
+ @AliveRange(varName="o", bytecodeStart=39, bytecodeLength=1)
+ void m(String[] args) {
+ Object o;
+ for (String s : args) {
+ o = "";
+ o.hashCode();
+ }
+ o = "";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/flow/tests/TestCaseIf.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,61 @@
+/* /nodynamiccopyright/ */
+
+public class TestCaseIf {
+
+ @AliveRange(varName="o", bytecodeStart=9, bytecodeLength=5)
+ @AliveRange(varName="o", bytecodeStart=17, bytecodeLength=1)
+ void m0(String[] args) {
+ Object o;
+ if (args[0] != null) {
+ o = "";
+ o.hashCode();
+ }
+ o = "";
+ }
+
+ @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=5)
+ @AliveRange(varName="o", bytecodeStart=18, bytecodeLength=1)
+ void m1() {
+ Object o;
+ int i = 5;
+ if (i == 5) {
+ o = "";
+ o.hashCode();
+ }
+ o = "";
+ }
+
+ @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=5)
+ @AliveRange(varName="o", bytecodeStart=18, bytecodeLength=1)
+ void m2() {
+ Object o;
+ int i = 5;
+ if (!(i == 5)) {
+ o = "";
+ o.hashCode();
+ }
+ o = "";
+ }
+
+ @AliveRange(varName="o", bytecodeStart=15, bytecodeLength=5)
+ @AliveRange(varName="o", bytecodeStart=23, bytecodeLength=1)
+ void m3(String[] args) {
+ Object o;
+ if (args[0] != null && args[1] != null) {
+ o = "";
+ o.hashCode();
+ }
+ o = "";
+ }
+
+ @AliveRange(varName="o", bytecodeStart=15, bytecodeLength=5)
+ @AliveRange(varName="o", bytecodeStart=23, bytecodeLength=1)
+ void m4(String[] args) {
+ Object o;
+ if (args[0] != null || args[1] != null) {
+ o = "";
+ o.hashCode();
+ }
+ o = "";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/flow/tests/TestCaseIfElse.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,48 @@
+/* /nodynamiccopyright/ */
+
+public class TestCaseIfElse {
+
+ @AliveRange(varName="o", bytecodeStart=9, bytecodeLength=8)
+ @AliveRange(varName="o", bytecodeStart=20, bytecodeLength=9)
+ void m0(String[] args) {
+ Object o;
+ if (args[0] != null) {
+ o = "then";
+ o.hashCode();
+ } else {
+ o = "else";
+ o.hashCode();
+ }
+ o = "finish";
+ }
+
+ @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=8)
+ @AliveRange(varName="o", bytecodeStart=21, bytecodeLength=9)
+ void m1() {
+ Object o;
+ int i = 5;
+ if (i == 5) {
+ o = "then";
+ o.hashCode();
+ } else {
+ o = "else";
+ o.hashCode();
+ }
+ o = "finish";
+ }
+
+ @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=8)
+ @AliveRange(varName="o", bytecodeStart=21, bytecodeLength=9)
+ void m2(String[] args) {
+ Object o;
+ int i = 5;
+ if (i != 5) {
+ o = "then";
+ o.hashCode();
+ } else {
+ o = "else";
+ o.hashCode();
+ }
+ o = "finish";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/flow/tests/TestCaseSwitch.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,73 @@
+/* /nodynamiccopyright/ */
+
+public class TestCaseSwitch {
+
+ @AliveRange(varName="o", bytecodeStart=31, bytecodeLength=16)
+ @AliveRange(varName="o", bytecodeStart=50, bytecodeLength=15)
+ @AliveRange(varName="o", bytecodeStart=68, bytecodeLength=1)
+ @AliveRange(varName="oo", bytecodeStart=39, bytecodeLength=26)
+ @AliveRange(varName="uu", bytecodeStart=59, bytecodeLength=6)
+ void m1(String[] args) {
+ Object o;
+ switch (args.length) {
+ case 0:
+ o = "0";
+ o.hashCode();
+ Object oo = "oo";
+ oo.hashCode();
+ break;
+ case 1:
+ o = "1";
+ o.hashCode();
+ Object uu = "uu";
+ uu.hashCode();
+ break;
+ }
+ o = "return";
+ }
+
+ @AliveRange(varName="o", bytecodeStart=95, bytecodeLength=18)
+ @AliveRange(varName="o", bytecodeStart=116, bytecodeLength=15)
+ @AliveRange(varName="o", bytecodeStart=134, bytecodeLength=1)
+ @AliveRange(varName="oo", bytecodeStart=104, bytecodeLength=27)
+ @AliveRange(varName="uu", bytecodeStart=125, bytecodeLength=6)
+ void m2(String[] args) {
+ Object o;
+ switch (args[0]) {
+ case "string0":
+ o = "0";
+ o.hashCode();
+ Object oo = "oo";
+ oo.hashCode();
+ break;
+ case "string1":
+ o = "1";
+ o.hashCode();
+ Object uu = "uu";
+ uu.hashCode();
+ break;
+ }
+ o = "return";
+ }
+
+ @AliveRange(varName="o", bytecodeStart=31, bytecodeLength=8)
+ @AliveRange(varName="o", bytecodeStart=42, bytecodeLength=8)
+ @AliveRange(varName="o", bytecodeStart=53, bytecodeLength=9)
+ void m3(String[] args) {
+ Object o;
+ switch (args.length) {
+ case 0:
+ o = "0";
+ o.hashCode();
+ break;
+ case 1:
+ o = "1";
+ o.hashCode();
+ break;
+ default:
+ o = "default";
+ o.hashCode();
+ }
+ o = "finish";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/flow/tests/TestCaseTry.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,76 @@
+/* /nodynamiccopyright/ */
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+
+public class TestCaseTry {
+
+ @AliveRange(varName="o", bytecodeStart=3, bytecodeLength=8)
+ @AliveRange(varName="o", bytecodeStart=15, bytecodeLength=1)
+ void m0(String[] args) {
+ Object o;
+ try {
+ o = "";
+ o.hashCode();
+ } catch (RuntimeException e) {}
+ o = "";
+ }
+
+ @AliveRange(varName="o", bytecodeStart=3, bytecodeLength=16)
+ @AliveRange(varName="o", bytecodeStart=23, bytecodeLength=23)
+ void m1() {
+ Object o;
+ try {
+ o = "";
+ o.hashCode();
+ } catch (RuntimeException e) {
+ }
+ finally {
+ o = "finally";
+ o.hashCode();
+ }
+ o = "";
+ }
+
+ @AliveRange(varName="o", bytecodeStart=3, bytecodeLength=16)
+ @AliveRange(varName="o", bytecodeStart=23, bytecodeLength=31)
+ void m2() {
+ Object o;
+ try {
+ o = "";
+ o.hashCode();
+ } catch (RuntimeException e) {
+ o = "catch";
+ o.hashCode();
+ }
+ finally {
+ o = "finally";
+ o.hashCode();
+ }
+ o = "";
+ }
+
+ @AliveRange(varName="o", bytecodeStart=22, bytecodeLength=38)
+ @AliveRange(varName="o", bytecodeStart=103, bytecodeLength=8)
+ void m3() {
+ Object o;
+ try (BufferedReader br =
+ new BufferedReader(new FileReader("aFile"))) {
+ o = "inside try";
+ o.hashCode();
+ } catch (Exception e) {}
+ o = "";
+ }
+
+ @AliveRange(varName="o", bytecodeStart=12, bytecodeLength=96)
+ @AliveRange(varName="o", bytecodeStart=112, bytecodeLength=1)
+ void m4() {
+ String o;
+ try (BufferedReader br =
+ new BufferedReader(new FileReader(o = "aFile"))) {
+ o = "inside try";
+ o.hashCode();
+ } catch (Exception e) {}
+ o = "";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/flow/tests/TestCaseWhile.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,15 @@
+/* /nodynamiccopyright/ */
+
+public class TestCaseWhile {
+
+ @AliveRange(varName="o", bytecodeStart=9, bytecodeLength=5)
+ @AliveRange(varName="o", bytecodeStart=20, bytecodeLength=1)
+ void m(String[] args) {
+ Object o;
+ while (args[0] != null) {
+ o = "";
+ o.hashCode();
+ }
+ o = "";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/neg/OrderedIntersections.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,21 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6962494
+ * @summary The order of elements of intersection types shouldn't matter
+ * @compile/fail/ref=OrderedIntersections.out -XDrawDiagnostics OrderedIntersections.java
+ */
+
+interface i1 {}
+interface i2 {}
+
+public class OrderedIntersections {
+ static <t1 extends i1 & i2> Object smf(t1 x) {
+ System.out.println( " smf1 " );
+ return null;
+ }
+
+ static <t2 extends i2 & i1> Object smf(t2 x) {
+ System.out.println( " smf2 " );
+ return null;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/neg/OrderedIntersections.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,2 @@
+OrderedIntersections.java:17:40: compiler.err.already.defined: kindname.method, <t1>smf(t1), kindname.class, OrderedIntersections
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8016177/T8016177a.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,45 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8016177 8016178
+ * @summary structural most specific and stuckness
+ * @compile/fail/ref=T8016177a.out -XDrawDiagnostics T8016177a.java
+ */
+import java.util.List;
+
+class T8016177a {
+
+ interface ToIntFunction<X> {
+ int m(X x);
+ }
+
+ interface Function<X, Y> {
+ Y m(X x);
+ }
+
+ <T,R> void m1(List<T> s, Function<T,R> f) { }
+ <T,R> void m1(List<T> s, ToIntFunction<T> f) { }
+
+ <T,R> List<R> m2(List<T> s, Function<T,R> f) { return null; }
+ <T,R> List<R> m2(List<T> s, ToIntFunction<T> f) { return null; }
+
+ <T,R> List<T> m3(List<T> s, Function<T,R> f) { return null; }
+ <T,R> List<R> m3(List<T> s, ToIntFunction<T> f) { return null; }
+
+ <T,R> List<T> m4(List<T> s, Function<T,R> f) { return null; }
+ <T,R> List<T> m4(List<T> s, ToIntFunction<T> f) { return null; }
+
+ <T,R> List<R> m5(List<T> s, Function<T,R> f) { return null; }
+ <T,R> List<T> m5(List<T> s, ToIntFunction<T> f) { return null; }
+
+ <T extends R,R> List<R> m6(List<T> s, Function<T,R> f) { return null; }
+ <T extends R,R> List<T> m6(List<T> s, ToIntFunction<T> f) { return null; }
+
+ void test(List<String> ss) {
+ m1(ss, s->s.length()); //ambiguous
+ m2(ss, s->s.length()); //ambiguous
+ m3(ss, s->s.length()); //ambiguous
+ m4(ss, s->s.length()); //ambiguous
+ m5(ss, s->s.length()); //ambiguous
+ m6(ss, s->s.length()); //ambiguous
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8016177/T8016177a.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,8 @@
+T8016177a.java:38:10: compiler.err.ref.ambiguous: m1, kindname.method, <T,R>m1(java.util.List<T>,T8016177a.Function<T,R>), T8016177a, kindname.method, <T,R>m1(java.util.List<T>,T8016177a.ToIntFunction<T>), T8016177a
+T8016177a.java:39:10: compiler.err.ref.ambiguous: m2, kindname.method, <T,R>m2(java.util.List<T>,T8016177a.Function<T,R>), T8016177a, kindname.method, <T,R>m2(java.util.List<T>,T8016177a.ToIntFunction<T>), T8016177a
+T8016177a.java:40:10: compiler.err.ref.ambiguous: m3, kindname.method, <T,R>m3(java.util.List<T>,T8016177a.Function<T,R>), T8016177a, kindname.method, <T,R>m3(java.util.List<T>,T8016177a.ToIntFunction<T>), T8016177a
+T8016177a.java:41:10: compiler.err.ref.ambiguous: m4, kindname.method, <T,R>m4(java.util.List<T>,T8016177a.Function<T,R>), T8016177a, kindname.method, <T,R>m4(java.util.List<T>,T8016177a.ToIntFunction<T>), T8016177a
+T8016177a.java:42:10: compiler.err.ref.ambiguous: m5, kindname.method, <T,R>m5(java.util.List<T>,T8016177a.Function<T,R>), T8016177a, kindname.method, <T,R>m5(java.util.List<T>,T8016177a.ToIntFunction<T>), T8016177a
+T8016177a.java:43:10: compiler.err.ref.ambiguous: m6, kindname.method, <T,R>m6(java.util.List<T>,T8016177a.Function<T,R>), T8016177a, kindname.method, <T,R>m6(java.util.List<T>,T8016177a.ToIntFunction<T>), T8016177a
+T8016177a.java:43:12: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: T,R, (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: int, java.lang.String)))
+7 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8016177/T8016177b.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,34 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8016177 8016178
+ * @summary structural most specific and stuckness
+ * @compile/fail/ref=T8016177b.out -XDrawDiagnostics T8016177b.java
+ */
+class T8016177b {
+ interface ToIntFunction<X> {
+ int m(X x);
+ }
+
+ interface Function<X, Y> {
+ Y m(X x);
+ }
+
+ <U, V> Function<U, V> id(Function<U, V> arg) { return null; }
+
+ <U, V> Function<U, V> id2(Function<U, V> arg) { return null; }
+ <U> ToIntFunction<U> id2(ToIntFunction<U> arg) { return null; }
+
+
+ <X,Y,Z> X f(Y arg, Function<Y, Z> f) { return null; }
+
+ <X,Y,Z> X f2(Y arg, Function<Y, Z> f) { return null; }
+ <X,Y> X f2(Y arg, ToIntFunction<Y> f) { return null; }
+
+ <T> T g(T arg) { return null; }
+
+ void test() {
+ g(f("hi", id(x->1))); //ok
+ g(f("hi", id2(x->1))); //ambiguous
+ g(f2("hi", id(x->1))); //ok
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8016177/T8016177b.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,2 @@
+T8016177b.java:31:19: compiler.err.ref.ambiguous: id2, kindname.method, <U,V>id2(T8016177b.Function<U,V>), T8016177b, kindname.method, <U>id2(T8016177b.ToIntFunction<U>), T8016177b
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8016177/T8016177c.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,47 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8016081 8016178
+ * @summary structural most specific and stuckness
+ * @compile/fail/ref=T8016177c.out -XDrawDiagnostics T8016177c.java
+ */
+
+class T8016177c {
+
+ interface Function<X, Y> {
+ Y m(X x);
+ }
+
+ interface ExtFunction<X, Y> extends Function<X, Y> { }
+
+ <U, V> U m1(Function<U, V> f) { return null; }
+ <U, V> U m1(ExtFunction<U, V> f) { return null; }
+
+ void m2(Function<Integer, Integer> f) { }
+ void m2(ExtFunction<Integer, Integer> f) { }
+
+ void m3(Function<Integer, Integer> f) { }
+ void m3(ExtFunction<Object, Integer> f) { }
+
+ int g1(Object s) { return 1; }
+
+ int g2(Number s) { return 1; }
+ int g2(Object s) { return 1; }
+
+ void test() {
+ m1((Integer x)->x); //ok - explicit lambda - subtyping picks most specific
+ m2((Integer x)->x); //ok - explicit lambda - subtyping picks most specific
+ m3((Integer x)->x); //ok - explicit lambda (only one applicable)
+
+ m1(x->1); //ok - stuck lambda but nominal most specific wins
+ m2(x->1); //ok - stuck lambda but nominal most specific wins
+ m3(x->1); //ambiguous - implicit lambda & different params
+
+ m1(this::g1); //ok - unambiguous ref - subtyping picks most specific
+ m2(this::g1); //ok - unambiguous ref - subtyping picks most specific
+ m3(this::g1); //ambiguous - both applicable, neither most specific
+
+ m1(this::g2); //ok - stuck mref but nominal most specific wins
+ m2(this::g2); //ok - stuck mref but nominal most specific wins
+ m3(this::g2); //ambiguous - different params
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8016177/T8016177c.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,4 @@
+T8016177c.java:37:9: compiler.err.ref.ambiguous: m3, kindname.method, m3(T8016177c.Function<java.lang.Integer,java.lang.Integer>), T8016177c, kindname.method, m3(T8016177c.ExtFunction<java.lang.Object,java.lang.Integer>), T8016177c
+T8016177c.java:41:9: compiler.err.ref.ambiguous: m3, kindname.method, m3(T8016177c.Function<java.lang.Integer,java.lang.Integer>), T8016177c, kindname.method, m3(T8016177c.ExtFunction<java.lang.Object,java.lang.Integer>), T8016177c
+T8016177c.java:45:9: compiler.err.ref.ambiguous: m3, kindname.method, m3(T8016177c.Function<java.lang.Integer,java.lang.Integer>), T8016177c, kindname.method, m3(T8016177c.ExtFunction<java.lang.Object,java.lang.Integer>), T8016177c
+3 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8016177/T8016177d.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8016081 8016178
+ * @summary structural most specific and stuckness
+ * @compile T8016177d.java
+ */
+import java.util.*;
+
+class T8016177d {
+
+ interface UnaryOperator<X> {
+ X m(X x);
+ }
+
+ interface IntStream {
+ IntStream sorted();
+ IntStream distinct();
+ IntStream limit(int i);
+ }
+
+ abstract class WrappingUnaryOperator<S> implements UnaryOperator<S> { }
+
+ <S1> WrappingUnaryOperator<S1> wrap1(UnaryOperator<S1> uo) { return null; }
+ <S2> WrappingUnaryOperator<S2> wrap2(UnaryOperator<S2> uo) { return null; }
+ <S3> WrappingUnaryOperator<S3> wrap3(UnaryOperator<S3> uo) { return null; }
+
+ <P> List<List<P>> perm(List<P> l) { return null; }
+
+ List<List<WrappingUnaryOperator<IntStream>>> intPermutationOfFunctions =
+ perm(Arrays.asList(
+ wrap1(s -> s.sorted()),
+ wrap2(s -> s.distinct()),
+ wrap3(s -> s.limit(5))
+ ));
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8016177/T8016177e.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8016081 8016178
+ * @summary structural most specific and stuckness
+ * @compile T8016177e.java
+ */
+import java.util.*;
+
+class T8016177e {
+
+ interface TerminalOp<X, Y> { }
+
+ interface Consumer<X> {
+ void m(X x);
+ }
+
+ <T> TerminalOp<T, Void> makeRef(Consumer<? super T> action) { return null; }
+
+ <T> void test() {
+ Map<T, Boolean> map = null;
+ TerminalOp<T, Void> forEachOp = makeRef(t -> { map.put(t, null); });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8016177/T8016177f.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8016081 8016178
+ * @summary structural most specific and stuckness
+ * @compile T8016177f.java
+ */
+import java.util.*;
+
+class T8016177f {
+
+ interface Function<S, T> {
+ T apply(S s);
+ }
+
+ interface IntFunction<T> {
+ T apply(int s);
+ }
+
+
+ interface BiConsumer<X,Y> {
+ void m(X x, Y y);
+ }
+
+ interface Consumer<X> {
+ void m(X x);
+ }
+
+ interface Supplier<X> {
+ X make();
+ }
+
+ interface TestData<T, S extends BaseStream<T, S>> {
+ interface OfRef<T> extends TestData<T, Stream<T>> { }
+ interface OfDouble extends TestData<Double, DoubleStream> { }
+ }
+
+ interface BaseStream<T, S extends BaseStream<T, S>> { }
+
+ interface Stream<T> extends BaseStream<T, Stream<T>> {
+ <M> Stream<M> map(Function<T, M> s);
+ <R> R collect(Supplier<R> resultFactory, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);
+ <Z> Z[] toArray(IntFunction<Z[]> s);
+ }
+
+ interface DoubleStream extends BaseStream<Double, DoubleStream> {
+ DoubleStream filter(DoublePredicate dp);
+ double[] toArray();
+ }
+
+ interface DoublePredicate {
+ boolean p(double d);
+ }
+
+ <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 null; }
+
+ <O> TestData.OfRef<O> ofCollection(Collection<O> collection) { return null; }
+
+ void test1(TestData.OfDouble data, DoublePredicate dp) {
+ exerciseTerminalOps(data, s -> s.filter(dp), s -> s.toArray());
+ }
+
+ void test2(Function<Double, Integer> fdi, TestData.OfRef<Double> td, Stream<Integer> si) {
+ exerciseTerminalOps(
+ ofCollection((List<Double>)null),
+ s -> s.map(fdi),
+ s -> s.toArray(Integer[]::new));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8016177/T8016177g.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,37 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8016081 8016178
+ * @summary structural most specific and stuckness
+ * @compile/fail/ref=T8016177g.out -XDrawDiagnostics T8016177g.java
+ */
+
+
+class Test {
+
+ interface Function<X, Y> {
+ Y m(X x);
+ }
+
+ interface Box<T> {
+ T get();
+ <R> R map(Function<T,R> f);
+ }
+
+ static class Person {
+ Person(String name) { }
+ }
+
+ void print(Object arg) { }
+ void print(String arg) { }
+
+ int abs(int a) { return 0; }
+ long abs(long a) { return 0; }
+ float abs(float a) { return 0; }
+ double abs(double a) { return 0; }
+
+ void test() {
+ Box<String> b = null;
+ print(b.map(s -> new Person(s)));
+ int i = abs(b.map(s -> Double.valueOf(s)));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8016177/T8016177g.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,2 @@
+T8016177g.java:35:20: compiler.err.prob.found.req: (compiler.misc.possible.loss.of.precision: double, int)
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8023389/T8023389.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8023389
+ * @summary Javac fails to infer type for lambda used with intersection type and wildcards
+ * @compile T8023389.java
+ */
+public class T8023389 {
+
+ static class U1 {}
+ static class X1 extends U1 {}
+
+ interface I { }
+
+ interface SAM<T> {
+ void m(T t);
+ }
+
+ /* Strictly speaking only the second of the following declarations provokes the bug.
+ * But the first line is also a useful test case.
+ */
+ SAM<? extends U1> sam1 = (SAM<? extends U1>) (X1 x) -> { };
+ SAM<? extends U1> sam2 = (SAM<? extends U1> & I) (X1 x) -> { };
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8023549/T8023549.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,27 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8023549
+ * @summary Compiler emitting spurious errors when constructor reference type is inferred and explicit type arguments are supplied
+ * @compile/fail/ref=T8023549.out -XDrawDiagnostics T8023549.java
+ */
+
+public class T8023549 {
+ static class Foo<X> { }
+
+ interface Supplier<X> {
+ X make();
+ }
+
+ interface ExtSupplier<X> extends Supplier<X> { }
+
+ void m1(Supplier<Foo<String>> sfs) { }
+
+ void m2(Supplier<Foo<String>> sfs) { }
+ void m2(ExtSupplier<Foo<Integer>> sfs) { }
+
+ void test() {
+ Supplier<Foo<String>> sfs = Foo::<Number>new;
+ m1(Foo::<Number>new);
+ m2(Foo::<Number>new);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8023549/T8023549.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,5 @@
+T8023549.java:23:37: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.mref.infer.and.explicit.params)
+T8023549.java:24:12: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.mref.infer.and.explicit.params)
+T8023549.java:25:9: compiler.err.ref.ambiguous: m2, kindname.method, m2(T8023549.Supplier<T8023549.Foo<java.lang.String>>), T8023549, kindname.method, m2(T8023549.ExtSupplier<T8023549.Foo<java.lang.Integer>>), T8023549
+T8023549.java:25:12: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.mref.infer.and.explicit.params)
+4 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8023558/T8023558a.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8023558
+ * @summary Javac creates invalid bootstrap methods for complex lambda/methodref case
+ */
+public class T8023558a {
+ interface SAM<T> {
+ T get();
+ }
+
+ public static void main(String[] args) {
+ SAM<SAM> sam = new SAM<SAM>() { public SAM get() { return null; } };
+ SAM temp = sam.get()::get;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8023558/T8023558b.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8023558
+ * @summary Javac creates invalid bootstrap methods for complex lambda/methodref case
+ */
+public class T8023558b {
+
+ interface Supplier<X> {
+ X get();
+ }
+
+ static class A {
+ public A(Supplier<B> supplier) { }
+ }
+
+ static class B { }
+
+ static class C {
+ public B getB() {
+ return new B();
+ }
+ }
+
+ public static void main(String[] args) {
+ new T8023558b().test(T8023558b::getC);
+ }
+
+ private static C getC() {
+ return new C();
+ }
+
+ public void test(Supplier<C> supplier) {
+ new A(supplier.get()::getB);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8023558/T8023558c.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8023558
+ * @summary Javac creates invalid bootstrap methods for complex lambda/methodref case
+ */
+
+interface SAM<T> {
+ T get();
+}
+
+public class T8023558c {
+ public static void main(String[] args) {
+ SAM<SAM> sam = () -> Object::new;
+ SAM temp = sam.get()::get;
+ }
+}
--- a/langtools/test/tools/javac/lambda/BadRecovery.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/BadRecovery.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,2 +1,3 @@
+BadRecovery.java:17:9: compiler.err.cant.apply.symbol: kindname.method, m, BadRecovery.SAM1, @369, kindname.class, BadRecovery, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.arg.types.in.lambda))
BadRecovery.java:17:77: compiler.err.cant.resolve.location: kindname.variable, f, , , (compiler.misc.location: kindname.class, BadRecovery, null)
-1 error
+2 errors
--- a/langtools/test/tools/javac/lambda/EffectivelyFinalTest.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/EffectivelyFinalTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,6 +1,6 @@
/*
* @test /nodynamiccopyright/
- * @bug 8003280
+ * @bug 7175538 8003280
* @summary Add lambda tests
* Integrate effectively final check with DA/DU analysis
* @compile/fail/ref=EffectivelyFinalTest01.out -XDrawDiagnostics EffectivelyFinalTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/EffectivelyFinalThrows.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,25 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8019521
+ * @summary Check that enhanced rethrow/effectivelly final works correctly inside lambdas
+ * @compile EffectivelyFinalThrows.java
+ */
+
+class EffectivelyFinalThrows {
+ interface SAM<E extends Throwable> {
+ public void t() throws E;
+ }
+ <E extends Throwable> void test(SAM<E> s) throws E {
+ s.t();
+ }
+ void test2(SAM<Checked> s) throws Checked {
+ test(() -> {
+ try {
+ s.t();
+ } catch (Throwable t) {
+ throw t;
+ }
+ });
+ }
+ static class Checked extends Exception {}
+}
--- a/langtools/test/tools/javac/lambda/ErroneousLambdaExpr.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/ErroneousLambdaExpr.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -26,6 +26,7 @@
* @bug 8003280
* @summary Add lambda tests
* stale state after speculative attribution round leads to missing classfiles
+ * @compile/fail/ref=ErroneousLambdaExpr.out -XDrawDiagnostics ErroneousLambdaExpr.java
*/
public class ErroneousLambdaExpr<T> {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/ErroneousLambdaExpr.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,2 @@
+ErroneousLambdaExpr.java:63:13: compiler.err.ref.ambiguous: call, kindname.method, call(ErroneousLambdaExpr.SAM1<T>), ErroneousLambdaExpr, kindname.method, call(ErroneousLambdaExpr.SAM2), ErroneousLambdaExpr
+1 error
--- a/langtools/test/tools/javac/lambda/MethodReference22.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/MethodReference22.out Sat Sep 14 20:43:34 2013 +0100
@@ -3,13 +3,17 @@
MethodReference22.java:46:19: compiler.err.invalid.mref: kindname.method, (compiler.misc.non-static.cant.be.ref: kindname.method, m4(java.lang.String))
MethodReference22.java:47:15: compiler.err.invalid.mref: kindname.method, (compiler.misc.non-static.cant.be.ref: kindname.method, m4(java.lang.String))
MethodReference22.java:51:19: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.ref.ambiguous: m1, kindname.method, m1(MethodReference22,java.lang.String), MethodReference22, kindname.method, m1(java.lang.String), MethodReference22))
-MethodReference22.java:52:9: compiler.err.cant.apply.symbol: kindname.method, call2, MethodReference22.SAM2, @1401, kindname.class, MethodReference22, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.ref.ambiguous: m1, kindname.method, m1(MethodReference22,java.lang.String), MethodReference22, kindname.method, m1(java.lang.String), MethodReference22)))
+MethodReference22.java:52:14: compiler.err.cant.apply.symbol: kindname.method, call2, MethodReference22.SAM2, @1401, kindname.class, MethodReference22, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.ref.ambiguous: m1, kindname.method, m1(MethodReference22,java.lang.String), MethodReference22, kindname.method, m1(java.lang.String), MethodReference22)))
MethodReference22.java:53:19: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.ref.ambiguous: m2, kindname.method, m2(MethodReference22,java.lang.String), MethodReference22, kindname.method, m2(java.lang.String), MethodReference22))
-MethodReference22.java:54:9: compiler.err.cant.apply.symbol: kindname.method, call2, MethodReference22.SAM2, @1504, kindname.class, MethodReference22, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.ref.ambiguous: m2, kindname.method, m2(MethodReference22,java.lang.String), MethodReference22, kindname.method, m2(java.lang.String), MethodReference22)))
+MethodReference22.java:54:14: compiler.err.cant.apply.symbol: kindname.method, call2, MethodReference22.SAM2, @1504, kindname.class, MethodReference22, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.ref.ambiguous: m2, kindname.method, m2(MethodReference22,java.lang.String), MethodReference22, kindname.method, m2(java.lang.String), MethodReference22)))
MethodReference22.java:55:19: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.ref.ambiguous: m3, kindname.method, m3(MethodReference22,java.lang.String), MethodReference22, kindname.method, m3(java.lang.String), MethodReference22))
-MethodReference22.java:56:9: compiler.err.cant.apply.symbol: kindname.method, call2, MethodReference22.SAM2, @1607, kindname.class, MethodReference22, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.ref.ambiguous: m3, kindname.method, m3(MethodReference22,java.lang.String), MethodReference22, kindname.method, m3(java.lang.String), MethodReference22)))
+MethodReference22.java:56:14: compiler.err.cant.apply.symbol: kindname.method, call2, MethodReference22.SAM2, @1607, kindname.class, MethodReference22, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.ref.ambiguous: m3, kindname.method, m3(MethodReference22,java.lang.String), MethodReference22, kindname.method, m3(java.lang.String), MethodReference22)))
MethodReference22.java:57:19: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.ref.ambiguous: m4, kindname.method, m4(MethodReference22,java.lang.String), MethodReference22, kindname.method, m4(java.lang.String), MethodReference22))
-MethodReference22.java:58:9: compiler.err.cant.apply.symbol: kindname.method, call2, MethodReference22.SAM2, @1710, kindname.class, MethodReference22, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.ref.ambiguous: m4, kindname.method, m4(MethodReference22,java.lang.String), MethodReference22, kindname.method, m4(java.lang.String), MethodReference22)))
+MethodReference22.java:58:14: compiler.err.cant.apply.symbol: kindname.method, call2, MethodReference22.SAM2, @1710, kindname.class, MethodReference22, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.ref.ambiguous: m4, kindname.method, m4(MethodReference22,java.lang.String), MethodReference22, kindname.method, m4(java.lang.String), MethodReference22)))
+MethodReference22.java:62:9: compiler.err.ref.ambiguous: call3, kindname.method, call3(MethodReference22.SAM1), MethodReference22, kindname.method, call3(MethodReference22.SAM2), MethodReference22
MethodReference22.java:62:15: compiler.err.invalid.mref: kindname.method, (compiler.misc.non-static.cant.be.ref: kindname.method, m1(java.lang.String))
+MethodReference22.java:63:9: compiler.err.ref.ambiguous: call3, kindname.method, call3(MethodReference22.SAM1), MethodReference22, kindname.method, call3(MethodReference22.SAM2), MethodReference22
+MethodReference22.java:64:9: compiler.err.ref.ambiguous: call3, kindname.method, call3(MethodReference22.SAM1), MethodReference22, kindname.method, call3(MethodReference22.SAM2), MethodReference22
+MethodReference22.java:65:9: compiler.err.ref.ambiguous: call3, kindname.method, call3(MethodReference22.SAM1), MethodReference22, kindname.method, call3(MethodReference22.SAM2), MethodReference22
MethodReference22.java:65:15: compiler.err.invalid.mref: kindname.method, (compiler.misc.non-static.cant.be.ref: kindname.method, m4(java.lang.String))
-14 errors
+18 errors
--- a/langtools/test/tools/javac/lambda/MethodReference23.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/MethodReference23.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,6 +1,6 @@
MethodReference23.java:52:19: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner1, MethodReference23, MethodReference23))
-MethodReference23.java:53:9: compiler.err.cant.apply.symbol: kindname.method, call11, MethodReference23.SAM11, @1140, kindname.class, MethodReference23, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner1, MethodReference23, MethodReference23)))
+MethodReference23.java:53:15: compiler.err.cant.apply.symbol: kindname.method, call11, MethodReference23.SAM11, @1140, kindname.class, MethodReference23, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner1, MethodReference23, MethodReference23)))
MethodReference23.java:57:19: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner1, , MethodReference23))
-MethodReference23.java:58:9: compiler.err.cant.apply.symbol: kindname.method, call12, MethodReference23.SAM12, @1282, kindname.class, MethodReference23, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner1, , MethodReference23)))
+MethodReference23.java:58:15: compiler.err.cant.apply.symbol: kindname.method, call12, MethodReference23.SAM12, @1282, kindname.class, MethodReference23, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner1, , MethodReference23)))
MethodReference23.java:72:9: compiler.err.ref.ambiguous: call3, kindname.method, call3(MethodReference23.SAM21), MethodReference23, kindname.method, call3(MethodReference23.SAM22), MethodReference23
5 errors
--- a/langtools/test/tools/javac/lambda/MethodReference41.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/MethodReference41.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,42 +1,12 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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
+ * @test /nodynamiccopyright/
* @bug 8003280
* @summary Add lambda tests
* check that diamond inference is applied when using raw constructor reference qualifier
- * @run main MethodReference41
+ * @compile/fail/ref=MethodReference41.out -XDrawDiagnostics MethodReference41.java
*/
-public class MethodReference41 {
-
- static int assertionCount = 0;
- static void assertTrue(boolean cond) {
- assertionCount++;
- if (!cond)
- throw new AssertionError();
- }
+public class MethodReference41 {
interface SAM1 {
void m(String s);
@@ -54,13 +24,20 @@
Foo(X x) { }
}
+ static void m1(SAM1 s) { }
- static void m(SAM1 s) { assertTrue(false); }
- static void m(SAM2 s) { assertTrue(true); }
- static void m(SAM3 s) { assertTrue(false); }
+ static void m2(SAM2 s) { }
+
+ static void m3(SAM3 s) { }
+
+ static void m4(SAM1 s) { }
+ static void m4(SAM2 s) { }
+ static void m4(SAM3 s) { }
public static void main(String[] args) {
- m(Foo::new);
- assertTrue(assertionCount == 1);
+ m1(Foo::new);
+ m2(Foo::new);
+ m3(Foo::new);
+ m4(Foo::new);
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference41.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,4 @@
+MethodReference41.java:38:11: compiler.err.cant.apply.symbol: kindname.method, m1, MethodReference41.SAM1, @767, kindname.class, MethodReference41, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Foo, java.lang.Number, java.lang.String, kindname.class, MethodReference41.Foo<X>, (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.String, java.lang.Number))))
+MethodReference41.java:40:11: compiler.err.cant.apply.symbol: kindname.method, m3, MethodReference41.SAM3, @811, kindname.class, MethodReference41, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Foo, java.lang.Number, java.lang.Object, kindname.class, MethodReference41.Foo<X>, (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Object, java.lang.Number))))
+MethodReference41.java:41:9: compiler.err.ref.ambiguous: m4, kindname.method, m4(MethodReference41.SAM2), MethodReference41, kindname.method, m4(MethodReference41.SAM3), MethodReference41
+3 errors
--- a/langtools/test/tools/javac/lambda/MethodReference42.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/MethodReference42.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,42 +1,12 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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
+ * @test /nodynamiccopyright/
* @bug 8003280
* @summary Add lambda tests
* check that diamond inference is applied when using raw constructor reference qualifier
- * @run main MethodReference42
+ * @compile/fail/ref=MethodReference42.out -XDrawDiagnostics MethodReference42.java
*/
-public class MethodReference42 {
-
- static int assertionCount = 0;
- static void assertTrue(boolean cond) {
- assertionCount++;
- if (!cond)
- throw new AssertionError();
- }
+public class MethodReference42 {
static class SuperFoo<X> { }
@@ -54,12 +24,20 @@
SuperFoo<Object> m();
}
- static void m(SAM1 s) { assertTrue(false); }
- static void m(SAM2 s) { assertTrue(true); }
- static void m(SAM3 s) { assertTrue(false); }
+ static void m1(SAM1 s) { }
+
+ static void m2(SAM2 s) { }
+
+ static void m3(SAM3 s) { }
+
+ static void m4(SAM1 s) { }
+ static void m4(SAM2 s) { }
+ static void m4(SAM3 s) { }
public static void main(String[] args) {
- m(Foo::new);
- assertTrue(assertionCount == 1);
+ m1(Foo::new);
+ m2(Foo::new);
+ m3(Foo::new);
+ m4(Foo::new);
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference42.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,4 @@
+MethodReference42.java:38:11: compiler.err.cant.apply.symbol: kindname.method, m1, MethodReference42.SAM1, @811, kindname.class, MethodReference42, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.eq.upper.bounds: X, java.lang.String, java.lang.Number))
+MethodReference42.java:40:11: compiler.err.cant.apply.symbol: kindname.method, m3, MethodReference42.SAM3, @855, kindname.class, MethodReference42, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.eq.upper.bounds: X, java.lang.Object, java.lang.Number))
+MethodReference42.java:41:9: compiler.err.ref.ambiguous: m4, kindname.method, m4(MethodReference42.SAM2), MethodReference42, kindname.method, m4(MethodReference42.SAM3), MethodReference42
+3 errors
--- a/langtools/test/tools/javac/lambda/MethodReference43.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/MethodReference43.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,42 +1,12 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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
+ * @test /nodynamiccopyright/
* @bug 8003280
* @summary Add lambda tests
* check that diamond inference is applied when using raw constructor reference qualifier
- * @run main MethodReference43
+ * @compile/fail/ref=MethodReference43.out -XDrawDiagnostics MethodReference43.java
*/
-public class MethodReference43 {
-
- static int assertionCount = 0;
- static void assertTrue(boolean cond) {
- assertionCount++;
- if (!cond)
- throw new AssertionError();
- }
+public class MethodReference43 {
interface SAM1 {
Foo<?> m(String s);
@@ -58,14 +28,24 @@
Foo(X x) { }
}
+ static void m1(SAM1 s) { }
- static void m(SAM1 s) { assertTrue(false); }
- static void m(SAM2 s) { assertTrue(false); }
- static void m(SAM3 s) { assertTrue(false); }
- static void m(SAM4 s) { assertTrue(true); }
+ static void m2(SAM2 s) { }
+
+ static void m3(SAM3 s) { }
+
+ static void m4(SAM4 s) { }
+
+ static void m5(SAM1 s) { }
+ static void m5(SAM2 s) { }
+ static void m5(SAM3 s) { }
+ static void m5(SAM4 s) { }
public static void main(String[] args) {
- m(Foo::new);
- assertTrue(assertionCount == 1);
+ m1(Foo::new);
+ m2(Foo::new);
+ m3(Foo::new);
+ m4(Foo::new);
+ m5(Foo::new);
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference43.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,5 @@
+MethodReference43.java:45:11: compiler.err.cant.apply.symbol: kindname.method, m1, MethodReference43.SAM1, @897, kindname.class, MethodReference43, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Foo, java.lang.Number, java.lang.String, kindname.class, MethodReference43.Foo<X>, (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.String, java.lang.Number))))
+MethodReference43.java:47:11: compiler.err.cant.apply.symbol: kindname.method, m3, MethodReference43.SAM3, @941, kindname.class, MethodReference43, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Foo, java.lang.Number, java.lang.Object, kindname.class, MethodReference43.Foo<X>, (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Object, java.lang.Number))))
+MethodReference43.java:49:9: compiler.err.ref.ambiguous: m5, kindname.method, m5(MethodReference43.SAM3), MethodReference43, kindname.method, m5(MethodReference43.SAM4), MethodReference43
+MethodReference43.java:49:11: compiler.err.cant.apply.symbol: kindname.method, m5, MethodReference43.SAM3, @985, kindname.class, MethodReference43, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Foo, java.lang.Number, java.lang.Object, kindname.class, MethodReference43.Foo<X>, (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Object, java.lang.Number))))
+4 errors
--- a/langtools/test/tools/javac/lambda/MethodReference44.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/MethodReference44.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,42 +1,12 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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
+ * @test /nodynamiccopyright/
* @bug 8003280
* @summary Add lambda tests
* check that generic method reference is inferred when type parameters are omitted
- * @run main MethodReference44
+ * @compile/fail/ref=MethodReference44.out -XDrawDiagnostics MethodReference44.java
*/
-public class MethodReference44 {
-
- static int assertionCount = 0;
- static void assertTrue(boolean cond) {
- assertionCount++;
- if (!cond)
- throw new AssertionError();
- }
+public class MethodReference44 {
static class SuperFoo<X> { }
@@ -56,12 +26,20 @@
static <X extends Number> Foo<X> m() { return null; }
- static void g(SAM1 s) { assertTrue(false); }
- static void g(SAM2 s) { assertTrue(true); }
- static void g(SAM3 s) { assertTrue(false); }
+ static void g1(SAM1 s) { }
+
+ static void g2(SAM2 s) { }
+
+ static void g3(SAM3 s) { }
+
+ static void g4(SAM1 s) { }
+ static void g4(SAM2 s) { }
+ static void g4(SAM3 s) { }
public static void main(String[] args) {
- g(MethodReference44::m);
- assertTrue(assertionCount == 1);
+ g1(MethodReference44::m);
+ g2(MethodReference44::m);
+ g3(MethodReference44::m);
+ g4(MethodReference44::m);
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference44.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,4 @@
+MethodReference44.java:40:11: compiler.err.cant.apply.symbol: kindname.method, g1, MethodReference44.SAM1, @864, kindname.class, MethodReference44, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.eq.upper.bounds: X, java.lang.String, java.lang.Number))
+MethodReference44.java:42:11: compiler.err.cant.apply.symbol: kindname.method, g3, MethodReference44.SAM3, @932, kindname.class, MethodReference44, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.eq.upper.bounds: X, java.lang.Object, java.lang.Number))
+MethodReference44.java:43:9: compiler.err.ref.ambiguous: g4, kindname.method, g4(MethodReference44.SAM2), MethodReference44, kindname.method, g4(MethodReference44.SAM3), MethodReference44
+3 errors
--- a/langtools/test/tools/javac/lambda/MethodReference46.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/MethodReference46.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,42 +1,12 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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
+ * @test /nodynamiccopyright/
* @bug 8003280
* @summary Add lambda tests
* check that generic method reference is inferred when type parameters are omitted
- * @run main MethodReference46
+ * @compile/fail/ref=MethodReference46.out -XDrawDiagnostics MethodReference46.java
*/
-public class MethodReference46 {
-
- static int assertionCount = 0;
- static void assertTrue(boolean cond) {
- assertionCount++;
- if (!cond)
- throw new AssertionError();
- }
+public class MethodReference46 {
interface SAM1 {
void m(String s);
@@ -56,12 +26,20 @@
static <X extends Number> void m(X fx) { }
- static void g(SAM1 s) { assertTrue(false); }
- static void g(SAM2 s) { assertTrue(true); }
- static void g(SAM3 s) { assertTrue(false); }
+ static void g1(SAM1 s) { }
+
+ static void g2(SAM2 s) { }
+
+ static void g3(SAM3 s) { }
+
+ static void g4(SAM1 s) { }
+ static void g4(SAM2 s) { }
+ static void g4(SAM3 s) { }
public static void main(String[] args) {
- g(MethodReference46::m);
- assertTrue(assertionCount == 1);
+ g1(MethodReference46::m);
+ g2(MethodReference46::m);
+ g3(MethodReference46::m);
+ g4(MethodReference46::m);
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference46.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,4 @@
+MethodReference46.java:40:11: compiler.err.cant.apply.symbol: kindname.method, g1, MethodReference46.SAM1, @809, kindname.class, MethodReference46, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbol: kindname.method, m, X, java.lang.String, kindname.class, MethodReference46, (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.String, java.lang.Number))))
+MethodReference46.java:42:11: compiler.err.cant.apply.symbol: kindname.method, g3, MethodReference46.SAM3, @877, kindname.class, MethodReference46, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbol: kindname.method, m, X, java.lang.Object, kindname.class, MethodReference46, (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Object, java.lang.Number))))
+MethodReference46.java:43:9: compiler.err.ref.ambiguous: g4, kindname.method, g4(MethodReference46.SAM2), MethodReference46, kindname.method, g4(MethodReference46.SAM3), MethodReference46
+3 errors
--- a/langtools/test/tools/javac/lambda/MethodReference47.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/MethodReference47.java Sat Sep 14 20:43:34 2013 +0100
@@ -7,14 +7,6 @@
*/
public class MethodReference47 {
- static int assertionCount = 0;
-
- static void assertTrue(boolean cond) {
- assertionCount++;
- if (!cond)
- throw new AssertionError();
- }
-
interface SAM1 {
void m(Integer s);
}
@@ -34,7 +26,7 @@
static void g2(SAM2 s) { }
public static void main(String[] args) {
- g1(MethodReference46::m);
- g2(MethodReference46::m);
+ g1(MethodReference47::m);
+ g2(MethodReference47::m);
}
}
--- a/langtools/test/tools/javac/lambda/MethodReference47.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/MethodReference47.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,2 +1,2 @@
-MethodReference47.java:38:9: compiler.err.ref.ambiguous: g2, kindname.method, g2(MethodReference47.SAM1), MethodReference47, kindname.method, g2(MethodReference47.SAM2), MethodReference47
+MethodReference47.java:30:9: compiler.err.ref.ambiguous: g2, kindname.method, g2(MethodReference47.SAM1), MethodReference47, kindname.method, g2(MethodReference47.SAM2), MethodReference47
1 error
--- a/langtools/test/tools/javac/lambda/MethodReference48.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/MethodReference48.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,42 +1,12 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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
+ * @test /nodynamiccopyright/
* @bug 8003280
* @summary Add lambda tests
* check that raw qualifier in unbound method reference is inferred from descriptor
- * @run main MethodReference48
+ * @compile/fail/ref=MethodReference48.out -XDrawDiagnostics MethodReference48.java
*/
-public class MethodReference48 {
-
- static int assertionCount = 0;
- static void assertTrue(boolean cond) {
- assertionCount++;
- if (!cond)
- throw new AssertionError();
- }
+public class MethodReference48 {
static class Foo<X> {
X m() { return null; };
@@ -54,12 +24,20 @@
Object m(Foo<Integer> fi);
}
- static void g(SAM1 s) { assertTrue(false); } //return type not compatible
- static void g(SAM2 s) { assertTrue(true); } //ok
- static void g(SAM3 s) { assertTrue(false); } //ok but less specific
+ static void g1(SAM1 s) { } //return type not compatible
+
+ static void g2(SAM2 s) { } //ok
+
+ static void g3(SAM3 s) { } //ok
+
+ static void g4(SAM1 s) { } //return type not compatible
+ static void g4(SAM2 s) { } //ok
+ static void g4(SAM3 s) { } //ok
public static void main(String[] args) {
- g(Foo::m);
- assertTrue(assertionCount == 1);
+ g1(Foo::m);
+ g2(Foo::m);
+ g3(Foo::m);
+ g4(Foo::m);
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference48.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,3 @@
+MethodReference48.java:38:11: compiler.err.cant.apply.symbol: kindname.method, g1, MethodReference48.SAM1, @869, kindname.class, MethodReference48, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.mref: (compiler.misc.inconvertible.types: java.lang.String, MethodReference48.Foo<java.lang.Object>)))
+MethodReference48.java:41:9: compiler.err.ref.ambiguous: g4, kindname.method, g4(MethodReference48.SAM2), MethodReference48, kindname.method, g4(MethodReference48.SAM3), MethodReference48
+2 errors
--- a/langtools/test/tools/javac/lambda/MethodReference70.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/MethodReference70.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,3 +1,3 @@
MethodReference70.java:26:10: compiler.err.ref.ambiguous: g, kindname.method, <Z>g(MethodReference70.F<Z>), MethodReference70, kindname.method, <Z>g(MethodReference70.G<Z>), MethodReference70
-MethodReference70.java:26:11: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: Z)
+MethodReference70.java:26:11: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: Z, (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbols: kindname.method, m2, java.lang.Object,{(compiler.misc.inapplicable.method: kindname.method, MethodReference70, m2(java.lang.Integer), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, java.lang.Integer))),(compiler.misc.inapplicable.method: kindname.method, MethodReference70, m2(java.lang.String), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, java.lang.String)))})))
2 errors
--- a/langtools/test/tools/javac/lambda/MethodReference71.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/MethodReference71.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,3 +1,3 @@
MethodReference71.java:24:10: compiler.err.ref.ambiguous: g, kindname.method, <Z>g(MethodReference71.F<Z>), MethodReference71, kindname.method, <Z>g(MethodReference71.G<Z>), MethodReference71
-MethodReference71.java:24:11: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: Z)
+MethodReference71.java:24:11: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: Z, (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbol: kindname.method, m2, java.lang.Integer[], java.lang.Object, kindname.class, MethodReference71, (compiler.misc.varargs.argument.mismatch: (compiler.misc.inconvertible.types: java.lang.Object, java.lang.Integer)))))
2 errors
--- a/langtools/test/tools/javac/lambda/MostSpecific04.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/MostSpecific04.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -26,17 +26,10 @@
* @bug 8003280
* @summary Add lambda tests
* Structural most specific doesn't handle cases with wildcards in functional interfaces
+ * @compile/fail/ref=MostSpecific04.out -XDrawDiagnostics MostSpecific04.java
*/
public class MostSpecific04 {
- static int assertionCount = 0;
-
- static void assertTrue(boolean cond) {
- assertionCount++;
- if (!cond)
- throw new AssertionError();
- }
-
interface DoubleMapper<T> {
double map(T t);
}
@@ -46,13 +39,13 @@
}
static class MyList<E> {
- void map(DoubleMapper<? super E> m) { assertTrue(false); }
- void map(LongMapper<? super E> m) { assertTrue(true); }
+ void map(DoubleMapper<? super E> m) { }
+ void map(LongMapper<? super E> m) { }
}
public static void main(String[] args) {
MyList<String> ls = new MyList<String>();
- ls.map(e->e.length());
- assertTrue(assertionCount == 1);
+ ls.map(e->e.length()); //ambiguous - implicit
+ ls.map((String e)->e.length()); //ok
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MostSpecific04.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,2 @@
+MostSpecific04.java:48:11: compiler.err.ref.ambiguous: map, kindname.method, map(MostSpecific04.DoubleMapper<? super E>), MostSpecific04.MyList, kindname.method, map(MostSpecific04.LongMapper<? super E>), MostSpecific04.MyList
+1 error
--- a/langtools/test/tools/javac/lambda/MostSpecific05.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/MostSpecific05.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -26,17 +26,10 @@
* @bug 8003280
* @summary Add lambda tests
* Structural most specific doesn't handle cases with wildcards in functional interfaces
+ * @compile/fail/ref=MostSpecific05.out -XDrawDiagnostics MostSpecific05.java
*/
public class MostSpecific05 {
- static int assertionCount = 0;
-
- static void assertTrue(boolean cond) {
- assertionCount++;
- if (!cond)
- throw new AssertionError();
- }
-
interface ObjectConverter<T extends Object> {
T map(Object o);
}
@@ -46,13 +39,13 @@
}
static class MyMapper<A extends Object, B extends Number> {
- void map(ObjectConverter<? extends A> m) { assertTrue(false); }
- void map(NumberConverter<? extends B> m) { assertTrue(true); }
+ void map(ObjectConverter<? extends A> m) { }
+ void map(NumberConverter<? extends B> m) { }
}
public static void main(String[] args) {
MyMapper<Number, Double> mm = new MyMapper<Number, Double>();
- mm.map(e->1.0);
- assertTrue(assertionCount == 1);
+ mm.map(e->1.0); //ambiguous - implicit
+ mm.map((Object e)->1.0); //ok
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MostSpecific05.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,2 @@
+MostSpecific05.java:48:11: compiler.err.ref.ambiguous: map, kindname.method, map(MostSpecific05.ObjectConverter<? extends A>), MostSpecific05.MyMapper, kindname.method, map(MostSpecific05.NumberConverter<? extends B>), MostSpecific05.MyMapper
+1 error
--- a/langtools/test/tools/javac/lambda/MostSpecific08.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/MostSpecific08.java Sat Sep 14 20:43:34 2013 +0100
@@ -25,7 +25,7 @@
* @test
* @bug 8008813
* @summary Structural most specific fails when method reference is passed to overloaded method
- * @compile MostSpecific08.java
+ * @compile/fail/ref=MostSpecific08.out -XDrawDiagnostics MostSpecific08.java
*/
class MostSpecific08 {
@@ -51,12 +51,14 @@
}
void testMref(Tester t) {
- IntResult pr = t.apply(C::getInt);
- ReferenceResult<Integer> rr = t.apply(C::getInteger);
+ IntResult pr = t.apply(C::getInt); //ok - unoverloaded mref
+ ReferenceResult<Integer> rr = t.apply(C::getInteger); //ok - unoverloaded mref
}
void testLambda(Tester t) {
- IntResult pr = t.apply(c->c.getInt());
- ReferenceResult<Integer> rr = t.apply(c->c.getInteger());
+ IntResult pr1 = t.apply(c->c.getInt()); //ambiguous - implicit
+ IntResult pr2 = t.apply((C c)->c.getInt()); //ok
+ ReferenceResult<Integer> rr1 = t.apply(c->c.getInteger()); //ambiguous - implicit
+ ReferenceResult<Integer> rr2 = t.apply((C c)->c.getInteger()); //ok
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MostSpecific08.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,4 @@
+MostSpecific08.java:59:26: compiler.err.ref.ambiguous: apply, kindname.method, apply(MostSpecific08.PrimitiveFunction), MostSpecific08.Tester, kindname.method, <Z>apply(MostSpecific08.ReferenceFunction<Z>), MostSpecific08.Tester
+MostSpecific08.java:61:41: compiler.err.ref.ambiguous: apply, kindname.method, apply(MostSpecific08.PrimitiveFunction), MostSpecific08.Tester, kindname.method, <Z>apply(MostSpecific08.ReferenceFunction<Z>), MostSpecific08.Tester
+MostSpecific08.java:61:47: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: MostSpecific08.IntResult, MostSpecific08.ReferenceResult<java.lang.Integer>)
+3 errors
--- a/langtools/test/tools/javac/lambda/TargetType01.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/TargetType01.java Sat Sep 14 20:43:34 2013 +0100
@@ -26,7 +26,7 @@
* @bug 8003280 8009131
* @summary Add lambda tests
* check nested case of overload resolution and lambda parameter inference
- * @compile TargetType01.java
+ * @compile/fail/ref=TargetType01.out -XDrawDiagnostics TargetType01.java
*/
class TargetType01 {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/TargetType01.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,3 @@
+TargetType01.java:45:9: compiler.err.ref.ambiguous: M, kindname.method, M(TargetType01.F_I_I), TargetType01, kindname.method, M(TargetType01.F_S_S), TargetType01
+TargetType01.java:45:26: compiler.err.ref.ambiguous: M, kindname.method, M(TargetType01.F_I_I), TargetType01, kindname.method, M(TargetType01.F_S_S), TargetType01
+2 errors
--- a/langtools/test/tools/javac/lambda/TargetType02.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/TargetType02.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,19 +27,11 @@
* @summary Add lambda tests
* check overload resolution and target type inference w.r.t. generic methods
* @author Maurizio Cimadamore
- * @run main TargetType02
+ * @compile/fail/ref=TargetType02.out -XDrawDiagnostics TargetType02.java
*/
public class TargetType02 {
- static int assertionCount = 0;
-
- static void assertTrue(boolean cond) {
- assertionCount++;
- if (!cond)
- throw new AssertionError();
- }
-
interface S1<X extends Number> {
X m(Integer x);
}
@@ -48,15 +40,16 @@
abstract X m(Integer x);
}
- static <Z extends Number> void call(S1<Z> s) { s.m(1); assertTrue(true); }
- static <Z extends String> void call(S2<Z> s) { s.m(2); assertTrue(false); }
+ static <Z extends Number> void call1(S1<Z> s) { }
+
+ static <Z extends String> void call2(S2<Z> s) { }
+
+ static <Z extends Number> void call3(S1<Z> s) { }
+ static <Z extends String> void call3(S2<Z> s) { }
void test() {
- call(i -> { toString(); return i; });
- }
-
- public static void main(String[] args) {
- new TargetType02().test();
- assertTrue(assertionCount == 1);
+ call1(i -> { toString(); return i; });
+ call2(i -> { toString(); return i; });
+ call3(i -> { toString(); return i; });
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/TargetType02.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,3 @@
+TargetType02.java:52:14: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Integer, java.lang.String)
+TargetType02.java:53:9: compiler.err.ref.ambiguous: call3, kindname.method, <Z>call3(TargetType02.S1<Z>), TargetType02, kindname.method, <Z>call3(TargetType02.S2<Z>), TargetType02
+2 errors
--- a/langtools/test/tools/javac/lambda/TargetType10.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/TargetType10.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,10 +1,10 @@
/*
* @test /nodynamiccopyright/
- * @bug 8003280
+ * @bug 8003280 8016177
* @summary Add lambda tests
* check that wildcards in the target method of a lambda conversion is handled correctly
* @author Maurizio Cimadamore
- * @compile/fail/ref=TargetType10.out -XDrawDiagnostics TargetType10.java
+ * @compile TargetType10.java
*/
class TargetType10 {
--- a/langtools/test/tools/javac/lambda/TargetType10.out Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-TargetType10.java:17:18: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: B,A)
-1 error
--- a/langtools/test/tools/javac/lambda/TargetType21.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/TargetType21.java Sat Sep 14 20:43:34 2013 +0100
@@ -26,8 +26,10 @@
void test() {
call(x -> { throw new Exception(); }); //ambiguous
+ call((Integer x) -> { System.out.println(""); }); //ok (only one is void)
+ call((Integer x) -> { return (Object) null; }); //ok (only one returns Object)
call(x -> { System.out.println(""); }); //ambiguous
- call(x -> { return (Object) null; }); //cyclic inference
+ call(x -> { return (Object) null; }); //ambiguous
call(x -> { return null; }); //ambiguous
}
}
--- a/langtools/test/tools/javac/lambda/TargetType21.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/TargetType21.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,7 @@
TargetType21.java:28:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM2), TargetType21, kindname.method, <R,A>call(TargetType21.SAM3<R,A>), TargetType21
-TargetType21.java:29:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM2), TargetType21, kindname.method, <R,A>call(TargetType21.SAM3<R,A>), TargetType21
-TargetType21.java:30:13: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: A)
-TargetType21.java:31:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM1), TargetType21, kindname.method, <R,A>call(TargetType21.SAM3<R,A>), TargetType21
-4 errors
+TargetType21.java:31:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM2), TargetType21, kindname.method, <R,A>call(TargetType21.SAM3<R,A>), TargetType21
+TargetType21.java:32:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM2), TargetType21, kindname.method, <R,A>call(TargetType21.SAM3<R,A>), TargetType21
+TargetType21.java:32:13: compiler.err.cant.apply.symbol: kindname.method, call, TargetType21.SAM2, @888, kindname.class, TargetType21, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.unexpected.ret.val)))
+TargetType21.java:33:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM2), TargetType21, kindname.method, <R,A>call(TargetType21.SAM3<R,A>), TargetType21
+TargetType21.java:33:13: compiler.err.cant.apply.symbol: kindname.method, call, TargetType21.SAM2, @946, kindname.class, TargetType21, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.unexpected.ret.val)))
+6 errors
--- a/langtools/test/tools/javac/lambda/TargetType24.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/TargetType24.java Sat Sep 14 20:43:34 2013 +0100
@@ -29,11 +29,14 @@
}
void test(Array<String> as, final Array<Character> ac) {
- final boolean b1 = as.forAll(s -> ac.forAll(c -> false)); //ok
+ final boolean b1 = as.forAll((String s) -> ac.forAll((Character c) -> false)); //ok
+ final boolean b2 = as.forAll(s -> ac.forAll(c -> false)); //ambiguous
+ final boolean b3 = as.forAll((String s) -> ac.forAll(c -> false)); //ambiguous
+ final boolean b4 = as.forAll(s -> ac.forAll((Character c) -> false)); //ambiguous
final String s1 = as.forAll2(s -> ac.forAll2(c -> "")); //ok
- final boolean b2 = as.forAll(s -> ac.forAll(c -> "" )); //fail
+ final boolean b5 = as.forAll(s -> ac.forAll(c -> "" )); //fail
final String s2 = as.forAll2(s -> ac.forAll2(c -> false)); //fail
- final boolean b3 = as.forAll((F<String, Boolean>)s -> ac.forAll((F<Character, Boolean>)c -> "")); //fail
+ final boolean b6 = as.forAll((F<String, Boolean>)s -> ac.forAll((F<Character, Boolean>)c -> "")); //fail
final String s3 = as.forAll((FSub<String, String>)s -> ac.forAll((FSub<Character, String>)c -> false)); //fail
}
}
--- a/langtools/test/tools/javac/lambda/TargetType24.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/TargetType24.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,11 @@
-TargetType24.java:34:37: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, boolean)
-TargetType24.java:35:45: compiler.err.cant.apply.symbol: kindname.method, forAll2, TargetType24.FSub<java.lang.Character,java.lang.String>, @945, kindname.class, TargetType24.Array<A>, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: boolean, java.lang.String)))
-TargetType24.java:36:101: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Boolean))
-TargetType24.java:37:104: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: boolean, java.lang.String))
-4 errors
+TargetType24.java:33:30: compiler.err.ref.ambiguous: forAll, kindname.method, forAll(TargetType24.F<A,java.lang.Boolean>), TargetType24.Array, kindname.method, forAll(TargetType24.FSub<A,java.lang.String>), TargetType24.Array
+TargetType24.java:33:45: compiler.err.ref.ambiguous: forAll, kindname.method, forAll(TargetType24.F<A,java.lang.Boolean>), TargetType24.Array, kindname.method, forAll(TargetType24.FSub<A,java.lang.String>), TargetType24.Array
+TargetType24.java:34:54: compiler.err.ref.ambiguous: forAll, kindname.method, forAll(TargetType24.F<A,java.lang.Boolean>), TargetType24.Array, kindname.method, forAll(TargetType24.FSub<A,java.lang.String>), TargetType24.Array
+TargetType24.java:35:30: compiler.err.ref.ambiguous: forAll, kindname.method, forAll(TargetType24.F<A,java.lang.Boolean>), TargetType24.Array, kindname.method, forAll(TargetType24.FSub<A,java.lang.String>), TargetType24.Array
+TargetType24.java:37:30: compiler.err.ref.ambiguous: forAll, kindname.method, forAll(TargetType24.F<A,java.lang.Boolean>), TargetType24.Array, kindname.method, forAll(TargetType24.FSub<A,java.lang.String>), TargetType24.Array
+TargetType24.java:37:45: compiler.err.ref.ambiguous: forAll, kindname.method, forAll(TargetType24.F<A,java.lang.Boolean>), TargetType24.Array, kindname.method, forAll(TargetType24.FSub<A,java.lang.String>), TargetType24.Array
+TargetType24.java:37:52: compiler.err.cant.apply.symbol: kindname.method, forAll, TargetType24.F<java.lang.Character,java.lang.Boolean>, @1149, kindname.class, TargetType24.Array<A>, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Boolean)))
+TargetType24.java:38:53: compiler.err.cant.apply.symbol: kindname.method, forAll2, TargetType24.FSub<java.lang.Character,java.lang.String>, @1221, kindname.class, TargetType24.Array<A>, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: boolean, java.lang.String)))
+TargetType24.java:39:101: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Boolean))
+TargetType24.java:40:104: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: boolean, java.lang.String))
+10 errors
--- a/langtools/test/tools/javac/lambda/TargetType26.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/TargetType26.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,2 +1,2 @@
-TargetType26.java:16:11: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: Z)
+TargetType26.java:16:11: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: Z, (compiler.misc.not.a.functional.intf: java.lang.Object))
1 error
--- a/langtools/test/tools/javac/lambda/TargetType27.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/TargetType27.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,2 +1,2 @@
-TargetType27.java:18:10: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: R)
+TargetType27.java:18:10: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: A,R, (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.not.a.functional.intf: java.lang.Object)))
1 error
--- a/langtools/test/tools/javac/lambda/TargetType39.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/TargetType39.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,3 +1,3 @@
-TargetType39.java:19:13: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: U)
-TargetType39.java:20:13: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: V)
+TargetType39.java:19:13: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: U,V, (compiler.misc.incompatible.type.in.conditional: (compiler.misc.inconvertible.types: TargetType39.SAM<java.lang.String,java.lang.Void>, TargetType39.SAM<java.lang.Object,V>)))
+TargetType39.java:20:13: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: U,V, (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.incompatible.type.in.conditional: (compiler.misc.not.a.functional.intf: java.lang.Object))))
2 errors
--- a/langtools/test/tools/javac/lambda/TargetType43.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/TargetType43.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,4 +1,5 @@
TargetType43.java:13:20: compiler.err.prob.found.req: (compiler.misc.not.a.functional.intf: java.lang.Object)
TargetType43.java:13:30: compiler.err.cant.resolve.location: kindname.class, NonExistentClass, , , (compiler.misc.location: kindname.class, TargetType43, null)
+TargetType43.java:14:9: compiler.err.cant.apply.symbol: kindname.method, m, java.lang.Object, @359, kindname.class, TargetType43, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.not.a.functional.intf: java.lang.Object))
TargetType43.java:14:21: compiler.err.cant.resolve.location: kindname.class, NonExistentClass, , , (compiler.misc.location: kindname.class, TargetType43, null)
-3 errors
+4 errors
--- a/langtools/test/tools/javac/lambda/TargetType66.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/TargetType66.java Sat Sep 14 20:43:34 2013 +0100
@@ -17,8 +17,8 @@
void g(SAM2 s2) { }
void test() {
- g(x->{ String s = x; }); //g(SAM1)
- g(x->{ Integer i = x; }); //g(SAM2)
+ g(x->{ String s = x; }); //ambiguous
+ g(x->{ Integer i = x; }); //ambiguous
g(x->{ Object o = x; }); //ambiguous
g(x->{ Character c = x; }); //error: inapplicable methods
g(x->{ Character c = ""; }); //error: incompatible types
--- a/langtools/test/tools/javac/lambda/TargetType66.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/TargetType66.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,4 +1,9 @@
+TargetType66.java:20:9: compiler.err.ref.ambiguous: g, kindname.method, g(TargetType66.SAM1), TargetType66, kindname.method, g(TargetType66.SAM2), TargetType66
+TargetType66.java:21:9: compiler.err.ref.ambiguous: g, kindname.method, g(TargetType66.SAM1), TargetType66, kindname.method, g(TargetType66.SAM2), TargetType66
+TargetType66.java:21:28: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer)
TargetType66.java:22:9: compiler.err.ref.ambiguous: g, kindname.method, g(TargetType66.SAM1), TargetType66, kindname.method, g(TargetType66.SAM2), TargetType66
-TargetType66.java:23:9: compiler.err.cant.apply.symbols: kindname.method, g, @578,{(compiler.misc.inapplicable.method: kindname.method, TargetType66, g(TargetType66.SAM1), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.bad.arg.types.in.lambda: java.lang.String, (compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Character))))),(compiler.misc.inapplicable.method: kindname.method, TargetType66, g(TargetType66.SAM2), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.bad.arg.types.in.lambda: java.lang.Integer, (compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Integer, java.lang.Character)))))}
+TargetType66.java:23:9: compiler.err.ref.ambiguous: g, kindname.method, g(TargetType66.SAM1), TargetType66, kindname.method, g(TargetType66.SAM2), TargetType66
+TargetType66.java:23:30: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Character)
+TargetType66.java:24:9: compiler.err.ref.ambiguous: g, kindname.method, g(TargetType66.SAM1), TargetType66, kindname.method, g(TargetType66.SAM2), TargetType66
TargetType66.java:24:30: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Character)
-3 errors
+8 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/bridge/template_tests/BridgeMethodTestCase.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,421 @@
+/*
+ * 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.
+ *
+ */
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import tools.javac.combo.*;
+
+import static org.testng.Assert.fail;
+
+/**
+ * BridgeMethodTestCase -- used for asserting linkage to bridges under separate compilation.
+ *
+ * Example test case:
+ * public void test1() throws IOException, ReflectiveOperationException {
+ * compileSpec("C(Bc1(A))");
+ * assertLinkage("C", LINKAGE_ERROR, "B1");
+ * recompileSpec("C(Bc1(Ac0))", "A");
+ * assertLinkage("C", "A0", "B1");
+ * }
+ *
+ * This compiles A, B, and C, asserts that C.m()Object does not exist, asserts
+ * that C.m()Number eventually invokes B.m()Number, recompiles B, and then asserts
+ * that the result of calling C.m()Object now arrives at A.
+ *
+ * @author Brian Goetz
+ */
+
+@Test
+public abstract class BridgeMethodTestCase extends JavacTemplateTestBase {
+
+ private static final String TYPE_LETTERS = "ABCDIJK";
+
+ private static final String BASE_INDEX_CLASS = "class C0 {\n" +
+ " int val;\n" +
+ " C0(int val) { this.val = val; }\n" +
+ " public int getVal() { return val; }\n" +
+ "}\n";
+ private static final String INDEX_CLASS_TEMPLATE = "class C#ID extends C#PREV {\n" +
+ " C#ID(int val) { super(val); }\n" +
+ "}\n";
+
+
+
+ protected static String LINKAGE_ERROR = "-1";
+
+ private List<File> compileDirs = new ArrayList<>();
+
+ /**
+ * Compile all the classes in a class spec, and put them on the classpath.
+ *
+ * The spec is the specification for a nest of classes, using the following notation
+ * A, B represent abstract classes
+ * C represents a concrete class
+ * I, J, K represent interfaces
+ * Lowercase 'c' following a class means that the method m() is concrete
+ * Lowercase 'a' following a class or interface means that the method m() is abstract
+ * Lowercase 'd' following an interface means that the method m() is default
+ * A number 0, 1, or 2 following the lowercase letter indicates the return type of that method
+ * 0 = Object, 1 = Number, 2 = Integer (these form an inheritance chain so bridges are generated)
+ * A classes supertypes follow its method spec, in parentheses
+ * Examples:
+ * C(Ia0, Jd0) -- C extends I and J, I has abstract m()Object, J has default m()Object
+ * Cc1(Ia0) -- C has concrete m()Number, extends I with abstract m()Object
+ * If a type must appear multiple times, its full spec must be in the first occurrence
+ * Example:
+ * C(I(Kd0), J(K))
+ */
+ protected void compileSpec(String spec) throws IOException {
+ compileSpec(spec, false);
+ }
+
+ /**
+ * Compile all the classes in a class spec, and assert that there were compilation errors.
+ */
+ protected void compileSpec(String spec, String... errorKeys) throws IOException {
+ compileSpec(spec, false, errorKeys);
+ }
+
+ protected void compileSpec(String spec, boolean debug, String... errorKeys) throws IOException {
+ ClassModel cm = new Parser(spec).parseClassModel();
+ for (int i = 0; i <= cm.maxIndex() ; i++) {
+ if (debug) System.out.println(indexClass(i));
+ addSourceFile(String.format("C%d.java", i), new StringTemplate(indexClass(i)));
+ }
+ for (Map.Entry<String, ClassModel> e : classes(cm).entrySet()) {
+ if (debug) System.out.println(e.getValue().toSource());
+ addSourceFile(e.getKey() + ".java", new StringTemplate(e.getValue().toSource()));
+ }
+ compileDirs.add(compile(true));
+ resetSourceFiles();
+ if (errorKeys.length == 0)
+ assertCompileSucceeded();
+ else
+ assertCompileErrors(errorKeys);
+ }
+
+ /**
+ * Recompile only a subset of classes in the class spec, as named by names,
+ * and put them on the classpath such that they shadow earlier versions of that class.
+ */
+ protected void recompileSpec(String spec, String... names) throws IOException {
+ List<String> nameList = Arrays.asList(names);
+ ClassModel cm = new Parser(spec).parseClassModel();
+ for (int i = 0; i <= cm.maxIndex() ; i++) {
+ addSourceFile(String.format("C%d.java", i), new StringTemplate(indexClass(i)));
+ }
+ for (Map.Entry<String, ClassModel> e : classes(cm).entrySet())
+ if (nameList.contains(e.getKey()))
+ addSourceFile(e.getKey() + ".java", new StringTemplate(e.getValue().toSource()));
+ compileDirs.add(compile(Arrays.asList(classPaths()), true));
+ resetSourceFiles();
+ assertCompileSucceeded();
+ }
+
+ protected void assertLinkage(String name, String... expected) throws ReflectiveOperationException {
+ for (int i=0; i<expected.length; i++) {
+ String e = expected[i];
+ if (e.equals(LINKAGE_ERROR)) {
+ try {
+ int actual = invoke(name, i);
+ fail("Expected linkage error, got" + fromNum(actual));
+ }
+ catch (LinkageError x) {
+ // success
+ }
+ }
+ else {
+ if (e.length() == 1)
+ e += "0";
+ int expectedInt = toNum(e);
+ int actual = invoke(name, i);
+ if (expectedInt != actual)
+ fail(String.format("Expected %s but found %s for %s.m()%d", fromNum(expectedInt), fromNum(actual), name, i));
+ }
+ }
+ }
+
+ private Map<String, ClassModel> classes(ClassModel cm) {
+ HashMap<String, ClassModel> m = new HashMap<>();
+ classesHelper(cm, m);
+ return m;
+ }
+
+ private String indexClass(int index) {
+ if (index == 0) {
+ return BASE_INDEX_CLASS;
+ } else {
+ return INDEX_CLASS_TEMPLATE
+ .replace("#ID", String.valueOf(index))
+ .replace("#PREV", String.valueOf(index - 1));
+ }
+ }
+
+ private static String overrideName(int index) {
+ return "C" + index;
+ }
+
+ private void classesHelper(ClassModel cm, Map<String, ClassModel> m) {
+ if (!m.containsKey(cm.name))
+ m.put(cm.name, cm);
+ for (ClassModel s : cm.supertypes)
+ classesHelper(s, m);
+ }
+
+ private static String fromNum(int num) {
+ return String.format("%c%d", TYPE_LETTERS.charAt(num / 10), num % 10);
+ }
+
+ private static int toNum(String name, int index) {
+ return 10*(TYPE_LETTERS.indexOf(name.charAt(0))) + index;
+ }
+
+ private static int toNum(String string) {
+ return 10*(TYPE_LETTERS.indexOf(string.charAt(0))) + Integer.parseInt(string.substring(1, 2));
+ }
+
+ private int invoke(String name, int index) throws ReflectiveOperationException {
+ File[] files = classPaths();
+ Class clazz = loadClass(name, files);
+ Method[] ms = clazz.getMethods();
+ for (Method m : ms) {
+ if (m.getName().equals("m") && m.getReturnType().getName().equals(overrideName(index))) {
+ m.setAccessible(true);
+ Object instance = clazz.newInstance();
+ Object c0 = m.invoke(instance);
+ Method getVal = c0.getClass().getMethod("getVal");
+ getVal.setAccessible(true);
+ return (int)getVal.invoke(c0);
+ }
+ }
+ throw new NoSuchMethodError("cannot find method m()" + index + " in class " + name);
+ }
+
+ private File[] classPaths() {
+ File[] files = new File[compileDirs.size()];
+ for (int i=0; i<files.length; i++)
+ files[files.length - i - 1] = compileDirs.get(i);
+ return files;
+ }
+
+ @BeforeMethod
+ @Override
+ public void reset() {
+ compileDirs.clear();
+ super.reset();
+ }
+
+ private static class ClassModel {
+
+ enum MethodType {
+ ABSTRACT('a'), CONCRETE('c'), DEFAULT('d');
+
+ public final char designator;
+
+ MethodType(char designator) {
+ this.designator = designator;
+ }
+
+ public static MethodType find(char c) {
+ for (MethodType m : values())
+ if (m.designator == c)
+ return m;
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private final String name;
+ private final boolean isInterface;
+ private final List<ClassModel> supertypes;
+ private final MethodType methodType;
+ private final int methodIndex;
+
+ private ClassModel(String name,
+ boolean anInterface,
+ List<ClassModel> supertypes,
+ MethodType methodType,
+ int methodIndex) {
+ this.name = name;
+ isInterface = anInterface;
+ this.supertypes = supertypes;
+ this.methodType = methodType;
+ this.methodIndex = methodIndex;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(name);
+ if (methodType != null) {
+ sb.append(methodType.designator);
+ sb.append(methodIndex);
+ }
+ if (!supertypes.isEmpty()) {
+ sb.append("(");
+ for (int i=0; i<supertypes.size(); i++) {
+ if (i > 0)
+ sb.append(",");
+ sb.append(supertypes.get(i).toString());
+ }
+ sb.append(")");
+ }
+ return sb.toString();
+ }
+
+ int maxIndex() {
+ int maxSoFar = methodIndex;
+ for (ClassModel cm : supertypes) {
+ maxSoFar = Math.max(cm.maxIndex(), maxSoFar);
+ }
+ return maxSoFar;
+ }
+
+ public String toSource() {
+ String extendsClause = "";
+ String implementsClause = "";
+ String methodBody = "";
+ boolean isAbstract = "AB".contains(name);
+
+ for (ClassModel s : supertypes) {
+ if (!s.isInterface) {
+ extendsClause = String.format("extends %s", s.name);
+ break;
+ }
+ }
+
+ StringJoiner sj = new StringJoiner(", ");
+ for (ClassModel s : supertypes)
+ if (s.isInterface)
+ sj.add(s.name);
+ if (sj.length() > 0) {
+ if (isInterface)
+ implementsClause = "extends " + sj.toString();
+ else
+ implementsClause = "implements " + sj.toString();
+ }
+ if (methodType != null) {
+ switch (methodType) {
+ case ABSTRACT:
+ methodBody = String.format("public abstract %s m();", overrideName(methodIndex));
+ break;
+ case CONCRETE:
+ methodBody = String.format("public %s m() { return new %s(%d); };",
+ overrideName(methodIndex), overrideName(methodIndex), toNum(name, methodIndex));
+ break;
+ case DEFAULT:
+ methodBody = String.format("public default %s m() { return new %s(%d); };",
+ overrideName(methodIndex), overrideName(methodIndex), toNum(name, methodIndex));
+ break;
+
+ }
+ }
+
+ return String.format("public %s %s %s %s %s { %s }", isAbstract ? "abstract" : "",
+ isInterface ? "interface" : "class",
+ name, extendsClause, implementsClause, methodBody);
+ }
+ }
+
+ private static class Parser {
+ private final String input;
+ private final char[] chars;
+ private int index;
+
+ private Parser(String s) {
+ input = s;
+ chars = s.toCharArray();
+ }
+
+ private char peek() {
+ return index < chars.length ? chars[index] : 0;
+ }
+
+ private boolean peek(String validChars) {
+ return validChars.indexOf(peek()) >= 0;
+ }
+
+ private char advanceIf(String validChars) {
+ if (peek(validChars))
+ return chars[index++];
+ else
+ return 0;
+ }
+
+ private char advanceIfDigit() {
+ return advanceIf("0123456789");
+ }
+
+ private int index() {
+ StringBuilder buf = new StringBuilder();
+ char c = advanceIfDigit();
+ while (c != 0) {
+ buf.append(c);
+ c = advanceIfDigit();
+ }
+ return Integer.valueOf(buf.toString());
+ }
+
+ private char advance() {
+ return chars[index++];
+ }
+
+ private char expect(String validChars) {
+ char c = advanceIf(validChars);
+ if (c == 0)
+ throw new IllegalArgumentException(String.format("Expecting %s at position %d of %s", validChars, index, input));
+ return c;
+ }
+
+ public ClassModel parseClassModel() {
+ List<ClassModel> supers = new ArrayList<>();
+ char name = expect(TYPE_LETTERS);
+ boolean isInterface = "IJK".indexOf(name) >= 0;
+ ClassModel.MethodType methodType = peek(isInterface ? "ad" : "ac") ? ClassModel.MethodType.find(advance()) : null;
+ int methodIndex = 0;
+ if (methodType != null) {
+ methodIndex = index();
+ }
+ if (peek() == '(') {
+ advance();
+ supers.add(parseClassModel());
+ while (peek() == ',') {
+ advance();
+ supers.add(parseClassModel());
+ }
+ expect(")");
+ }
+ return new ClassModel(new String(new char[]{ name }), isInterface, supers, methodType, methodIndex);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/bridge/template_tests/BridgeMethodsTemplateTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,1082 @@
+/*
+ * 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.
+ *
+ */
+import java.io.IOException;
+
+import org.testng.annotations.Test;
+
+/**
+ * BridgeMethodsTemplateTest
+ *
+ * @author Brian Goetz
+ */
+@Test
+public class BridgeMethodsTemplateTest extends BridgeMethodTestCase {
+
+ /*
+ * Cc1(A) -> Cc1(Ac0)
+ *
+ * 0*: Inherited from A
+ * 1: Declared in C
+ */
+ public void test1() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc1(A)");
+ assertLinkage("C", LINKAGE_ERROR, "C1");
+ recompileSpec("Cc1(Ac0)", "A");
+ assertLinkage("C", "A0", "C1");
+ }
+
+ /*
+ * Cc1(I) -> Cc1(Id0)
+ *
+ * 0*: Inherited default from I
+ * 1: Declared in C
+ */
+ public void test2() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc1(I)");
+ assertLinkage("C", LINKAGE_ERROR, "C1");
+ recompileSpec("Cc1(Id0)", "I");
+ assertLinkage("C", "I0", "C1");
+ }
+
+ /*
+ * C(Bc1(A)) -> C(Bc1(Ac0))
+ *
+ * 0*: Inherited from A
+ * 1: Inherited from B
+ */
+ public void test3() throws IOException, ReflectiveOperationException {
+ compileSpec("C(Bc1(A))");
+ assertLinkage("C", LINKAGE_ERROR, "B1");
+ recompileSpec("C(Bc1(Ac0))", "A");
+ assertLinkage("C", "A0", "B1");
+ }
+
+ /*
+ * C(B(Ac0)) -> C(Bc1(Ac0))
+ *
+ * 0: Inherited from B (through bridge)
+ * 1: Inherited from B
+ */
+ public void test4() throws IOException, ReflectiveOperationException {
+ compileSpec("C(B(Ac0))");
+ assertLinkage("C", "A0", LINKAGE_ERROR);
+ recompileSpec("C(Bc1(Ac0))", "B");
+ assertLinkage("C", "B1", "B1");
+ }
+
+ /*
+ * C(B(A)) -> C(Bc1(Ac0))
+ *
+ * 0: Inherited from B (through bridge)
+ * 1: Inherited from B
+ */
+ public void test5() throws IOException, ReflectiveOperationException {
+ compileSpec("C(B(A))");
+ assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR);
+ recompileSpec("C(Bc1(Ac0))", "A", "B");
+ assertLinkage("C", "B1", "B1");
+ }
+
+ /*
+ * C(Ac1(I)) -> C(Ac1(Id0))
+ *
+ * 0*: Inherited default from I
+ * 1: Inherited from A
+ */
+ public void test6() throws IOException, ReflectiveOperationException {
+ compileSpec("C(Ac1(I))");
+ assertLinkage("C", LINKAGE_ERROR, "A1");
+ recompileSpec("C(Ac1(Id0))", "I");
+ assertLinkage("C", "I0", "A1");
+ }
+
+ /*
+ * C(A(Id0)) -> C(Ac1(Id0))
+ *
+ * 0: Inherited from A (through bridge)
+ * 1: Inherited from A
+ */
+ public void test7() throws IOException, ReflectiveOperationException {
+ compileSpec("C(A(Id0))");
+ assertLinkage("C", "I0", LINKAGE_ERROR);
+ recompileSpec("C(Ac1(Id0))", "A");
+ assertLinkage("C", "A1", "A1");
+ }
+
+ /*
+ * C(A(I)) -> C(Ac1(Id0))
+ *
+ * 0*: Inherited from A (through bridge)
+ * 1*: Inherited from A
+ */
+ public void test8() throws IOException, ReflectiveOperationException {
+ compileSpec("C(A(I))");
+ assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR);
+ recompileSpec("C(Ac1(Id0))", "A", "I");
+ assertLinkage("C", "A1", "A1");
+ }
+
+ /*
+ * C(Id1(J)) -> C(Id1(Jd0))
+ *
+ * 0*: Inherited default from J
+ * 1: Inherited default from I
+ */
+ public void test9() throws IOException, ReflectiveOperationException {
+ compileSpec("C(Id1(J))");
+ assertLinkage("C", LINKAGE_ERROR, "I1");
+ recompileSpec("C(Id1(Jd0))", "J");
+ assertLinkage("C", "J0", "I1");
+ }
+
+ /*
+ * C(I(Jd0)) -> C(Id1(Jd0))
+ *
+ * 0: Inherited default from I (through bridge)
+ * 1: Inherited default from I
+ */
+ public void test10() throws IOException, ReflectiveOperationException {
+ compileSpec("C(I(Jd0))");
+ assertLinkage("C", "J0", LINKAGE_ERROR);
+ recompileSpec("C(Id1(Jd0))", "I");
+ assertLinkage("C", "I1", "I1");
+ }
+
+ /*
+ * C(I(J)) -> C(Id1(Jd0))
+ *
+ * 0: Inherited default from I (through bridge)
+ * 1: Inherited default from I
+ */
+ public void test11() throws IOException, ReflectiveOperationException {
+ compileSpec("C(I(J))");
+ assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR);
+ recompileSpec("C(Id1(Jd0))", "I", "J");
+ assertLinkage("C", "I1", "I1");
+ }
+
+ /*
+ * Cc2(B(Ac0)) -> Cc2(Bc1(Ac0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited from B
+ * 2: Declared in C
+ */
+ public void test12() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(B(Ac0))");
+ assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Bc1(Ac0))", "B");
+ assertLinkage("C", "C2", "B1", "C2");
+ }
+
+ /*
+ * Cc2(B(Aa0)) -> Cc2(Bc1(Aa0))
+ *
+ * 0: Bridge in C (through bridge)
+ * 1*: Inherited from B
+ * 2: Declared in C
+ */
+ public void test13() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(B(Aa0))");
+ assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Bc1(Aa0))", "B");
+ assertLinkage("C", "C2", "B1", "C2");
+ }
+
+ /*
+ * Cc2(Bc1(A)) -> Cc2(Bc1(Ac0))
+ *
+ * 0*: Inherited from A
+ * 1: Declared in C (through bridge)
+ * 2: Declared in C
+ */
+ public void test14() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(Bc1(A))");
+ assertLinkage("C", LINKAGE_ERROR, "C2", "C2");
+ recompileSpec("Cc2(Bc1(Ac0))", "A");
+ assertLinkage("C", "A0", "C2", "C2");
+ }
+
+ /*
+ * Cc2(Ba1(A)) -> Cc2(Ba1(Ac0))
+ *
+ * 0*: Inherited from A
+ * 1: Declared in C (through bridge)
+ * 2: Declared in C
+ */
+ public void test15() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(Ba1(A))");
+ assertLinkage("C", LINKAGE_ERROR, "C2", "C2");
+ recompileSpec("Cc2(Ba1(Ac0))", "A");
+ assertLinkage("C", "A0", "C2", "C2");
+ }
+
+ /*
+ * Cc2(B(A)) -> Cc2(Bc1(Ac0))
+ *
+ * 0*: Inherited from B (through bridge)
+ * 1*: Inherited from B
+ * 2: Declared in C
+ */
+ public void test16() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(B(A))");
+ assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Bc1(Ac0))", "B", "A");
+ assertLinkage("C", "B1", "B1", "C2");
+ }
+
+ /*
+ * Cc2(A(Id0)) -> Cc2(Ac1(Id0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited from A
+ * 2: Declared in C
+ */
+ public void test17() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(A(Id0))");
+ assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Ac1(Id0))", "A");
+ assertLinkage("C", "C2", "A1", "C2");
+ }
+
+ /*
+ * Cc2(A(Ia0)) -> Cc2(Ac1(Ia0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited from A
+ * 2: Declared in C
+ */
+ public void test18() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(A(Ia0))");
+ assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Ac1(Ia0))", "A");
+ assertLinkage("C", "C2", "A1", "C2");
+ }
+
+ /*
+ * Cc2(Ac1(I)) -> Cc2(Ac1(Id0))
+ *
+ * 0*: Inherited from I
+ * 1: Declared in C (through bridge)
+ * 2: Declared in C
+ */
+ public void test19() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(Ac1(I))");
+ assertLinkage("C", LINKAGE_ERROR, "C2", "C2");
+ recompileSpec("Cc2(Ac1(Id0))", "I");
+ assertLinkage("C", "I0", "C2", "C2");
+ }
+
+ /*
+ * Cc2(Aa1(I)) -> Cc2(Aa1(Id0))
+ *
+ * 0*: Inherited from I
+ * 1: Declared in C (through bridge)
+ * 2: Declared in C
+ */
+ public void test20() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(Aa1(I))");
+ assertLinkage("C", LINKAGE_ERROR, "C2", "C2");
+ recompileSpec("Cc2(Aa1(Id0))", "I");
+ assertLinkage("C", "I0", "C2", "C2");
+ }
+
+ /*
+ * Cc2(A(I)) -> Cc2(Ac1(Id0))
+ *
+ * 0*: Inherited from A (through bridge)
+ * 1*: Inherited from A
+ * 2: Declared in C
+ */
+ public void test21() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(A(I))");
+ assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Ac1(Id0))", "A", "I");
+ assertLinkage("C", "A1", "A1", "C2");
+ }
+
+ /*
+ * Cc2(J(Id0)) -> Cc2(Jd1(Id0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited default from J
+ * 2: Declared in C
+ */
+ public void test22() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(J(Id0))");
+ assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Jd1(Id0))", "J");
+ assertLinkage("C", "C2", "J1", "C2");
+ }
+
+ /*
+ * Cc2(J(Ia0)) -> Cc2(Jd1(Ia0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited default from J
+ * 2: Declared in C
+ */
+ public void test23() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(J(Ia0))");
+ assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Jd1(Ia0))", "J");
+ assertLinkage("C", "C2", "J1", "C2");
+ }
+
+ /*
+ * Cc2(Jd1(I)) -> Cc2(Jd1(Id0))
+ *
+ * 0*: Inherited default from I
+ * 1: Declared in C (through bridge)
+ * 2: Declared in C
+ */
+ public void test24() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(Jd1(I))");
+ assertLinkage("C", LINKAGE_ERROR, "C2", "C2");
+ recompileSpec("Cc2(Jd1(Id0))", "I");
+ assertLinkage("C", "I0", "C2", "C2");
+ }
+
+ /*
+ * Cc2(Ja1(I)) -> Cc2(Ja1(Id0))
+ *
+ * 0*: Inherited default from I
+ * 1: Declared in C (through bridge)
+ * 2: Declared in C
+ */
+ public void test25() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(Ja1(I))");
+ assertLinkage("C", LINKAGE_ERROR, "C2", "C2");
+ recompileSpec("Cc2(Ja1(Id0))", "I");
+ assertLinkage("C", "I0", "C2", "C2");
+ }
+
+ /*
+ * Cc2(J(I)) -> Cc2(Jd1(Id0))
+ *
+ * 0*: Inherited default from J (through bridge)
+ * 1*: Inherited default from J
+ * 2: Declared in C
+ */
+ public void test26() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(J(I))");
+ assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Jd1(Id0))", "J", "I");
+ assertLinkage("C", "J1", "J1", "C2");
+ }
+
+ /*
+ * C(Ac1, I) -> C(Ac1, Id0)
+ *
+ * 0*: Inherited default from I
+ * 1: Inherited from A
+ */
+ public void test27() throws IOException, ReflectiveOperationException {
+ compileSpec("C(Ac1,I)");
+ assertLinkage("C", LINKAGE_ERROR, "A1");
+ recompileSpec("C(Ac1,Id0)", "I");
+ assertLinkage("C", "I0", "A1");
+ }
+
+ /*
+ * C(A, Id0) -> C(Ac1, Id0)
+ *
+ * 0*: Inherited default from I
+ * 1: Inherited from A
+ */
+ public void test28() throws IOException, ReflectiveOperationException {
+ compileSpec("C(A,Id0)");
+ assertLinkage("C", "I0", LINKAGE_ERROR);
+ recompileSpec("C(Ac1,Id0)", "A");
+ assertLinkage("C", "I0", "A1");
+ }
+
+ /*
+ * C(A, I) -> C(Ac1, Id0)
+ *
+ * 0*: Inherited default from I
+ * 1: Inherited from A
+ */
+ public void test29() throws IOException, ReflectiveOperationException {
+ compileSpec("C(A,I)");
+ assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR);
+ recompileSpec("C(Ac1,Id0)", "A", "I");
+ assertLinkage("C", "I0", "A1");
+ }
+
+ /*
+ * Cc2(Ac1, I) -> Cc2(Ac1, Id0)
+ *
+ * 0*: Inherited default from I
+ * 1: Declared in C (through bridge)
+ * 2: Declared in C
+ */
+ public void test30() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(Ac1,I)");
+ assertLinkage("C", LINKAGE_ERROR, "C2", "C2");
+ recompileSpec("Cc2(Ac1,Id0)", "I");
+ assertLinkage("C", "I0", "C2", "C2");
+ }
+
+ /*
+ * Cc2(Aa1, I) -> Cc2(Aa1, Id0)
+ *
+ * 0*: Inherited default from I
+ * 1: Declared in C (through bridge)
+ * 2: Declared in C
+ */
+ public void test31() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(Aa1,I)");
+ assertLinkage("C", LINKAGE_ERROR, "C2", "C2");
+ recompileSpec("Cc2(Aa1,Id0)", "I");
+ assertLinkage("C", "I0", "C2", "C2");
+ }
+
+ /*
+ * Cc2(A, Id0) -> Cc2(Ac1, Id0)
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited from A
+ * 2: Declared in C
+ */
+ public void test32() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(A,Id0)");
+ assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Ac1,Id0)", "A");
+ assertLinkage("C", "C2", "A1", "C2");
+ }
+
+ /*
+ * Cc2(A, Ia0) -> Cc2(Ac1, Ia0)
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited from A
+ * 2: Declared in C
+ */
+ public void test33() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(A,Ia0)");
+ assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Ac1,Ia0)", "A");
+ assertLinkage("C", "C2", "A1", "C2");
+ }
+
+ /*
+ * Cc2(A, I) -> Cc2(Ac1, Id0)
+ *
+ * 0*: Inherited from A
+ * 1*: Inherited default from I
+ * 2: Declared in C
+ */
+ public void test34() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(A,I)");
+ assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Ac1,Id0)", "A", "I");
+ assertLinkage("C", "I0", "A1", "C2");
+ }
+
+ /*
+ * Cc2(Id0, J) -> Cc2(Id0, Jd1)
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited default from J
+ * 2: Declared in C
+ */
+ public void test35() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(Id0,J)");
+ assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Id0,Jd1)", "J");
+ assertLinkage("C", "C2", "J1", "C2");
+ }
+
+ /*
+ * Cc2(Ia0, J) -> Cc2(Ia0, Jd1)
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited default from J
+ * 2: Declared in C
+ */
+ public void test36() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(Ia0,J)");
+ assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Ia0,Jd1)", "J");
+ assertLinkage("C", "C2", "J1", "C2");
+ }
+
+ /*
+ * Cc2(I, J) -> Cc2(Id0, Jd1)
+ *
+ * 0*: Inherited default from I
+ * 1*: Inherited default from J
+ * 2: Declared in C
+ */
+ public void test37() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(I,J)");
+ assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Id0,Jd1)", "I", "J");
+ assertLinkage("C", "I0", "J1", "C2");
+ }
+
+ /*
+ * C(A(Id0), J(Id0)) -> C(Ac1(Id0), J(Id0))
+ *
+ * 0: Inherited default from I
+ * 0*: Inherited from A (through bridge)
+ * 1*: Inherited from A
+ */
+ public void test38() throws IOException, ReflectiveOperationException {
+ compileSpec("C(A(Id0),J(Id0))");
+ assertLinkage("C", "I0", LINKAGE_ERROR);
+ recompileSpec("C(Ac1(Id0),J(Id0))", "A");
+ assertLinkage("C", "A1", "A1");
+ }
+
+ /*
+ * C(A(Id0), J(Id0)) -> C(A(Id0), Jd1(Id0))
+ *
+ * 0: Inherited default from I
+ * 0: Inherited default from J (through bridge)
+ * 1*: Inherited default from J
+ */
+ public void test39() throws IOException, ReflectiveOperationException {
+ compileSpec("C(A(Id0),J(Id0))");
+ assertLinkage("C", "I0", LINKAGE_ERROR);
+ recompileSpec("C(A(Id0),Jd1(Id0))", "J");
+ assertLinkage("C", "J1", "J1");
+ }
+
+ /*
+ * C(A(Id0), J(Id0)) -> C(Ac2(Id0), Jd1(Id0))
+ *
+ * 0: Inherited default from I
+ * 0*: Inherited from A (new bridge in A beats new bridge in J)
+ * 1*: Inherited default from J
+ * 2: Inherited from A
+ */
+ public void test40() throws IOException, ReflectiveOperationException {
+ compileSpec("C(A(Id0),J(Id0))");
+ assertLinkage("C", "I0", LINKAGE_ERROR);
+ recompileSpec("C(Ac2(Id0),Jd1(Id0))", "A", "J");
+ assertLinkage("C", "A2", "J1", "A2");
+ }
+
+ /*
+ * C(J(Id0), K(Id0)) -> C(Jd1(Id0), K(Id0))
+ *
+ * 0: Inherited from I
+ * 0*: Inherited default from J (through bridge)
+ * 1: Inherited default from J
+ */
+ public void test41() throws IOException, ReflectiveOperationException {
+ compileSpec("C(J(Id0),K(Id0))");
+ assertLinkage("C", "I0", LINKAGE_ERROR);
+ recompileSpec("C(Jd1(Id0),K(Id0))", "J");
+ assertLinkage("C", "J1", "J1");
+ }
+
+ /*
+ * C(Ac2(Id0), J(Id0)) -> C(Ac2(Id0), Jd1(Id0))
+ *
+ * 0: Inherited from A (bridge in A beats new bridge in J)
+ * 1*: Inherited default from J
+ * 2: Inherited from A
+ */
+ public void test42() throws IOException, ReflectiveOperationException {
+ compileSpec("C(Ac2(Id0),J(Id0))");
+ assertLinkage("C", "A2", LINKAGE_ERROR, "A2");
+ recompileSpec("C(Ac2(Id0),Jd1(Id0))", "J");
+ assertLinkage("C", "A2", "J1", "A2");
+ }
+
+ /*
+ * C(Ac2(Ia0), J(Ia0)) -> C(Ac2(Ia0), Jd1(Ia0))
+ *
+ * 0: Inherited from A (bridge in A beats new bridge in J)
+ * 1*: Inherited default from J
+ * 2: Inherited from A
+ */
+ public void test43() throws IOException, ReflectiveOperationException {
+ compileSpec("C(Ac2(Ia0),J(Ia0))");
+ assertLinkage("C", "A2", LINKAGE_ERROR, "A2");
+ recompileSpec("C(Ac2(Ia0),Jd1(Ia0))", "J");
+ assertLinkage("C", "A2", "J1", "A2");
+ }
+
+ /*
+ * C(A(Id0), Jd1(Id0)) -> C(Ac2(Id0), Jd1(Id0))
+ *
+ * 0: Inherited from J
+ * 0*: Inherited from A (new bridge in A beats bridge in J)
+ * 1: Inherited default from J
+ * 2*: Inherited from A
+ */
+ public void test44() throws IOException, ReflectiveOperationException {
+ compileSpec("C(A(Id0),Jd1(Id0))");
+ assertLinkage("C", "J1", "J1", LINKAGE_ERROR);
+ recompileSpec("C(Ac2(Id0),Jd1(Id0))", "A");
+ assertLinkage("C", "A2", "J1", "A2");
+ }
+
+ /*
+ * C(A(Ia0), Jd1(Ia0)) -> C(Ac2(Ia0), Jd1(Ia0))
+ *
+ * 0: Inherited from J
+ * 0*: Inherited from A (new bridge in A beats bridge in J)
+ * 1: Inherited default from J
+ * 2*: Inherited from A
+ */
+ public void test45() throws IOException, ReflectiveOperationException {
+ compileSpec("C(A(Ia0),Jd1(Ia0))");
+ assertLinkage("C", "J1", "J1", LINKAGE_ERROR);
+ recompileSpec("C(Ac2(Ia0),Jd1(Ia0))", "A");
+ assertLinkage("C", "A2", "J1", "A2");
+ }
+
+ /*
+ * Cc2(A(Id0), J(Id0)) -> Cc2(Ac1(Id0), J(Id0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited from A
+ * 2: Declared in C
+ */
+ public void test46() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(A(Id0),J(Id0))");
+ assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Ac1(Id0),J(Id0))", "A");
+ assertLinkage("C", "C2", "A1", "C2");
+ }
+
+ /*
+ * Cc2(A(Ia0), J(Ia0)) -> Cc2(Ac1(Ia0), J(Ia0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited from A
+ * 2: Declared in C
+ */
+ public void test47() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(A(Ia0),J(Ia0))");
+ assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Ac1(Ia0),J(Ia0))", "A");
+ assertLinkage("C", "C2", "A1", "C2");
+ }
+
+ /*
+ * Cc2(A(Id0), J(Id0)) -> Cc2(A(Id0), Jd1(Id0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited default from J
+ * 2: Declared in C
+ */
+ public void test48() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(A(Id0),J(Id0))");
+ assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(A(Id0),Jd1(Id0))", "J");
+ assertLinkage("C", "C2", "J1", "C2");
+ }
+
+ /*
+ * Cc2(A(Ia0), J(Ia0)) -> Cc2(A(Ia0), Jd1(Ia0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited default from J
+ * 2: Declared in C
+ */
+ public void test49() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(A(Ia0),J(Ia0))");
+ assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(A(Ia0),Jd1(Ia0))", "J");
+ assertLinkage("C", "C2", "J1", "C2");
+ }
+
+
+ /*
+ * Cc3(A(Id0), J(Id0)) -> Cc3(Ac1(Id0), Jd2(Id0))
+ *
+ * 0: Bridge in C
+ * 1*: Inherited from A
+ * 2*: Inherited default from J
+ * 3: Declared in C
+ */
+ public void test50() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc3(A(Id0),J(Id0))");
+ assertLinkage("C", "C3", LINKAGE_ERROR, LINKAGE_ERROR, "C3");
+ recompileSpec("Cc3(Ac1(Id0),Jd2(Id0))", "A", "J");
+ assertLinkage("C", "C3", "A1", "J2", "C3");
+ }
+
+ /*
+ * Cc3(A(Ia0), J(Ia0)) -> Cc3(Ac1(Ia0), Jd2(Ia0))
+ *
+ * 0: Bridge in C
+ * 1*: Inherited from A
+ * 2*: Inherited default from J
+ * 3: Declared in C
+ */
+ public void test51() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc3(A(Ia0),J(Ia0))");
+ assertLinkage("C", "C3", LINKAGE_ERROR, LINKAGE_ERROR, "C3");
+ recompileSpec("Cc3(Ac1(Ia0),Jd2(Ia0))", "A", "J");
+ assertLinkage("C", "C3", "A1", "J2", "C3");
+ }
+
+ /*
+ * Cc2(J(Id0), K(Id0)) -> Cc2(Jd1(Id0), K(Id0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited default from J
+ * 2: Declared in C
+ */
+ public void test52() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(J(Id0),K(Id0))");
+ assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Jd1(Id0),K(Id0))", "J");
+ assertLinkage("C", "C2", "J1", "C2");
+ }
+
+ /*
+ * Cc2(J(Ia0), K(Ia0)) -> Cc2(Jd1(Ia0), K(Ia0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited default from J
+ * 2: Declared in C
+ */
+ public void test53() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc2(J(Ia0),K(Ia0))");
+ assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+ recompileSpec("Cc2(Jd1(Ia0),K(Ia0))", "J");
+ assertLinkage("C", "C2", "J1", "C2");
+ }
+
+ /*
+ * Cc3(J(Id0), K(Id0)) -> Cc3(Jd1(Id0), Kd2(Id0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited default from J
+ * 2*: Inherited default from K
+ * 3: Declared in C
+ */
+ public void test54() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc3(J(Id0),K(Id0))");
+ assertLinkage("C", "C3", LINKAGE_ERROR, LINKAGE_ERROR, "C3");
+ recompileSpec("Cc3(Jd1(Id0),Kd2(Id0))", "J", "K");
+ assertLinkage("C", "C3", "J1", "K2", "C3");
+ }
+
+ /*
+ * Cc3(J(Ia0), K(Ia0)) -> Cc3(Jd1(Ia0), Kd2(Ia0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited default from J
+ * 2*: Inherited default from K
+ * 3: Declared in C
+ */
+ public void test55() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc3(J(Ia0),K(Ia0))");
+ assertLinkage("C", "C3", LINKAGE_ERROR, LINKAGE_ERROR, "C3");
+ recompileSpec("Cc3(Jd1(Ia0),Kd2(Ia0))", "J", "K");
+ assertLinkage("C", "C3", "J1", "K2", "C3");
+ }
+
+ /*
+ * Cc3(Ac1(Id0), J(Id0)) -> Cc3(Ac1(Id0), Jd2(Id0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1: Declared in C (through bridge)
+ * 2*: Inherited default from J
+ * 3: Declared in C
+ */
+ public void test56() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc3(Ac1(Id0),J(Id0))");
+ assertLinkage("C", "C3", "C3", LINKAGE_ERROR, "C3");
+ recompileSpec("Cc3(Ac1(Id0),Jd2(Id0))", "J");
+ assertLinkage("C", "C3", "C3", "J2", "C3");
+ }
+
+ /*
+ * Cc3(Ac1(Ia0), J(Ia0)) -> Cc3(Ac1(Ia0), Jd2(Ia0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1: Declared in C (through bridge)
+ * 2*: Inherited default from J
+ * 3: Declared in C
+ */
+ public void test57() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc3(Ac1(Ia0),J(Ia0))");
+ assertLinkage("C", "C3", "C3", LINKAGE_ERROR, "C3");
+ recompileSpec("Cc3(Ac1(Ia0),Jd2(Ia0))", "J");
+ assertLinkage("C", "C3", "C3", "J2", "C3");
+ }
+
+ /*
+ * Cc3(Aa1(Id0), J(Id0)) -> Cc3(Aa1(Id0), Jd2(Id0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1: Declared in C (through bridge)
+ * 2*: Inherited default from J
+ * 3: Declared in C
+ */
+ public void test58() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc3(Aa1(Id0),J(Id0))");
+ assertLinkage("C", "C3", "C3", LINKAGE_ERROR, "C3");
+ recompileSpec("Cc3(Aa1(Id0),Jd2(Id0))", "J");
+ assertLinkage("C", "C3", "C3", "J2", "C3");
+ }
+
+ /*
+ * Cc3(Aa1(Ia0), J(Ia0)) -> Cc3(Aa1(Ia0), Jd2(Ia0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1: Declared in C (through bridge)
+ * 2*: Inherited default from J
+ * 3: Declared in C
+ */
+ public void test59() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc3(Aa1(Ia0),J(Ia0))");
+ assertLinkage("C", "C3", "C3", LINKAGE_ERROR, "C3");
+ recompileSpec("Cc3(Aa1(Ia0),Jd2(Ia0))", "J");
+ assertLinkage("C", "C3", "C3", "J2", "C3");
+ }
+
+ /*
+ * Cc3(A(Id0), Jd2(Id0)) -> Cc3(Ac1(Id0), Jd2(Id0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited from A
+ * 2: Declared in C (through bridge)
+ * 3: Declared in C
+ */
+ public void test60() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc3(A(Id0),Jd2(Id0))");
+ assertLinkage("C", "C3", LINKAGE_ERROR, "C3", "C3");
+ recompileSpec("Cc3(Ac1(Id0),Jd2(Id0))", "A");
+ assertLinkage("C", "C3", "A1", "C3", "C3");
+ }
+
+ /*
+ * Cc3(A(Im0), Jd2(Ia0)) -> Cc3(Ac1(Im0), Jd2(Ia0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited from A
+ * 2: Declared in C (through bridge)
+ * 3: Declared in C
+ */
+ public void test61() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc3(A(Ia0),Jd2(Ia0))");
+ assertLinkage("C", "C3", LINKAGE_ERROR, "C3", "C3");
+ recompileSpec("Cc3(Ac1(Ia0),Jd2(Ia0))", "A");
+ assertLinkage("C", "C3", "A1", "C3", "C3");
+ }
+
+ /*
+ * Cc3(A(Im0), Ja2(Id0)) -> Cc3(Ac1(Id0), Ja2(Id0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited from A
+ * 2: Declared in C (through bridge)
+ * 3: Declared in C
+ */
+ public void test62() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc3(A(Id0),Ja2(Id0))");
+ assertLinkage("C", "C3", LINKAGE_ERROR, "C3", "C3");
+ recompileSpec("Cc3(Ac1(Id0),Ja2(Id0))", "A");
+ assertLinkage("C", "C3", "A1", "C3", "C3");
+ }
+
+ /*
+ * Cc3(A(Im0), Ja2(Ia0)) -> Cc3(Ac1(Ia0), Ja2(Ia0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1*: Inherited from A
+ * 2: Declared in C (through bridge)
+ * 3: Declared in C
+ */
+ public void test63() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc3(A(Ia0),Ja2(Ia0))");
+ assertLinkage("C", "C3", LINKAGE_ERROR, "C3", "C3");
+ recompileSpec("Cc3(Ac1(Ia0),Ja2(Ia0))", "A");
+ assertLinkage("C", "C3", "A1", "C3", "C3");
+ }
+
+ /*
+ * Cc3(Jd1(Id0), K(Id0)) -> Cc3(Jd1(Id0), Kd2(Id0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1: Declared in C (through bridge)
+ * 2*: Inherited default from K
+ * 3: Declared in C
+ */
+ public void test64() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc3(Jd1(Id0),K(Id0))");
+ assertLinkage("C", "C3", "C3", LINKAGE_ERROR, "C3");
+ recompileSpec("Cc3(Jd1(Id0),Kd2(Id0))", "K");
+ assertLinkage("C", "C3", "C3", "K2", "C3");
+ }
+
+ /*
+ * Cc3(Jd1(Ia0), K(Ia0)) -> Cc3(Jd1(Ia0), Kd2(Ia0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1: Declared in C (through bridge)
+ * 2*: Inherited default from K
+ * 3: Declared in C
+ */
+ public void test65() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc3(Jd1(Ia0),K(Ia0))");
+ assertLinkage("C", "C3", "C3", LINKAGE_ERROR, "C3");
+ recompileSpec("Cc3(Jd1(Ia0),Kd2(Ia0))", "K");
+ assertLinkage("C", "C3", "C3", "K2", "C3");
+ }
+
+ /*
+ * Cc3(Ja1(Id0), K(Id0)) -> Cc3(Ja1(Id0), Kd2(Id0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1: Declared in C (through bridge)
+ * 2*: Inherited default from K
+ * 3: Declared in C
+ */
+ public void test66() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc3(Jd1(Id0),K(Id0))");
+ assertLinkage("C", "C3", "C3", LINKAGE_ERROR, "C3");
+ recompileSpec("Cc3(Jd1(Id0),Kd2(Id0))", "K");
+ assertLinkage("C", "C3", "C3", "K2", "C3");
+ }
+
+ /*
+ * Cc3(Ja1(Ia0), K(Ia0)) -> Cc3(Ja1(Ia0), Kd2(Ia0))
+ *
+ * 0: Declared in C (through bridge)
+ * 1: Declared in C (through bridge)
+ * 2*: Inherited default from K
+ * 3: Declared in C
+ */
+ public void test67() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc3(Jd1(Ia0),K(Ia0))");
+ assertLinkage("C", "C3", "C3", LINKAGE_ERROR, "C3");
+ recompileSpec("Cc3(Jd1(Ia0),Kd2(Ia0))", "K");
+ assertLinkage("C", "C3", "C3", "K2", "C3");
+ }
+
+ // Dan's set A
+ public void testA1() throws IOException, ReflectiveOperationException {
+ compileSpec("C(Id0)");
+ assertLinkage("C", "I0");
+ }
+
+ public void testA2() throws IOException, ReflectiveOperationException {
+ compileSpec("C(A(Id0))");
+ assertLinkage("C", "I0");
+ }
+
+ public void testA3() throws IOException, ReflectiveOperationException {
+ compileSpec("C(A(Id0),J)");
+ assertLinkage("C", "I0");
+ }
+
+ public void testA4() throws IOException, ReflectiveOperationException {
+ compileSpec("D(C(Id0),Jd0(Id0))");
+ assertLinkage("D", "J0");
+ assertLinkage("C", "I0");
+ }
+
+ public void testA5() throws IOException, ReflectiveOperationException {
+ compileSpec("C(A(Id0),Jd0)",
+ "compiler.err.types.incompatible.unrelated.defaults");
+ }
+
+ public void testA6() throws IOException, ReflectiveOperationException {
+ compileSpec("C(A(Ia0,Jd0))",
+ "compiler.err.does.not.override.abstract",
+ "compiler.err.types.incompatible.abstract.default");
+ }
+
+ public void testA7() throws IOException, ReflectiveOperationException {
+ compileSpec("C(A(Id0,Jd0))",
+ "compiler.err.types.incompatible.unrelated.defaults");
+ }
+
+ public void testA8() throws IOException, ReflectiveOperationException {
+ compileSpec("C(A(Ia0),J)", "compiler.err.does.not.override.abstract");
+ }
+
+ public void testA9() throws IOException, ReflectiveOperationException {
+ compileSpec("C(Ac0(Id0))");
+ assertLinkage("C", "A0");
+ }
+
+ public void testA10() throws IOException, ReflectiveOperationException {
+ compileSpec("C(Aa0,I)", "compiler.err.does.not.override.abstract");
+ }
+
+ public void testA11() throws IOException, ReflectiveOperationException {
+ compileSpec("C(Ac0,Id0)");
+ assertLinkage("C", "A0");
+ }
+
+ // Dan's set B
+
+ /* B1 can't be done, needs a second concrete class D
+ public void testB1() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc1(Dc0)");
+ assertLinkage("C", "C1", "C1");
+ assertLinkage("D", "A0", LINKAGE_ERROR);
+ }
+ */
+
+ public void testB2() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc1(Ac0)");
+ assertLinkage("C", "C1", "C1");
+ }
+
+ //??? B3 seems to suggest that we should create an abstract class
+ //public void testB3() throws IOException, ReflectiveOperationException {
+ // compileSpec("Ba1(Cc0)");
+ // assertLinkage("B", "C0", "A1");
+ //}
+
+ // B4 needs too many classes
+
+ public void testB5() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc1(Aa1(Id0))");
+ assertLinkage("C", "C1", "C1");
+ }
+
+ public void testB6() throws IOException, ReflectiveOperationException {
+ compileSpec("C(Ac1(Id0))");
+ assertLinkage("C", "A1", "A1");
+ }
+
+ public void testB7() throws IOException, ReflectiveOperationException {
+ compileSpec("Cc1(Id0)");
+ assertLinkage("C", "C1", "C1");
+ }
+
+ public void testB8() throws IOException, ReflectiveOperationException {
+ compileSpec("C(Jd1(Id0))");
+ assertLinkage("C", "J1", "J1");
+ }
+
+ // B9 needs too many classes
+
+ // The rest of Dan's tests need generics
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/bridge/template_tests/TEST.properties Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,7 @@
+# This file identifies root(s) of the test-ng hierarchy.
+
+
+
+TestNG.dirs = .
+
+lib.dirs = /lib/combo
--- a/langtools/test/tools/javac/lambda/mostSpecific/StructuralMostSpecificTest.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/mostSpecific/StructuralMostSpecificTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -197,7 +197,7 @@
"class Test {\n" +
" void m(SAM1 s) { }\n" +
" void m(SAM2 s) { }\n" +
- " { m(x->{ #LR }); }\n" +
+ " { m((#A1 x)->{ #LR }); }\n" +
"}\n";
String source;
@@ -236,14 +236,17 @@
void check() {
checkCount.incrementAndGet();
+ if (ak1 != ak2)
+ return;
+
if (!lrk.compatibleWith(rt1) || !lrk.compatibleWith(rt2))
return;
if (lrk.needsConversion(rt1) != lrk.needsConversion(rt2))
return;
- boolean m1MoreSpecific = moreSpecific(rt1, rt2, ek1, ek2, ak1, ak2);
- boolean m2MoreSpecific = moreSpecific(rt2, rt1, ek2, ek1, ak2, ak1);
+ boolean m1MoreSpecific = rt1.moreSpecificThan(rt2);
+ boolean m2MoreSpecific = rt2.moreSpecificThan(rt1);
boolean ambiguous = (m1MoreSpecific == m2MoreSpecific);
@@ -268,17 +271,6 @@
}
}
- boolean moreSpecific(RetTypeKind rk1, RetTypeKind rk2, ExceptionKind ek1,
- ExceptionKind ek2, ArgTypeKind ak1, ArgTypeKind ak2) {
- if (!rk1.moreSpecificThan(rk2))
- return false;
-
- if (ak1 != ak2)
- return false;
-
- return true;
- }
-
static class DiagnosticChecker
implements javax.tools.DiagnosticListener<JavaFileObject> {
--- a/langtools/test/tools/javac/lambda/typeInference/InferenceTest5.java Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 8003280
- * @summary Add lambda tests
- * This test is for overloaded methods, verify that the specific method is
- selected when type inference occurs
- * @compile InferenceTest5.java
- * @run main InferenceTest5
- */
-
-import java.util.List;
-import java.io.File;
-
-public class InferenceTest5 {
-
- private static void assertTrue(boolean b) {
- if(!b)
- throw new AssertionError();
- }
-
- public static void main(String[] args) {
- InferenceTest5 test = new InferenceTest5();
- int n = test.method1((a, b) -> {} );
- assertTrue(n == 1);
-
- n = test.method1(() -> null);
- assertTrue(n == 2);
-
- n = test.method1(a -> null);
- assertTrue(n == 3);
-
- n = test.method1(a -> {});
- assertTrue(n == 4);
-
- n = test.method1(() -> {});
- assertTrue(n == 5);
-
- n = test.method1((a, b) -> 0);
- assertTrue(n == 6);
-
- n = test.method1((a, b) -> null);
- assertTrue(n == 6);
-
- n = test.method1((a, b) -> null, (a, b) -> null);
- assertTrue(n == 7);
- }
-
- int method1(SAM1<String> s) {
- return 1;
- }
-
- int method1(SAM2 s) {
- return 2;
- }
-
- int method1(SAM3 s) {
- return 3;
- }
-
- int method1(SAM4 s) {
- return 4;
- }
-
- int method1(SAM5 s) {
- return 5;
- }
-
- int method1(SAM6<?, ? super Integer> s) {
- return 6;
- }
-
- int method1(SAM6<?, ?>... s) {
- return 7;
- }
-
- static interface SAM1<T> {
- void foo(List<T> a, List<T> b);
- }
-
- static interface SAM2 {
- List<String> foo();
- }
-
- static interface SAM3 {
- String foo(int a);
- }
-
- static interface SAM4 {
- void foo(List<File> a);
- }
-
- static interface SAM5 {
- void foo();
- }
-
- static interface SAM6<T, V> {
- V get(T t, T t2);
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/typeInference/InferenceTest6.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,26 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8003280 8016177
+ * @summary Add lambda tests
+ * Missing cast to SAM type that causes type inference to not work.
+ * @compile -XDrawDiagnostics InferenceTest6.java
+ */
+
+import java.util.*;
+
+public class InferenceTest6 {
+ public static void main(String[] args) {
+ InferenceTest6 test = new InferenceTest6();
+ test.method1(n -> {});
+ test.method1((SAM1<String>)n -> {});
+ test.method1((SAM1<Integer>)n -> {n++;});
+ test.method1((SAM1<Comparator<String>>)n -> {List<String> list = Arrays.asList("string1", "string2"); Collections.sort(list,n);});
+ test.method1((SAM1<Thread>)n -> {n.start();});
+ }
+
+ interface SAM1<X> {
+ void m1(X arg);
+ }
+
+ <X> void method1(SAM1<X> s) {}
+}
--- a/langtools/test/tools/javac/lambda/typeInference/InferenceTest_neg1_2.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/typeInference/InferenceTest_neg1_2.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,4 +1,5 @@
InferenceTest_neg1_2.java:14:13: compiler.err.ref.ambiguous: method, kindname.method, method(InferenceTest_neg1_2.SAM4<java.lang.Double,java.lang.String>), InferenceTest_neg1_2, kindname.method, method(InferenceTest_neg1_2.SAM5<java.lang.Integer>), InferenceTest_neg1_2
-InferenceTest_neg1_2.java:15:13: compiler.err.ref.ambiguous: method, kindname.method, method(InferenceTest_neg1_2.SAM2), InferenceTest_neg1_2, kindname.method, method(InferenceTest_neg1_2.SAM4<java.lang.Double,java.lang.String>), InferenceTest_neg1_2
-InferenceTest_neg1_2.java:16:13: compiler.err.ref.ambiguous: method, kindname.method, method(InferenceTest_neg1_2.SAM3<java.lang.Integer>), InferenceTest_neg1_2, kindname.method, method(InferenceTest_neg1_2.SAM5<java.lang.Integer>), InferenceTest_neg1_2
-3 errors
+InferenceTest_neg1_2.java:15:13: compiler.err.ref.ambiguous: method, kindname.method, method(InferenceTest_neg1_2.SAM4<java.lang.Double,java.lang.String>), InferenceTest_neg1_2, kindname.method, method(InferenceTest_neg1_2.SAM5<java.lang.Integer>), InferenceTest_neg1_2
+InferenceTest_neg1_2.java:16:13: compiler.err.ref.ambiguous: method, kindname.method, method(InferenceTest_neg1_2.SAM4<java.lang.Double,java.lang.String>), InferenceTest_neg1_2, kindname.method, method(InferenceTest_neg1_2.SAM5<java.lang.Integer>), InferenceTest_neg1_2
+InferenceTest_neg1_2.java:16:20: compiler.err.cant.apply.symbol: kindname.method, method, InferenceTest_neg1_2.SAM4<java.lang.Double,java.lang.String>, @597, kindname.class, InferenceTest_neg1_2, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: int, java.lang.String)))
+4 errors
--- a/langtools/test/tools/javac/lambda/typeInference/InferenceTest_neg5.java Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 8003280
- * @summary Add lambda tests
- * Missing cast to SAM type that causes type inference to not work.
- * @compile/fail/ref=InferenceTest_neg5.out -XDrawDiagnostics InferenceTest_neg5.java
- */
-
-import java.util.*;
-
-public class InferenceTest_neg5 {
- public static void main(String[] args) {
- InferenceTest_neg5 test = new InferenceTest_neg5();
- test.method1(n -> {});
- test.method1((SAM1<String>)n -> {});
- test.method1((SAM1<Integer>)n -> {n++;});
- test.method1((SAM1<Comparator<String>>)n -> {List<String> list = Arrays.asList("string1", "string2"); Collections.sort(list,n);});
- test.method1((SAM1<Thread>)n -> {n.start();});
- }
-
- interface SAM1<X> {
- void m1(X arg);
- }
-
- <X> void method1(SAM1<X> s) {}
-}
--- a/langtools/test/tools/javac/lambda/typeInference/InferenceTest_neg5.out Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-InferenceTest_neg5.java:14:21: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: X)
-1 error
--- a/langtools/test/tools/javac/lambda/typeInference/combo/TypeInferenceComboTest.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lambda/typeInference/combo/TypeInferenceComboTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -227,12 +227,7 @@
}
else if (lambdaBodyType != LambdaBody.RETURN_ARG)
return false;
- if ( genericDeclKind == GenericDeclKind.GENERIC_NOBOUND ||
- genericDeclKind == GenericDeclKind.GENERIC_BOUND ) {
- if ( parameterType == TypeKind.GENERIC &&
- parameterKind == ParameterKind.IMPLICIT) //cyclic inference
- return false;
- }
+
return true;
}
--- a/langtools/test/tools/javac/lib/DPrinter.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/lib/DPrinter.java Sat Sep 14 20:43:34 2013 +0100
@@ -49,7 +49,7 @@
import com.sun.source.util.TaskListener;
import com.sun.source.util.Trees;
import com.sun.tools.javac.api.JavacTrees;
-import com.sun.tools.javac.code.Annotations;
+import com.sun.tools.javac.code.SymbolMetadata;
import com.sun.tools.javac.code.Attribute;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Kinds;
@@ -186,21 +186,21 @@
FULL
};
- public void printAnnotations(String label, Annotations annotations) {
+ public void printAnnotations(String label, SymbolMetadata annotations) {
printAnnotations(label, annotations, Details.FULL);
}
- protected void printAnnotations(String label, Annotations annotations, Details details) {
+ protected void printAnnotations(String label, SymbolMetadata annotations, Details details) {
if (annotations == null) {
printNull(label);
} else {
// no SUMMARY format currently available to use
// use reflection to get at private fields
- Object DECL_NOT_STARTED = getField(null, Annotations.class, "DECL_NOT_STARTED");
- Object DECL_IN_PROGRESS = getField(null, Annotations.class, "DECL_IN_PROGRESS");
- Object attributes = getField(annotations, Annotations.class, "attributes");
- Object type_attributes = getField(annotations, Annotations.class, "type_attributes");
+ Object DECL_NOT_STARTED = getField(null, SymbolMetadata.class, "DECL_NOT_STARTED");
+ Object DECL_IN_PROGRESS = getField(null, SymbolMetadata.class, "DECL_IN_PROGRESS");
+ Object attributes = getField(annotations, SymbolMetadata.class, "attributes");
+ Object type_attributes = getField(annotations, SymbolMetadata.class, "type_attributes");
if (!showEmptyItems) {
if (attributes instanceof List && ((List) attributes).isEmpty()
--- a/langtools/test/tools/javac/processing/model/element/TestMissingElement/TestMissingElement.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/processing/model/element/TestMissingElement/TestMissingElement.java Sat Sep 14 20:43:34 2013 +0100
@@ -31,6 +31,7 @@
* @compile/fail/ref=TestMissingElement.ref -proc:only -XprintRounds -XDrawDiagnostics -processor TestMissingElement InvalidSource.java
*/
+import java.io.PrintWriter;
import java.util.*;
import javax.annotation.processing.*;
import javax.lang.model.element.*;
@@ -38,7 +39,18 @@
import javax.lang.model.util.*;
import static javax.tools.Diagnostic.Kind.*;
+import com.sun.tools.javac.processing.JavacProcessingEnvironment;
+import com.sun.tools.javac.util.Log;
+
public class TestMissingElement extends JavacTestingAbstractProcessor {
+ private PrintWriter out;
+
+ @Override
+ public void init(ProcessingEnvironment env) {
+ super.init(env);
+ out = ((JavacProcessingEnvironment) env).getContext().get(Log.outKey);
+ }
+
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (TypeElement te: ElementFilter.typesIn(roundEnv.getRootElements())) {
@@ -70,13 +82,13 @@
}
private void checkInterfaces(TypeElement te, String expect) {
- System.err.println("check interfaces: " + te + " -- " + expect);
+ out.println("check interfaces: " + te + " -- " + expect);
String found = asString(te.getInterfaces(), ", ");
checkEqual("interfaces", te, found, expect);
}
private void checkSupertype(TypeElement te, String expect) {
- System.err.println("check supertype: " + te + " -- " + expect);
+ out.println("check supertype: " + te + " -- " + expect);
String found = asString(te.getSuperclass());
checkEqual("supertype", te, found, expect);
}
@@ -85,7 +97,7 @@
if (found.equals(expect)) {
// messager.printMessage(NOTE, "expected " + label + " found: " + expect, te);
} else {
- System.err.println("unexpected " + label + ": " + te + "\n"
+ out.println("unexpected " + label + ": " + te + "\n"
+ " found: " + found + "\n"
+ "expect: " + expect);
messager.printMessage(ERROR, "unexpected " + label + " found: " + found + "; expected: " + expect, te);
--- a/langtools/test/tools/javac/processing/model/element/TestMissingElement/TestMissingElement.ref Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/processing/model/element/TestMissingElement/TestMissingElement.ref Sat Sep 14 20:43:34 2013 +0100
@@ -2,6 +2,24 @@
input files: {ExpectInterfaces, ExpectSupertype, OK, InvalidSource}
annotations: [ExpectSupertype, ExpectInterfaces]
last round: false
+check supertype: InvalidSource.TestClassMissingClassA -- !:empty clss A!
+check supertype: InvalidSource.TestClassMissingClassAB -- !:empty clss (pkg A).B!
+check supertype: InvalidSource.TestClassMissingClass_juA -- !:empty clss (pkg java.util).A!
+check supertype: InvalidSource.TestClassTMissingClassAT -- !:empty clss A!<tvar T>
+check interfaces: InvalidSource.TestClassMissingIntfA -- !:empty intf A!
+check interfaces: InvalidSource.TestClassMissingIntfAB -- !:empty intf (pkg A).B!
+check interfaces: InvalidSource.TestClassMissingIntfAOK -- !:empty intf A!, intf OK
+check interfaces: InvalidSource.TestClassOKMissingIntfA -- intf OK, !:empty intf A!
+check interfaces: InvalidSource.TestClassMissingIntfA_B -- !:empty intf A!, !:empty intf B!
+check interfaces: InvalidSource.TestIntfMissingIntfA -- !:empty intf A!
+check interfaces: InvalidSource.TestIntfMissingIntfAOK -- !:empty intf A!, intf OK
+check interfaces: InvalidSource.TestIntfOKMissingIntfA -- intf OK, !:empty intf A!
+check interfaces: InvalidSource.TestIntfMissingIntfAB -- !:empty intf A!, !:empty intf B!
+check interfaces: InvalidSource.TestClassTMissingIntfAT -- !:empty intf A!<tvar T>
+check interfaces: InvalidSource.TestClassTMissingIntfAT_B -- !:empty intf A!<tvar T>, !:empty intf B!
+check interfaces: InvalidSource.TestIntfTMissingIntfAT -- !:empty intf A!<tvar T>
+check interfaces: InvalidSource.TestIntfTMissingIntfAT_B -- !:empty intf A!<tvar T>, !:empty intf B!
+check interfaces: InvalidSource.TestClassListMissingX -- intf (pkg java.util).List<!:empty clss X!>
Round 2:
input files: {}
annotations: []
@@ -28,22 +46,4 @@
InvalidSource.java:103:51: compiler.err.cant.resolve.location: kindname.class, A, , , (compiler.misc.location: kindname.class, InvalidSource, null)
InvalidSource.java:103:57: compiler.err.cant.resolve.location: kindname.class, B, , , (compiler.misc.location: kindname.class, InvalidSource, null)
InvalidSource.java:106:58: compiler.err.cant.resolve.location: kindname.class, X, , , (compiler.misc.location: kindname.class, InvalidSource, null)
-22 errors
-check supertype: InvalidSource.TestClassMissingClassA -- !:empty clss A!
-check supertype: InvalidSource.TestClassMissingClassAB -- !:empty clss (pkg A).B!
-check supertype: InvalidSource.TestClassMissingClass_juA -- !:empty clss (pkg java.util).A!
-check supertype: InvalidSource.TestClassTMissingClassAT -- !:empty clss A!<tvar T>
-check interfaces: InvalidSource.TestClassMissingIntfA -- !:empty intf A!
-check interfaces: InvalidSource.TestClassMissingIntfAB -- !:empty intf (pkg A).B!
-check interfaces: InvalidSource.TestClassMissingIntfAOK -- !:empty intf A!, intf OK
-check interfaces: InvalidSource.TestClassOKMissingIntfA -- intf OK, !:empty intf A!
-check interfaces: InvalidSource.TestClassMissingIntfA_B -- !:empty intf A!, !:empty intf B!
-check interfaces: InvalidSource.TestIntfMissingIntfA -- !:empty intf A!
-check interfaces: InvalidSource.TestIntfMissingIntfAOK -- !:empty intf A!, intf OK
-check interfaces: InvalidSource.TestIntfOKMissingIntfA -- intf OK, !:empty intf A!
-check interfaces: InvalidSource.TestIntfMissingIntfAB -- !:empty intf A!, !:empty intf B!
-check interfaces: InvalidSource.TestClassTMissingIntfAT -- !:empty intf A!<tvar T>
-check interfaces: InvalidSource.TestClassTMissingIntfAT_B -- !:empty intf A!<tvar T>, !:empty intf B!
-check interfaces: InvalidSource.TestIntfTMissingIntfAT -- !:empty intf A!<tvar T>
-check interfaces: InvalidSource.TestIntfTMissingIntfAT_B -- !:empty intf A!<tvar T>, !:empty intf B!
-check interfaces: InvalidSource.TestClassListMissingX -- intf (pkg java.util).List<!:empty clss X!>
\ No newline at end of file
+22 errors
\ No newline at end of file
--- a/langtools/test/tools/javac/warnings/6594914/T6594914a.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/warnings/6594914/T6594914a.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,7 +1,7 @@
T6594914a.java:11:5: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
T6594914a.java:16:16: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
-T6594914a.java:16:52: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
T6594914a.java:16:33: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
T6594914a.java:17:20: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6594914a.java:16:52: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
T6594914a.java:24:9: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
6 warnings
--- a/langtools/test/tools/javac/warnings/6594914/T6594914b.out Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javac/warnings/6594914/T6594914b.out Sat Sep 14 20:43:34 2013 +0100
@@ -1,7 +1,7 @@
T6594914b.java:11:13: compiler.warn.sun.proprietary: sun.misc.Lock
T6594914b.java:16:24: compiler.warn.sun.proprietary: sun.misc.Lock
-T6594914b.java:16:56: compiler.warn.sun.proprietary: sun.misc.Lock
T6594914b.java:16:39: compiler.warn.sun.proprietary: sun.misc.Lock
T6594914b.java:17:28: compiler.warn.sun.proprietary: sun.misc.CEFormatException
+T6594914b.java:16:56: compiler.warn.sun.proprietary: sun.misc.Lock
T6594914b.java:24:17: compiler.warn.sun.proprietary: sun.misc.Lock
6 warnings
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/suppress/ImplicitTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8021112
+ * @summary Verify that deprecated warning is printed correctly for import
+ * statement when processing a file on demand while attributing another file.
+ * @clean pack.ImplicitUse pack.ImplicitMain pack.Dep
+ * @compile/ref=ImplicitTest.out -XDrawDiagnostics -Xlint:deprecation pack/ImplicitMain.java
+ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/suppress/ImplicitTest.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,2 @@
+ImplicitUse.java:4:12: compiler.warn.has.been.deprecated: pack.Dep, pack
+1 warning
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/suppress/PackageInfo.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8021112
+ * @summary Verify that deprecated warnings are printed correctly for package-info.java
+ * @clean pack.package-info pack.DeprecatedClass
+ * @compile/ref=PackageInfo.out -XDrawDiagnostics -Xlint:deprecation pack/package-info.java pack/DeprecatedClass.java
+ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/suppress/PackageInfo.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,3 @@
+package-info.java:5:12: compiler.warn.has.been.deprecated: pack.DeprecatedClass, pack
+package-info.java:2:2: compiler.warn.has.been.deprecated: pack.DeprecatedClass, pack
+2 warnings
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/suppress/T6480588.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,36 @@
+/**
+ * @test /nodynamiccopyright/
+ * @bug 6470588
+ * @summary Verify that \\@SuppressWarnings("deprecation") works OK for all parts
+ * of class/method/field "header", including (declaration) annotations
+ * @build VerifySuppressWarnings
+ * @compile/ref=T6480588.out -XDrawDiagnostics -Xlint:unchecked,deprecation,cast T6480588.java
+ * @run main VerifySuppressWarnings T6480588.java
+ */
+
+@DeprecatedAnnotation
+class T6480588 extends DeprecatedClass implements DeprecatedInterface {
+ @DeprecatedAnnotation
+ public DeprecatedClass method(DeprecatedClass param) throws DeprecatedClass {
+ DeprecatedClass lv = new DeprecatedClass();
+ @Deprecated
+ DeprecatedClass lvd = new DeprecatedClass();
+ return null;
+ }
+
+ @Deprecated
+ public void methodD() {
+ }
+
+ @DeprecatedAnnotation
+ DeprecatedClass field = new DeprecatedClass();
+
+ @DeprecatedAnnotation
+ class Inner extends DeprecatedClass implements DeprecatedInterface {
+ }
+
+}
+
+@Deprecated class DeprecatedClass extends Throwable { }
+@Deprecated interface DeprecatedInterface { }
+@Deprecated @interface DeprecatedAnnotation { }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/suppress/T6480588.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,18 @@
+T6480588.java:12:24: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6480588.java:12:51: compiler.warn.has.been.deprecated: DeprecatedInterface, compiler.misc.unnamed.package
+T6480588.java:11:2: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package
+T6480588.java:14:12: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6480588.java:14:65: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6480588.java:13:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package
+T6480588.java:14:35: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6480588.java:15:9: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6480588.java:15:34: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6480588.java:17:9: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6480588.java:17:35: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6480588.java:26:5: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6480588.java:25:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package
+T6480588.java:26:33: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6480588.java:29:25: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package
+T6480588.java:29:52: compiler.warn.has.been.deprecated: DeprecatedInterface, compiler.misc.unnamed.package
+T6480588.java:28:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package
+17 warnings
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/suppress/T8021112a.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,45 @@
+/*
+ * 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 test;
+
+/**
+ * @test
+ * @bug 8021112
+ * @summary Verify that \\@SuppressWarnings work even if the value is defined
+ * inside the suppressed class itself, and verify that "unnecessary cast"
+ * lint can be properly suppressed.
+ * @compile -Xlint:cast -Werror T8021112a.java
+ */
+
+import static test.T8021112a.D;
+
+@SuppressWarnings(D)
+public class T8021112a {
+ public static final String D = (String) "cast";
+}
+
+class Other {
+ public static final String D = "cast";
+ @SuppressWarnings(D)
+ public static final String D2 = (String) "cast";
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/suppress/T8021112b.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,22 @@
+/**
+ * @test /nodynamiccopyright/
+ * @bug 8021112
+ * @summary Verify that \\@SuppressWarnings("unchecked") works correctly for lazy attrib values
+ * @build VerifySuppressWarnings
+ * @compile/ref=T8021112b.out -XDrawDiagnostics -Xlint:unchecked,deprecation,cast T8021112b.java
+ * @run main VerifySuppressWarnings T8021112b.java
+ */
+
+public class T8021112b {
+ public static final String D1 = Dep.D;
+ public static final String D2 = "";
+ public static final Object[] o = {
+ new Object() {
+ Dep d;
+ }
+ };
+}
+
+@Deprecated class Dep {
+ public static final String D = T8021112b.D2;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/suppress/T8021112b.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,3 @@
+T8021112b.java:11:37: compiler.warn.has.been.deprecated: Dep, compiler.misc.unnamed.package
+T8021112b.java:15:13: compiler.warn.has.been.deprecated: Dep, compiler.misc.unnamed.package
+2 warnings
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/suppress/TypeAnnotations.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,51 @@
+/**
+ * @test /nodynamiccopyright/
+ * @bug 8021112
+ * @summary Verify that \\@SuppressWarnings("unchecked") works for type annotations
+ * @build VerifySuppressWarnings
+ * @compile/ref=TypeAnnotations.out -XDrawDiagnostics -Xlint:unchecked,deprecation,cast TypeAnnotations.java
+ * @run main VerifySuppressWarnings TypeAnnotations.java
+ */
+
+import java.lang.annotation.*;
+
+public class TypeAnnotations extends @TA Object implements @TA Runnable {
+
+ public @TA String @TA [] m(@TA String @TA [] p) throws @TA Throwable {
+ Runnable r = () -> {
+ @TA Object tested = null;
+ @TA boolean isAnnotated = tested instanceof @TA String;
+ };
+
+ @TA Object tested = null;
+ @TA boolean isAnnotated = tested instanceof @TA String;
+
+ return (@TA String @TA []) null;
+ }
+
+ {
+ Runnable r = () -> {
+ @TA Object tested = null;
+ @TA boolean isAnnotated = tested instanceof @TA String;
+ };
+
+ @TA Object tested = null;
+ @TA boolean isAnnotated = tested instanceof @TA String;
+
+ @TA String @TA [] ret = (@TA String @TA []) null;
+ }
+
+ @TA String @TA [] f = new @TA String @TA[0];
+
+ @Override public void run() { }
+
+ public static class Inner extends @TA Object implements @TA Runnable {
+ @Override public void run() { }
+ }
+}
+
+@Target({ElementType.TYPE_USE, ElementType.TYPE})
+@Deprecated
+@interface TA {
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/suppress/TypeAnnotations.out Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,41 @@
+TypeAnnotations.java:12:39: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:12:61: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:14:24: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:14:61: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:14:13: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:14:44: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:14:33: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:23:29: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:23:18: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:16:14: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:17:58: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:17:14: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:17:58: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:20:10: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:21:54: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:21:10: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:21:54: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:23:18: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:23:29: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:28:14: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:29:58: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:29:14: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:29:58: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:32:10: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:33:54: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:33:10: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:33:54: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:35:46: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:35:35: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:35:21: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:35:10: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:35:35: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:35:46: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:38:17: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:38:6: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:38:43: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:38:32: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:38:32: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:42:40: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+TypeAnnotations.java:42:62: compiler.warn.has.been.deprecated: TA, compiler.misc.unnamed.package
+40 warnings
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/suppress/VerifySuppressWarnings.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ */
+
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.NewClassTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TreeScanner;
+import com.sun.source.util.Trees;
+import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.FileObject;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+
+/**Takes a source file, parses it once to get the warnings inside the file and
+ * then for each and every declaration in the file, it tries to place
+ * the @SuppressWarnings annotation on the declaration and verifies than no
+ * warnings are produced inside the declaration, but all are produced outside it.
+ *
+ * Currently only works with <code>unchecked,deprecation,cast</code> warnings.
+ */
+public class VerifySuppressWarnings {
+
+ private static final List<String> STANDARD_PARAMS = Arrays.asList("-Xlint:unchecked,deprecation,cast", "-Xjcov");
+
+ public static void main(String... args) throws IOException, URISyntaxException {
+ if (args.length != 1) throw new IllegalStateException("Must provide class name!");
+ String testContent = null;
+ List<File> sourcePath = new ArrayList<>();
+ for (String sourcePaths : System.getProperty("test.src.path").split(":")) {
+ sourcePath.add(new File(sourcePaths));
+ }
+ JavacFileManager fm = JavacTool.create().getStandardFileManager(null, null, null);
+ for (File sp : sourcePath) {
+ File inp = new File(sp, args[0]);
+
+ if (inp.canRead()) {
+ testContent = fm.getRegularFile(inp).getCharContent(true).toString();
+ }
+ }
+ if (testContent == null) throw new IllegalStateException();
+ final List<Diagnostic<?>> diagnostics = new ArrayList<>();
+ DiagnosticListener<JavaFileObject> collectDiagnostics = new DiagnosticListener<JavaFileObject>() {
+ @Override public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ diagnostics.add(diagnostic);
+ }
+ };
+ JavaFileObject testFile = new TestFO(new URI("mem://" + args[0]), testContent);
+ JavacTask task = JavacTool.create().getTask(null,
+ new TestFM(fm),
+ collectDiagnostics,
+ STANDARD_PARAMS,
+ null,
+ Arrays.asList(testFile));
+ final Trees trees = Trees.instance(task);
+ final CompilationUnitTree cut = task.parse().iterator().next();
+ task.analyze();
+
+ final List<int[]> declarationSpans = new ArrayList<>();
+
+ new TreeScanner<Void, Void>() {
+ @Override public Void visitClass(ClassTree node, Void p) {
+ handleDeclaration(node);
+ return super.visitClass(node, p);
+ }
+ @Override public Void visitMethod(MethodTree node, Void p) {
+ handleDeclaration(node);
+ return super.visitMethod(node, p);
+ }
+ @Override public Void visitVariable(VariableTree node, Void p) {
+ handleDeclaration(node);
+ return super.visitVariable(node, p);
+ }
+
+ @Override
+ public Void visitNewClass(NewClassTree node, Void p) {
+ if (node.getClassBody() != null) {
+ scan(node.getClassBody().getMembers(), null);
+ }
+ return null;
+ }
+
+ private void handleDeclaration(Tree node) {
+ int endPos = (int) trees.getSourcePositions().getEndPosition(cut, node);
+
+ if (endPos == (-1)) {
+ if (node.getKind() == Tree.Kind.METHOD && (((JCMethodDecl) node).getModifiers().flags & Flags.GENERATEDCONSTR) != 0) {
+ return ;
+ }
+ throw new IllegalStateException();
+ }
+
+ declarationSpans.add(new int[] {(int) trees.getSourcePositions().getStartPosition(cut, node), endPos});
+ }
+ }.scan(cut, null);
+
+ for (final int[] declarationSpan : declarationSpans) {
+ final String suppressWarnings = "@SuppressWarnings({\"deprecation\", \"unchecked\", \"serial\"})";
+ final String updatedContent = testContent.substring(0, declarationSpan[0]) + suppressWarnings + testContent.substring(declarationSpan[0]);
+ final List<Diagnostic<?>> foundErrors = new ArrayList<>(diagnostics);
+ DiagnosticListener<JavaFileObject> verifyDiagnostics = new DiagnosticListener<JavaFileObject>() {
+ @Override public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ long adjustedPos = diagnostic.getPosition();
+
+ if (adjustedPos >= declarationSpan[0]) adjustedPos -= suppressWarnings.length();
+
+ if (declarationSpan[0] <= adjustedPos && adjustedPos <= declarationSpan[1]) {
+ throw new IllegalStateException("unsuppressed: " + diagnostic.getMessage(null));
+ }
+
+ boolean found = false;
+
+ for (Iterator<Diagnostic<?>> it = foundErrors.iterator(); it.hasNext();) {
+ Diagnostic<?> d = it.next();
+ if (d.getPosition() == adjustedPos && d.getCode().equals(diagnostic.getCode())) {
+ it.remove();
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ throw new IllegalStateException("diagnostic not originally reported: " + diagnostic.getMessage(null));
+ }
+ }
+ };
+
+ JavaFileObject updatedFile = new TestFO(new URI("mem://" + args[0]), updatedContent);
+ JavacTask testTask = JavacTool.create().getTask(null,
+ new TestFM(fm),
+ verifyDiagnostics,
+ STANDARD_PARAMS,
+ null,
+ Arrays.asList(updatedFile));
+
+ testTask.analyze();
+
+ for (Diagnostic<?> d : foundErrors) {
+ if (d.getPosition() < declarationSpan[0] || declarationSpan[1] < d.getPosition()) {
+ throw new IllegalStateException("missing: " + d.getMessage(null));
+ }
+ }
+ }
+ }
+
+ private static final class TestFO extends SimpleJavaFileObject {
+ private final String content;
+ public TestFO(URI uri, String content) {
+ super(uri, Kind.SOURCE);
+ this.content = content;
+ }
+
+ @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return content;
+ }
+
+ @Override public boolean isNameCompatible(String simpleName, Kind kind) {
+ return true;
+ }
+ }
+
+ private static final class TestFM extends ForwardingJavaFileManager<JavaFileManager> {
+
+ public TestFM(JavaFileManager fileManager) {
+ super(fileManager);
+ }
+
+ @Override
+ public boolean isSameFile(FileObject a, FileObject b) {
+ return a.equals(b);
+ }
+
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/suppress/pack/DeprecatedClass.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,5 @@
+/* /nodynamiccopyright/ */
+package pack;
+@Deprecated
+@interface DeprecatedClass {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/suppress/pack/ImplicitMain.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,14 @@
+/* /nodynamiccopyright/ */
+package pack;
+
+@SuppressWarnings("deprecation")
+public class ImplicitMain {
+ private Object test() {
+ return new ImplicitUse();
+ }
+}
+
+@Deprecated
+class Dep {
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/suppress/pack/ImplicitUse.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,7 @@
+/* /nodynamiccopyright/ */
+package pack;
+
+import pack.Dep;
+
+public class ImplicitUse {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/suppress/pack/package-info.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,5 @@
+/* /nodynamiccopyright/ */
+@DeprecatedClass
+package pack;
+
+import pack.DeprecatedClass;
--- a/langtools/test/tools/javadoc/api/basic/APITest.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javadoc/api/basic/APITest.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -29,6 +29,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
+import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
@@ -164,11 +165,13 @@
}
private void listFiles(Path dir, Set<Path> files) throws IOException {
- for (Path f: Files.newDirectoryStream(dir)) {
- if (Files.isDirectory(f))
- listFiles(f, files);
- else if (Files.isRegularFile(f))
- files.add(f);
+ try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir)) {
+ for (Path f: ds) {
+ if (Files.isDirectory(f))
+ listFiles(f, files);
+ else if (Files.isRegularFile(f))
+ files.add(f);
+ }
}
}
--- a/langtools/test/tools/javadoc/api/basic/GetTask_FileManagerTest.java Fri Sep 06 09:55:59 2013 +0100
+++ b/langtools/test/tools/javadoc/api/basic/GetTask_FileManagerTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6493690
+ * @bug 6493690 8024434
* @summary javadoc should have a javax.tools.Tool service provider
* @build APITest
* @run main GetTask_FileManagerTest
--- a/make/scripts/webrev.ksh Fri Sep 06 09:55:59 2013 +0100
+++ b/make/scripts/webrev.ksh Sat Sep 14 20:43:34 2013 +0100
@@ -27,7 +27,7 @@
# Documentation is available via 'webrev -h'.
#
-WEBREV_UPDATED=24.0-hg+jbs
+WEBREV_UPDATED=24.1-hg+openjdk.java.net
HTML='<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
@@ -230,7 +230,7 @@
# $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
# new/usr/src/tools/scripts/webrev.sh \
# webrev.sh usr/src/tools/scripts \
-# '<a href="https://jbs.oracle.com/bugs/browse/JDK-1234567">
+# '<a href="https://bugs.openjdk.java.net/browse/JDK-1234567">
# JDK-1234567</a> my bugid' > <file>.html
#
# framed_sdiff() is then called which creates $2.frames.html
@@ -1476,7 +1476,7 @@
# The first and last are simple addition while the middle one
# is a move/rename or a copy. We can't distinguish from a rename vs a copy
# without also getting the status of removed files. The middle case above
- # is a rename if File4 is also shown a being removed. If File4 is not a
+ # is a rename if File4 is also shown a being removed. If File4 is not a
# removed file, then the middle case is a copy from File4 to subdir/File4
# FIXME - we're not distinguishing copy from rename
$HGCMD -aC | $FILTER | while read LINE; do
@@ -1644,7 +1644,7 @@
# The first and last are simple addition while the middle one
# is a move/rename or a copy. We can't distinguish from a rename vs a copy
# without also getting the status of removed files. The middle case above
- # is a rename if File4 is also shown a being removed. If File4 is not a
+ # is a rename if File4 is also shown a being removed. If File4 is not a
# removed file, then the middle case is a copy from File4 to subdir/File4
# FIXME - we're not distinguishing copy from rename
@@ -2529,7 +2529,7 @@
# Bug IDs will be replaced by a URL. Order of precedence
# is: default location, $WEBREV_BUGURL, the -O flag.
#
-BUGURL='https://jbs.oracle.com/bugs/browse/'
+BUGURL='https://bugs.openjdk.java.net/browse/'
[[ -n $WEBREV_BUGURL ]] && BUGURL="$WEBREV_BUGURL"
if [[ -n "$Oflag" ]]; then
CRID=`echo $CRID | sed -e 's/JDK-//'`
@@ -3056,7 +3056,7 @@
for id in $CRID
do
if [[ -z "$Oflag" ]]; then
- #add "JDK-" to raw bug id for jbs links.
+ #add "JDK-" to raw bug id for openjdk.java.net links.
id=`echo ${id} | sed 's/^\([0-9]\{5,\}\)$/JDK-\1/'`
fi
print "<tr><th>Bug id:</th><td>"
--- a/nashorn/.hgtags Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/.hgtags Sat Sep 14 20:43:34 2013 +0100
@@ -216,3 +216,4 @@
afc100513451d22f0b8135999d6eb52f36df3d36 jdk8-b104
f484bfb624dd06683cb33b524700a5dd4927a82b jdk8-b105
bf70cbd2c8369fd97ffdfcbe1a80dbc2797408ee jdk8-b106
+f35e1255024b66f7cf82517798f45f6e194e5567 jdk8-b107
--- a/nashorn/make/build.xml Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/make/build.xml Sat Sep 14 20:43:34 2013 +0100
@@ -230,6 +230,10 @@
<compilerarg value="-Xlint:deprecation"/>
</javac>
+ <copy todir="${build.test.classes.dir}/META-INF/services">
+ <fileset dir="${test.src.dir}/META-INF/services/"/>
+ </copy>
+
<!-- tests that check nashorn internals and internal API -->
<jar jarfile="${nashorn.internal.tests.jar}">
<fileset dir="${build.test.classes.dir}" excludes="**/api/**"/>
@@ -238,6 +242,7 @@
<!-- tests that check nashorn script engine (jsr-223) API -->
<jar jarfile="${nashorn.api.tests.jar}">
<fileset dir="${build.test.classes.dir}" includes="**/api/**"/>
+ <fileset dir="${build.test.classes.dir}" includes="**/META-INF/**"/>
</jar>
</target>
@@ -264,6 +269,13 @@
permission java.util.PropertyPermission "nashorn.test.*", "read";
};
+grant codeBase "file:/${basedir}/test/script/basic/parser/*" {
+ permission java.io.FilePermission "${basedir}/test/script/-", "read";
+ permission java.io.FilePermission "$${user.dir}", "read";
+ permission java.util.PropertyPermission "user.dir", "read";
+ permission java.util.PropertyPermission "nashorn.test.*", "read";
+};
+
grant codeBase "file:/${basedir}/test/script/basic/JDK-8010946-privileged.js" {
permission java.util.PropertyPermission "java.security.policy", "read";
};
--- a/nashorn/src/jdk/nashorn/api/scripting/JSObject.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/api/scripting/JSObject.java Sat Sep 14 20:43:34 2013 +0100
@@ -25,73 +25,210 @@
package jdk.nashorn.api.scripting;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
/**
- * netscape.javascript.JSObject-like interface for nashorn script objects.
+ * This is the base class for nashorn ScriptObjectMirror class.
+ *
+ * This class can also be subclassed by an arbitrary Java class. Nashorn will
+ * treat objects of such classes just like nashorn script objects. Usual nashorn
+ * operations like obj[i], obj.foo, obj.func(), delete obj.foo will be glued
+ * to appropriate method call of this class.
*/
public abstract class JSObject {
/**
- * Call a JavaScript function
+ * Call this object as a JavaScript function. This is equivalent to
+ * 'func.apply(thiz, args)' in JavaScript.
*
- * @param functionName name of function
+ * @param thiz 'this' object to be passed to the function
* @param args arguments to method
* @return result of call
*/
- public abstract Object call(String functionName, Object... args);
+ public Object call(Object thiz, Object... args) {
+ throw new UnsupportedOperationException("call");
+ }
/**
- * Call a JavaScript method as a constructor. This is equivalent to
- * calling new obj.Method(arg1, arg2...) in JavaScript.
+ * Call this 'constructor' JavaScript function to create a new object.
+ * This is equivalent to 'new func(arg1, arg2...)' in JavaScript.
*
- * @param functionName name of function
* @param args arguments to method
* @return result of constructor call
*/
- public abstract Object newObject(String functionName, Object... args);
+ public Object newObject(Object... args) {
+ throw new UnsupportedOperationException("newObject");
+ }
/**
- * Evaluate a JavaScript expression
+ * Evaluate a JavaScript expression.
*
* @param s JavaScript expression to evaluate
* @return evaluation result
*/
- public abstract Object eval(String s);
+ public Object eval(String s) {
+ throw new UnsupportedOperationException("eval");
+ }
/**
- * Retrieves a named member of a JavaScript object.
+ * Call a JavaScript function member of this object.
+ *
+ * @param name name of the member function to call
+ * @param args arguments to be passed to the member function
+ * @return result of call
+ */
+ public Object callMember(String name, Object... args) {
+ throw new UnsupportedOperationException("call");
+ }
+
+ /**
+ * Retrieves a named member of this JavaScript object.
*
* @param name of member
* @return member
*/
- public abstract Object getMember(String name);
+ public Object getMember(String name) {
+ return null;
+ }
/**
- * Retrieves an indexed member of a JavaScript object.
+ * Retrieves an indexed member of this JavaScript object.
*
- * @param index index of member slot
+ * @param index index slot to retrieve
* @return member
*/
- public abstract Object getSlot(int index);
+ public Object getSlot(int index) {
+ return null;
+ }
/**
- * Remove a named member from a JavaScript object
+ * Does this object have a named member?
*
* @param name name of member
+ * @return true if this object has a member of the given name
*/
- public abstract void removeMember(String name);
+ public boolean hasMember(String name) {
+ return false;
+ }
+
+ /**
+ * Does this object have a indexed property?
+ *
+ * @param slot index to check
+ * @return true if this object has a slot
+ */
+ public boolean hasSlot(int slot) {
+ return false;
+ }
+
+ /**
+ * Remove a named member from this JavaScript object
+ *
+ * @param name name of the member
+ */
+ public void removeMember(String name) {
+ }
+
+ /**
+ * Set a named member in this JavaScript object
+ *
+ * @param name name of the member
+ * @param value value of the member
+ */
+ public void setMember(String name, Object value) {
+ }
+
+ /**
+ * Set an indexed member in this JavaScript object
+ *
+ * @param index index of the member slot
+ * @param value value of the member
+ */
+ public void setSlot(int index, Object value) {
+ }
+
+ // property and value iteration
+
+ /**
+ * Returns the set of all property names of this object.
+ *
+ * @return set of property names
+ */
+ @SuppressWarnings("unchecked")
+ public Set<String> keySet() {
+ return Collections.EMPTY_SET;
+ }
/**
- * Set a named member in a JavaScript object
+ * Returns the set of all property values of this object.
+ *
+ * @return set of property values.
+ */
+ @SuppressWarnings("unchecked")
+ public Collection<Object> values() {
+ return Collections.EMPTY_SET;
+ }
+
+ // JavaScript instanceof check
+
+ /**
+ * Checking whether the given object is an instance of 'this' object.
*
- * @param name name of member
- * @param value value of member
+ * @param instance instace to check
+ * @return true if the given 'instance' is an instance of this 'function' object
*/
- public abstract void setMember(String name, Object value);
+ public boolean isInstance(final Object instance) {
+ return false;
+ }
+
+ /**
+ * Checking whether this object is an instance of the given 'clazz' object.
+ *
+ * @param clazz clazz to check
+ * @return true if this object is an instance of the given 'clazz'
+ */
+ public boolean isInstanceOf(final Object clazz) {
+ if (clazz instanceof JSObject) {
+ return ((JSObject)clazz).isInstance(this);
+ }
+
+ return false;
+ }
/**
- * Set an indexed member in a JavaScript object
+ * ECMA [[Class]] property
+ *
+ * @return ECMA [[Class]] property value of this object
+ */
+ public String getClassName() {
+ return getClass().getName();
+ }
+
+ /**
+ * Is this a function object?
*
- * @param index index of member slot
- * @param value value of member
+ * @return if this mirror wraps a ECMAScript function instance
+ */
+ public boolean isFunction() {
+ return false;
+ }
+
+ /**
+ * Is this a 'use strict' function object?
+ *
+ * @return true if this mirror represents a ECMAScript 'use strict' function
*/
- public abstract void setSlot(int index, Object value);
+ public boolean isStrictFunction() {
+ return false;
+ }
+
+ /**
+ * Is this an array object?
+ *
+ * @return if this mirror wraps a ECMAScript array object
+ */
+ public boolean isArray() {
+ return false;
+ }
}
--- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Sat Sep 14 20:43:34 2013 +0100
@@ -315,7 +315,7 @@
final ScriptObjectMirror mirror = (ScriptObjectMirror)thiz;
realSelf = mirror.getScriptObject();
realGlobal = mirror.getHomeGlobal();
- if (! realGlobal.isOfContext(nashornContext)) {
+ if (! isOfContext(realGlobal, nashornContext)) {
throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
}
} else if (thiz instanceof ScriptObject) {
@@ -326,7 +326,7 @@
throw new IllegalArgumentException(getMessage("no.current.nashorn.global"));
}
- if (! realGlobal.isOfContext(nashornContext)) {
+ if (! isOfContext(realGlobal, nashornContext)) {
throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
}
}
@@ -394,7 +394,7 @@
// Retrieve nashorn Global object from a given ScriptObjectMirror
private ScriptObject globalFromMirror(final ScriptObjectMirror mirror) {
ScriptObject sobj = mirror.getScriptObject();
- if (sobj instanceof GlobalObject && sobj.isOfContext(nashornContext)) {
+ if (sobj instanceof GlobalObject && isOfContext(sobj, nashornContext)) {
return sobj;
}
@@ -470,7 +470,7 @@
ScriptObjectMirror selfMirror = null;
if (selfObject instanceof ScriptObjectMirror) {
selfMirror = (ScriptObjectMirror)selfObject;
- if (! selfMirror.getHomeGlobal().isOfContext(nashornContext)) {
+ if (! isOfContext(selfMirror.getHomeGlobal(), nashornContext)) {
throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
}
} else if (selfObject instanceof ScriptObject) {
@@ -481,7 +481,7 @@
throw new IllegalArgumentException(getMessage("no.current.nashorn.global"));
}
- if (! oldGlobal.isOfContext(nashornContext)) {
+ if (! isOfContext(oldGlobal, nashornContext)) {
throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
}
@@ -494,7 +494,7 @@
if (selfMirror != null) {
try {
- return ScriptObjectMirror.translateUndefined(selfMirror.call(name, args));
+ return ScriptObjectMirror.translateUndefined(selfMirror.callMember(name, args));
} catch (final Exception e) {
final Throwable cause = e.getCause();
if (cause instanceof NoSuchMethodException) {
@@ -617,4 +617,9 @@
}
return true;
}
+
+ private static boolean isOfContext(final ScriptObject global, final Context context) {
+ assert global instanceof GlobalObject: "Not a Global object";
+ return ((GlobalObject)global).isOfContext(context);
+ }
}
--- a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Sat Sep 14 20:43:34 2013 +0100
@@ -42,14 +42,13 @@
import java.util.concurrent.Callable;
import javax.script.Bindings;
import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.GlobalObject;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
/**
- * Mirror object that wraps a given ScriptObject instance. User can
- * access ScriptObject via the javax.script.Bindings interface or
- * netscape.javascript.JSObject interface.
+ * Mirror object that wraps a given Nashorn Script object.
*/
public final class ScriptObjectMirror extends JSObject implements Bindings {
private static AccessControlContext getContextAccCtxt() {
@@ -62,6 +61,7 @@
private final ScriptObject sobj;
private final ScriptObject global;
+ private final boolean strict;
@Override
public boolean equals(final Object other) {
@@ -88,8 +88,9 @@
}
// JSObject methods
+
@Override
- public Object call(final String functionName, final Object... args) {
+ public Object call(final Object thiz, final Object... args) {
final ScriptObject oldGlobal = Context.getGlobal();
final boolean globalChanged = (oldGlobal != global);
@@ -98,15 +99,13 @@
Context.setGlobal(global);
}
- final Object val = functionName == null? sobj : sobj.get(functionName);
- if (val instanceof ScriptFunction) {
+ if (sobj instanceof ScriptFunction) {
final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
- return wrap(ScriptRuntime.checkAndApply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
- } else if (val instanceof ScriptObjectMirror && ((ScriptObjectMirror)val).isFunction()) {
- return ((ScriptObjectMirror)val).call(null, args);
+ final Object self = globalChanged? wrap(thiz, oldGlobal) : thiz;
+ return wrap(ScriptRuntime.apply((ScriptFunction)sobj, unwrap(self, global), unwrapArray(modArgs, global)), global);
}
- throw new NoSuchMethodException("No such function " + ((functionName != null)? functionName : ""));
+ throw new RuntimeException("not a function: " + toString());
} catch (final RuntimeException | Error e) {
throw e;
} catch (final Throwable t) {
@@ -119,7 +118,7 @@
}
@Override
- public Object newObject(final String functionName, final Object... args) {
+ public Object newObject(final Object... args) {
final ScriptObject oldGlobal = Context.getGlobal();
final boolean globalChanged = (oldGlobal != global);
@@ -128,15 +127,12 @@
Context.setGlobal(global);
}
- final Object val = functionName == null? sobj : sobj.get(functionName);
- if (val instanceof ScriptFunction) {
+ if (sobj instanceof ScriptFunction) {
final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
- return wrap(ScriptRuntime.checkAndConstruct((ScriptFunction)val, unwrapArray(modArgs, global)), global);
- } else if (val instanceof ScriptObjectMirror && ((ScriptObjectMirror)val).isFunction()) {
- return ((ScriptObjectMirror)val).newObject(null, args);
+ return wrap(ScriptRuntime.construct((ScriptFunction)sobj, unwrapArray(modArgs, global)), global);
}
- throw new RuntimeException("not a constructor " + ((functionName != null)? functionName : ""));
+ throw new RuntimeException("not a constructor: " + toString());
} catch (final RuntimeException | Error e) {
throw e;
} catch (final Throwable t) {
@@ -166,7 +162,39 @@
}
@Override
+ public Object callMember(final String functionName, final Object... args) {
+ functionName.getClass(); // null check
+ final ScriptObject oldGlobal = Context.getGlobal();
+ final boolean globalChanged = (oldGlobal != global);
+
+ try {
+ if (globalChanged) {
+ Context.setGlobal(global);
+ }
+
+ final Object val = sobj.get(functionName);
+ if (val instanceof ScriptFunction) {
+ final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
+ return wrap(ScriptRuntime.apply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
+ } else if (val instanceof JSObject && ((JSObject)val).isFunction()) {
+ return ((JSObject)val).call(sobj, args);
+ }
+
+ throw new NoSuchMethodException("No such function " + functionName);
+ } catch (final RuntimeException | Error e) {
+ throw e;
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ } finally {
+ if (globalChanged) {
+ Context.setGlobal(oldGlobal);
+ }
+ }
+ }
+
+ @Override
public Object getMember(final String name) {
+ name.getClass();
return inGlobal(new Callable<Object>() {
@Override public Object call() {
return wrap(sobj.get(name), global);
@@ -184,12 +212,33 @@
}
@Override
+ public boolean hasMember(final String name) {
+ name.getClass();
+ return inGlobal(new Callable<Boolean>() {
+ @Override public Boolean call() {
+ return sobj.has(name);
+ }
+ });
+ }
+
+ @Override
+ public boolean hasSlot(final int slot) {
+ return inGlobal(new Callable<Boolean>() {
+ @Override public Boolean call() {
+ return sobj.has(slot);
+ }
+ });
+ }
+
+ @Override
public void removeMember(final String name) {
+ name.getClass();
remove(name);
}
@Override
public void setMember(final String name, final Object value) {
+ name.getClass();
put(name, value);
}
@@ -197,19 +246,58 @@
public void setSlot(final int index, final Object value) {
inGlobal(new Callable<Void>() {
@Override public Void call() {
- sobj.set(index, unwrap(value, global), global.isStrictContext());
+ sobj.set(index, unwrap(value, global), strict);
return null;
}
});
}
+ @Override
+ public boolean isInstance(final Object obj) {
+ if (! (obj instanceof ScriptObjectMirror)) {
+ return false;
+ }
+
+ final ScriptObjectMirror instance = (ScriptObjectMirror)obj;
+ // if not belongs to my global scope, return false
+ if (global != instance.global) {
+ return false;
+ }
+
+ return inGlobal(new Callable<Boolean>() {
+ @Override public Boolean call() {
+ return sobj.isInstance(instance.sobj);
+ }
+ });
+ }
+
+ @Override
+ public String getClassName() {
+ return sobj.getClassName();
+ }
+
+ @Override
+ public boolean isFunction() {
+ return sobj instanceof ScriptFunction;
+ }
+
+ @Override
+ public boolean isStrictFunction() {
+ return isFunction() && ((ScriptFunction)sobj).isStrict();
+ }
+
+ @Override
+ public boolean isArray() {
+ return sobj.isArray();
+ }
+
// javax.script.Bindings methods
@Override
public void clear() {
inGlobal(new Callable<Object>() {
@Override public Object call() {
- sobj.clear();
+ sobj.clear(strict);
return null;
}
});
@@ -292,7 +380,7 @@
return inGlobal(new Callable<Object>() {
@Override public Object call() {
final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
- return translateUndefined(wrap(sobj.put(key, unwrap(modValue, global)), global));
+ return translateUndefined(wrap(sobj.put(key, unwrap(modValue, global), strict), global));
}
});
}
@@ -303,7 +391,6 @@
final boolean globalChanged = (oldGlobal != global);
inGlobal(new Callable<Object>() {
@Override public Object call() {
- final boolean strict = global.isStrictContext();
for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) {
final Object value = entry.getValue();
final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
@@ -318,7 +405,7 @@
public Object remove(final Object key) {
return inGlobal(new Callable<Object>() {
@Override public Object call() {
- return wrap(sobj.remove(unwrap(key, global)), global);
+ return wrap(sobj.remove(unwrap(key, global), strict), global);
}
});
}
@@ -333,7 +420,7 @@
public boolean delete(final Object key) {
return inGlobal(new Callable<Boolean>() {
@Override public Boolean call() {
- return sobj.delete(unwrap(key, global));
+ return sobj.delete(unwrap(key, global), strict);
}
});
}
@@ -391,15 +478,6 @@
}
/**
- * ECMA [[Class]] property
- *
- * @return ECMA [[Class]] property value of this object
- */
- public String getClassName() {
- return sobj.getClassName();
- }
-
- /**
* ECMA 8.12.1 [[GetOwnProperty]] (P)
*
* @param key property key
@@ -505,55 +583,6 @@
});
}
- // ECMAScript instanceof check
-
- /**
- * Checking whether a script object is an instance of another by
- * walking the proto chain
- *
- * @param instance instace to check
- * @return true if 'instance' is an instance of this object
- */
- public boolean isInstance(final ScriptObjectMirror instance) {
- // if not belongs to my global scope, return false
- if (instance == null || global != instance.global) {
- return false;
- }
-
- return inGlobal(new Callable<Boolean>() {
- @Override public Boolean call() {
- return sobj.isInstance(instance.sobj);
- }
- });
- }
-
- /**
- * is this a function object?
- *
- * @return if this mirror wraps a ECMAScript function instance
- */
- public boolean isFunction() {
- return sobj instanceof ScriptFunction;
- }
-
- /**
- * is this a 'use strict' function object?
- *
- * @return true if this mirror represents a ECMAScript 'use strict' function
- */
- public boolean isStrictFunction() {
- return isFunction() && ((ScriptFunction)sobj).isStrict();
- }
-
- /**
- * is this an array object?
- *
- * @return if this mirror wraps a ECMAScript array object
- */
- public boolean isArray() {
- return sobj.isArray();
- }
-
/**
* Utility to check if given object is ECMAScript undefined value
*
@@ -637,10 +666,11 @@
ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) {
assert sobj != null : "ScriptObjectMirror on null!";
- assert global != null : "null global for ScriptObjectMirror!";
+ assert global instanceof GlobalObject : "global is not a GlobalObject";
this.sobj = sobj;
this.global = global;
+ this.strict = ((GlobalObject)global).isStrictContext();
}
// accessors for script engine
--- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Sat Sep 14 20:43:34 2013 +0100
@@ -26,6 +26,7 @@
package jdk.nashorn.internal.codegen;
import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
+import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS_VAR;
import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE;
import static jdk.nashorn.internal.codegen.CompilerConstants.EXCEPTION_PREFIX;
import static jdk.nashorn.internal.codegen.CompilerConstants.ITERATOR_PREFIX;
@@ -172,7 +173,9 @@
initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL);
if (functionNode.needsArguments()) {
initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED);
- addLocalDef(ARGUMENTS.symbolName());
+ final String argumentsName = ARGUMENTS_VAR.symbolName();
+ newType(defineSymbol(body, argumentsName, IS_VAR | IS_ALWAYS_DEFINED), Type.typeFor(ARGUMENTS_VAR.type()));
+ addLocalDef(argumentsName);
}
}
@@ -491,30 +494,29 @@
objectifySymbols(body);
}
+ List<VarNode> syntheticInitializers = null;
+
if (body.getFlag(Block.NEEDS_SELF_SYMBOL)) {
- final IdentNode callee = compilerConstant(CALLEE);
- VarNode selfInit =
- new VarNode(
- newFunctionNode.getLineNumber(),
- newFunctionNode.getToken(),
- newFunctionNode.getFinish(),
- newFunctionNode.getIdent(),
- callee);
-
- LOG.info("Accepting self symbol init ", selfInit, " for ", newFunctionNode.getName());
+ syntheticInitializers = new ArrayList<>(2);
+ LOG.info("Accepting self symbol init for ", newFunctionNode.getName());
+ // "var fn = :callee"
+ syntheticInitializers.add(createSyntheticInitializer(newFunctionNode.getIdent(), CALLEE, newFunctionNode));
+ }
- final List<Statement> newStatements = new ArrayList<>();
- assert callee.getSymbol() != null && callee.getSymbol().hasSlot();
-
- final IdentNode name = selfInit.getName();
- final Symbol nameSymbol = body.getExistingSymbol(name.getName());
+ if(newFunctionNode.needsArguments()) {
+ if(syntheticInitializers == null) {
+ syntheticInitializers = new ArrayList<>(1);
+ }
+ // "var arguments = :arguments"
+ syntheticInitializers.add(createSyntheticInitializer(createImplicitIdentifier(ARGUMENTS_VAR.symbolName()),
+ ARGUMENTS, newFunctionNode));
+ }
- assert nameSymbol != null;
-
- selfInit = selfInit.setName((IdentNode)name.setSymbol(lc, nameSymbol));
-
- newStatements.add(selfInit);
- newStatements.addAll(body.getStatements());
+ if(syntheticInitializers != null) {
+ final List<Statement> stmts = body.getStatements();
+ final List<Statement> newStatements = new ArrayList<>(stmts.size() + syntheticInitializers.size());
+ newStatements.addAll(syntheticInitializers);
+ newStatements.addAll(stmts);
newFunctionNode = newFunctionNode.setBody(lc, body.setStatements(lc, newStatements));
}
@@ -533,6 +535,28 @@
return newFunctionNode;
}
+ /**
+ * Creates a synthetic initializer for a variable (a var statement that doesn't occur in the source code). Typically
+ * used to create assignmnent of {@code :callee} to the function name symbol in self-referential function
+ * expressions as well as for assignment of {@code :arguments} to {@code arguments}.
+ *
+ * @param name the ident node identifying the variable to initialize
+ * @param initConstant the compiler constant it is initialized to
+ * @param fn the function node the assignment is for
+ * @return a var node with the appropriate assignment
+ */
+ private VarNode createSyntheticInitializer(final IdentNode name, final CompilerConstants initConstant, final FunctionNode fn) {
+ final IdentNode init = compilerConstant(initConstant);
+ assert init.getSymbol() != null && init.getSymbol().hasSlot();
+
+ VarNode synthVar = new VarNode(fn.getLineNumber(), fn.getToken(), fn.getFinish(), name, init);
+
+ final Symbol nameSymbol = fn.getBody().getExistingSymbol(name.getName());
+ assert nameSymbol != null;
+
+ return synthVar.setName((IdentNode)name.setSymbol(lc, nameSymbol));
+ }
+
@Override
public Node leaveCONVERT(final UnaryNode unaryNode) {
assert false : "There should be no convert operators in IR during Attribution";
@@ -886,10 +910,9 @@
@Override
public Node leaveDECINC(final UnaryNode unaryNode) {
// @see assignOffset
- final UnaryNode newUnaryNode = unaryNode.setRHS(ensureAssignmentSlots(unaryNode.rhs()));
final Type type = arithType();
- newType(newUnaryNode.rhs().getSymbol(), type);
- return end(ensureSymbol(type, newUnaryNode));
+ newType(unaryNode.rhs().getSymbol(), type);
+ return end(ensureSymbol(type, unaryNode));
}
@Override
@@ -975,15 +998,18 @@
}
private IdentNode compilerConstant(CompilerConstants cc) {
- final FunctionNode functionNode = lc.getCurrentFunction();
- return (IdentNode)
- new IdentNode(
- functionNode.getToken(),
- functionNode.getFinish(),
- cc.symbolName()).
- setSymbol(
- lc,
- functionNode.compilerConstant(cc));
+ return (IdentNode)createImplicitIdentifier(cc.symbolName()).setSymbol(lc, lc.getCurrentFunction().compilerConstant(cc));
+ }
+
+ /**
+ * Creates an ident node for an implicit identifier within the function (one not declared in the script source
+ * code). These identifiers are defined with function's token and finish.
+ * @param name the name of the identifier
+ * @return an ident node representing the implicit identifier.
+ */
+ private IdentNode createImplicitIdentifier(final String name) {
+ final FunctionNode fn = lc.getCurrentFunction();
+ return new IdentNode(fn.getToken(), fn.getFinish(), name);
}
@Override
@@ -1575,39 +1601,6 @@
}
/**
- * In an assignment, recursively make sure that there are slots for
- * everything that has to be laid out as temporary storage, which is the
- * case if we are assign-op:ing a BaseNode subclass. This has to be
- * recursive to handle things like multi dimensional arrays as lhs
- *
- * see NASHORN-258
- *
- * @param assignmentDest the destination node of the assignment, e.g. lhs for binary nodes
- */
- private Expression ensureAssignmentSlots(final Expression assignmentDest) {
- final LexicalContext attrLexicalContext = lc;
- return (Expression)assignmentDest.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
- @Override
- public Node leaveIndexNode(final IndexNode indexNode) {
- assert indexNode.getSymbol().isTemp();
- final Expression index = indexNode.getIndex();
- //only temps can be set as needing slots. the others will self resolve
- //it is illegal to take a scope var and force it to be a slot, that breaks
- Symbol indexSymbol = index.getSymbol();
- if (indexSymbol.isTemp() && !indexSymbol.isConstant() && !indexSymbol.hasSlot()) {
- if(indexSymbol.isShared()) {
- indexSymbol = temporarySymbols.createUnshared(indexSymbol);
- }
- indexSymbol.setNeedsSlot(true);
- attrLexicalContext.getCurrentBlock().putSymbol(attrLexicalContext, indexSymbol);
- return indexNode.setIndex(index.setSymbol(attrLexicalContext, indexSymbol));
- }
- return indexNode;
- }
- });
- }
-
- /**
* Return the type that arithmetic ops should use. Until we have implemented better type
* analysis (range based) or overflow checks that are fast enough for int arithmetic,
* this is the number type
@@ -1704,7 +1697,7 @@
newType(lhs.getSymbol(), destType); //may not narrow if dest is already wider than destType
// ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine
- return end(ensureSymbol(destType, ensureAssignmentSlots(binaryNode)));
+ return end(ensureSymbol(destType, binaryNode));
}
private Expression ensureSymbol(final Type type, final Expression expr) {
--- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Sat Sep 14 20:43:34 2013 +0100
@@ -1361,6 +1361,7 @@
final List<Expression> values = new ArrayList<>();
boolean hasGettersSetters = false;
+ Expression protoNode = null;
for (PropertyNode propertyNode: elements) {
final Expression value = propertyNode.getValue();
@@ -1369,6 +1370,9 @@
if (value == null) {
hasGettersSetters = true;
+ } else if (key.equals(ScriptObject.PROTO_PROPERTY_NAME)) {
+ protoNode = value;
+ continue;
}
keys.add(key);
@@ -1410,8 +1414,13 @@
}
method.dup();
- globalObjectPrototype();
- method.invoke(ScriptObject.SET_PROTO);
+ if (protoNode != null) {
+ load(protoNode);
+ method.invoke(ScriptObject.SET_PROTO_CHECK);
+ } else {
+ globalObjectPrototype();
+ method.invoke(ScriptObject.SET_PROTO);
+ }
if (hasGettersSetters) {
for (final PropertyNode propertyNode : elements) {
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java Sat Sep 14 20:43:34 2013 +0100
@@ -102,8 +102,12 @@
/** the varargs variable when necessary */
VARARGS(":varargs", Object[].class),
- /** the arguments vector when necessary and the slot */
- ARGUMENTS("arguments", ScriptObject.class, 2),
+ /** the arguments variable (visible to function body). Initially set to ARGUMENTS, but can be reassigned by code in
+ * the function body.*/
+ ARGUMENTS_VAR("arguments", Object.class),
+
+ /** the internal arguments object, when necessary (not visible to scripts, can't be reassigned). */
+ ARGUMENTS(":arguments", ScriptObject.class),
/** prefix for iterators for for (x in ...) */
ITERATOR_PREFIX(":i", Iterator.class),
--- a/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java Sat Sep 14 20:43:34 2013 +0100
@@ -168,6 +168,7 @@
* return 3;
* }
* }
+ * </pre>
*
* @return true if can have callsite type
*/
--- a/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java Sat Sep 14 20:43:34 2013 +0100
@@ -27,6 +27,7 @@
import java.util.Arrays;
import java.util.List;
+import java.util.ArrayList;
import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode;
@@ -197,10 +198,10 @@
comma();
final IdentNode label = breakNode.getLabel();
+ property("label");
if (label != null) {
- property("label", label.getName());
+ label.accept(this);
} else {
- property("label");
nullValue();
}
@@ -256,13 +257,11 @@
comma();
final Node guard = catchNode.getExceptionCondition();
- property("guard");
if (guard != null) {
+ property("guard");
guard.accept(this);
- } else {
- nullValue();
+ comma();
}
- comma();
property("body");
catchNode.getBody().accept(this);
@@ -278,10 +277,10 @@
comma();
final IdentNode label = continueNode.getLabel();
+ property("label");
if (label != null) {
- property("label", label.getName());
+ label.accept(this);
} else {
- property("label");
nullValue();
}
@@ -299,13 +298,20 @@
@Override
public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
+ // handle debugger statement
+ final Node expression = expressionStatement.getExpression();
+ if (expression instanceof RuntimeNode) {
+ expression.accept(this);
+ return false;
+ }
+
enterDefault(expressionStatement);
type("ExpressionStatement");
comma();
property("expression");
- expressionStatement.getExpression().accept(this);
+ expression.accept(this);
return leave();
}
@@ -388,13 +394,14 @@
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
- enterDefault(functionNode);
+ final boolean program = functionNode.isProgram();
+ if (program) {
+ return emitProgram(functionNode);
+ }
- final boolean program = functionNode.isProgram();
+ enterDefault(functionNode);
final String name;
- if (program) {
- name = "Program";
- } else if (functionNode.isDeclared()) {
+ if (functionNode.isDeclared()) {
name = "FunctionDeclaration";
} else {
name = "FunctionExpression";
@@ -402,24 +409,41 @@
type(name);
comma();
- if (! program) {
- property("id");
- if (functionNode.isAnonymous()) {
- nullValue();
- } else {
- functionNode.getIdent().accept(this);
- }
- comma();
+ property("id");
+ if (functionNode.isAnonymous()) {
+ nullValue();
+ } else {
+ functionNode.getIdent().accept(this);
}
+ comma();
+
+ array("params", functionNode.getParameters());
+ comma();
+
+ arrayStart("defaults");
+ arrayEnd();
+ comma();
property("rest");
nullValue();
comma();
- if (!program) {
- array("params", functionNode.getParameters());
- comma();
- }
+ property("body");
+ functionNode.getBody().accept(this);
+ comma();
+
+ property("generator", false);
+ comma();
+
+ property("expression", false);
+
+ return leave();
+ }
+
+ private boolean emitProgram(final FunctionNode functionNode) {
+ enterDefault(functionNode);
+ type("Program");
+ comma();
// body consists of nested functions and statements
final List<Statement> stats = functionNode.getBody().getStatements();
@@ -730,7 +754,31 @@
tryNode.getBody().accept(this);
comma();
- array("handlers", tryNode.getCatches());
+
+ final List<? extends Node> catches = tryNode.getCatches();
+ final List<CatchNode> guarded = new ArrayList<>();
+ CatchNode unguarded = null;
+ if (catches != null) {
+ for (Node n : catches) {
+ CatchNode cn = (CatchNode)n;
+ if (cn.getExceptionCondition() != null) {
+ guarded.add(cn);
+ } else {
+ assert unguarded == null: "too many unguarded?";
+ unguarded = cn;
+ }
+ }
+ }
+
+ array("guardedHandlers", guarded);
+ comma();
+
+ property("handler");
+ if (unguarded != null) {
+ unguarded.accept(this);
+ } else {
+ nullValue();
+ }
comma();
property("finalizer");
@@ -760,8 +808,8 @@
array("arguments", callNode.getArgs());
} else {
+ final String operator;
final boolean prefix;
- final String operator;
switch (tokenType) {
case INCPOSTFIX:
prefix = false;
@@ -780,8 +828,9 @@
prefix = true;
break;
default:
- prefix = false;
+ prefix = true;
operator = tokenType.getName();
+ break;
}
type(unaryNode.isAssignment()? "UpdateExpression" : "UnaryExpression");
@@ -802,6 +851,14 @@
@Override
public boolean enterVarNode(final VarNode varNode) {
+ final Node init = varNode.getInit();
+ if (init instanceof FunctionNode && ((FunctionNode)init).isDeclared()) {
+ // function declaration - don't emit VariableDeclaration instead
+ // just emit FunctionDeclaration using 'init' Node.
+ init.accept(this);
+ return false;
+ }
+
enterDefault(varNode);
type("VariableDeclaration");
@@ -816,11 +873,11 @@
type("VariableDeclarator");
comma();
- property("id", varNode.getName().toString());
+ property("id");
+ varNode.getName().accept(this);
comma();
property("init");
- final Node init = varNode.getInit();
if (init != null) {
init.accept(this);
} else {
@@ -855,7 +912,7 @@
whileNode.getTest().accept(this);
comma();
- property("block");
+ property("body");
whileNode.getBody().accept(this);
}
@@ -894,23 +951,27 @@
return buf.toString();
}
- private void property(final String key, final String value) {
+ private void property(final String key, final String value, final boolean escape) {
buf.append('"');
buf.append(key);
buf.append("\":");
if (value != null) {
- buf.append('"');
+ if (escape) buf.append('"');
buf.append(value);
- buf.append('"');
+ if (escape) buf.append('"');
}
}
+ private void property(final String key, final String value) {
+ property(key, value, true);
+ }
+
private void property(final String key, final boolean value) {
- property(key, Boolean.toString(value));
+ property(key, Boolean.toString(value), false);
}
private void property(final String key, final int value) {
- property(key, Integer.toString(value));
+ property(key, Integer.toString(value), false);
}
private void property(final String key) {
--- a/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java Sat Sep 14 20:43:34 2013 +0100
@@ -565,7 +565,7 @@
@Override
public MethodHandle asSpreader(final MethodHandle handle, final Class<?> arrayType, final int arrayLength) {
- final MethodHandle mh = super.asCollector(handle, arrayType, arrayLength);
+ final MethodHandle mh = super.asSpreader(handle, arrayType, arrayLength);
return debug(mh, "asSpreader", handle, arrayType, arrayLength);
}
--- a/nashorn/src/jdk/nashorn/internal/objects/Global.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java Sat Sep 14 20:43:34 2013 +0100
@@ -412,6 +412,14 @@
// initialized by nasgen
private static PropertyMap $nasgenmap$;
+ // context to which this global belongs to
+ private final Context context;
+
+ @Override
+ protected Context getContext() {
+ return context;
+ }
+
// performs initialization checks for Global constructor and returns the
// PropertyMap, if everything is fine.
private static PropertyMap checkAndGetMap(final Context context) {
@@ -439,7 +447,7 @@
*/
public Global(final Context context) {
super(checkAndGetMap(context));
- this.setContext(context);
+ this.context = context;
this.setIsScope();
final int cacheSize = context.getEnv()._class_cache_size;
@@ -482,6 +490,16 @@
// GlobalObject interface implementation
@Override
+ public boolean isOfContext(final Context context) {
+ return this.context == context;
+ }
+
+ @Override
+ public boolean isStrictContext() {
+ return context.getEnv()._strict;
+ }
+
+ @Override
public void initBuiltinObjects() {
if (this.builtinObject != null) {
// already initialized, just return
@@ -1765,7 +1783,7 @@
// do not fill $ENV if we have a security manager around
// Retrieve current state of ENV variables.
final ScriptObject env = newObject();
- env.putAll(System.getenv());
+ env.putAll(System.getenv(), scriptEnv._strict);
addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env);
} else {
addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java Sat Sep 14 20:43:34 2013 +0100
@@ -41,7 +41,7 @@
import java.util.List;
import java.util.concurrent.Callable;
-import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
@@ -374,7 +374,7 @@
public static Object isArray(final Object self, final Object arg) {
return isArray(arg) || (arg == Global.instance().getArrayPrototype())
|| (arg instanceof NativeRegExpExecResult)
- || (arg instanceof ScriptObjectMirror && ((ScriptObjectMirror)arg).isArray());
+ || (arg instanceof JSObject && ((JSObject)arg).isArray());
}
/**
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java Sat Sep 14 20:43:34 2013 +0100
@@ -30,7 +30,7 @@
import java.util.List;
-import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
@@ -88,7 +88,7 @@
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object apply(final Object self, final Object thiz, final Object array) {
- if (!(self instanceof ScriptFunction)) {
+ if (!(self instanceof ScriptFunction) && !(self instanceof JSObject)) {
throw typeError("not.a.function", ScriptRuntime.safeToString(self));
}
@@ -111,21 +111,27 @@
list.toArray(args = new Object[list.size()]);
} else if (array == null || array == UNDEFINED) {
args = ScriptRuntime.EMPTY_ARRAY;
- } else if (array instanceof ScriptObjectMirror) {
- // look for array-like ScriptObjectMirror object
- final ScriptObjectMirror mirror = (ScriptObjectMirror)array;
- final Object len = mirror.containsKey("length")? mirror.getMember("length") : Integer.valueOf(0);
+ } else if (array instanceof JSObject) {
+ // look for array-like JSObject object
+ final JSObject jsObj = (JSObject)array;
+ final Object len = jsObj.hasMember("length")? jsObj.getMember("length") : Integer.valueOf(0);
final int n = (int)JSType.toUint32(len);
args = new Object[n];
for (int i = 0; i < args.length; i++) {
- args[i] = mirror.containsKey(i)? mirror.getSlot(i) : UNDEFINED;
+ args[i] = jsObj.hasSlot(i)? jsObj.getSlot(i) : UNDEFINED;
}
} else {
throw typeError("function.apply.expects.array");
}
- return ScriptRuntime.apply((ScriptFunction)self, thiz, args);
+ if (self instanceof ScriptFunction) {
+ return ScriptRuntime.apply((ScriptFunction)self, thiz, args);
+ } else if (self instanceof JSObject) {
+ return ((JSObject)self).call(thiz, args);
+ }
+
+ throw new AssertionError("should not reach here");
}
/**
@@ -137,7 +143,7 @@
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
public static Object call(final Object self, final Object... args) {
- if (!(self instanceof ScriptFunction)) {
+ if (!(self instanceof ScriptFunction) && !(self instanceof JSObject)) {
throw typeError("not.a.function", ScriptRuntime.safeToString(self));
}
@@ -151,7 +157,13 @@
arguments = ScriptRuntime.EMPTY_ARRAY;
}
- return ScriptRuntime.apply((ScriptFunction)self, thiz, arguments);
+ if (self instanceof ScriptFunction) {
+ return ScriptRuntime.apply((ScriptFunction)self, thiz, arguments);
+ } else if (self instanceof JSObject) {
+ return ((JSObject)self).call(thiz, arguments);
+ }
+
+ throw new AssertionError("should not reach here");
}
/**
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java Sat Sep 14 20:43:34 2013 +0100
@@ -34,6 +34,7 @@
import java.util.List;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.support.TypeUtilities;
+import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
@@ -43,6 +44,7 @@
import jdk.nashorn.internal.runtime.ListAdapter;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
@@ -288,7 +290,9 @@
return null;
}
- Global.checkObject(obj);
+ if (!(obj instanceof ScriptObject) && !(obj instanceof JSObject)) {
+ throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
+ }
final Class<?> targetClass;
if(objType == UNDEFINED) {
@@ -304,11 +308,11 @@
}
if(targetClass.isArray()) {
- return ((ScriptObject)obj).getArray().asArrayOfType(targetClass.getComponentType());
+ return JSType.toJavaArray(obj, targetClass.getComponentType());
}
if(targetClass == List.class || targetClass == Deque.class) {
- return new ListAdapter((ScriptObject)obj);
+ return ListAdapter.create(obj);
}
throw typeError("unsupported.java.to.type", targetClass.getName());
--- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java Sat Sep 14 20:43:34 2013 +0100
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.parser;
-import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL;
import static jdk.nashorn.internal.codegen.CompilerConstants.FUNCTION_PREFIX;
import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT;
@@ -115,6 +114,8 @@
* Builds the IR.
*/
public class Parser extends AbstractParser {
+ private static final String ARGUMENTS_NAME = CompilerConstants.ARGUMENTS_VAR.symbolName();
+
/** Current script environment. */
private final ScriptEnvironment env;
@@ -511,13 +512,19 @@
* @param ident Referenced property.
*/
private void detectSpecialProperty(final IdentNode ident) {
- final String name = ident.getName();
-
- if (ARGUMENTS.symbolName().equals(name)) {
+ if (isArguments(ident)) {
lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_ARGUMENTS);
}
}
+ private static boolean isArguments(final String name) {
+ return ARGUMENTS_NAME.equals(name);
+ }
+
+ private static boolean isArguments(final IdentNode ident) {
+ return isArguments(ident.getName());
+ }
+
/**
* Tells whether a IdentNode can be used as L-value of an assignment
*
@@ -2060,7 +2067,7 @@
case FLOATING:
return getLiteral();
default:
- return getIdentifierName();
+ return getIdentifierName().setIsPropertyName();
}
}
@@ -2449,7 +2456,7 @@
} else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) {
warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken);
}
- if (ARGUMENTS.symbolName().equals(name.getName())) {
+ if (isArguments(name)) {
lc.setFlag(lc.getCurrentFunction(), FunctionNode.DEFINES_ARGUMENTS);
}
}
@@ -2468,7 +2475,7 @@
final IdentNode parameter = parameters.get(i);
String parameterName = parameter.getName();
- if (ARGUMENTS.symbolName().equals(parameterName)) {
+ if (isArguments(parameterName)) {
functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
}
@@ -2486,7 +2493,7 @@
parametersSet.add(parameterName);
}
} else if (arity == 1) {
- if (ARGUMENTS.symbolName().equals(parameters.get(0).getName())) {
+ if (isArguments(parameters.get(0))) {
functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
}
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java Sat Sep 14 20:43:34 2013 +0100
@@ -236,6 +236,10 @@
private static final ClassLoader myLoader = Context.class.getClassLoader();
private static final StructureLoader sharedLoader;
+ /*package-private*/ ClassLoader getSharedLoader() {
+ return sharedLoader;
+ }
+
private static AccessControlContext createNoPermAccCtxt() {
return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) });
}
@@ -254,7 +258,7 @@
sharedLoader = AccessController.doPrivileged(new PrivilegedAction<StructureLoader>() {
@Override
public StructureLoader run() {
- return new StructureLoader(myLoader, null);
+ return new StructureLoader(myLoader);
}
}, CREATE_LOADER_ACC_CTXT);
}
@@ -573,7 +577,7 @@
setGlobalTrusted(newGlobal);
final Object[] wrapped = args == null? ScriptRuntime.EMPTY_ARRAY : ScriptObjectMirror.wrapArray(args, oldGlobal);
- newGlobal.put("arguments", ((GlobalObject)newGlobal).wrapAsObject(wrapped));
+ newGlobal.put("arguments", ((GlobalObject)newGlobal).wrapAsObject(wrapped), env._strict);
try {
// wrap objects from newGlobal's world as mirrors - but if result
@@ -599,7 +603,7 @@
* @throws ClassNotFoundException if structure class cannot be resolved
*/
public static Class<?> forStructureClass(final String fullName) throws ClassNotFoundException {
- if (System.getSecurityManager() != null && !NashornLoader.isStructureClass(fullName)) {
+ if (System.getSecurityManager() != null && !StructureLoader.isStructureClass(fullName)) {
throw new ClassNotFoundException(fullName);
}
return Class.forName(fullName, true, sharedLoader);
@@ -792,12 +796,11 @@
static Context fromClass(final Class<?> clazz) {
final ClassLoader loader = clazz.getClassLoader();
- Context context = null;
- if (loader instanceof NashornLoader) {
- context = ((NashornLoader)loader).getContext();
+ if (loader instanceof ScriptLoader) {
+ return ((ScriptLoader)loader).getContext();
}
- return (context != null) ? context : Context.getContextTrusted();
+ return Context.getContextTrusted();
}
private Object evaluateSource(final Source source, final ScriptObject scope, final ScriptObject thiz) {
@@ -899,7 +902,7 @@
new PrivilegedAction<ScriptLoader>() {
@Override
public ScriptLoader run() {
- return new ScriptLoader(sharedLoader, Context.this);
+ return new ScriptLoader(appLoader, Context.this);
}
}, CREATE_LOADER_ACC_CTXT);
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/ECMAErrors.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ECMAErrors.java Sat Sep 14 20:43:34 2013 +0100
@@ -28,7 +28,6 @@
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;
-
import jdk.nashorn.api.scripting.NashornException;
import jdk.nashorn.internal.scripts.JS;
--- a/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java Sat Sep 14 20:43:34 2013 +0100
@@ -37,6 +37,18 @@
public interface GlobalObject {
/**
+ * Is this global of the given Context?
+ * @return true if this global belongs to the given Context
+ */
+ public boolean isOfContext(Context context);
+
+ /**
+ * Does this global belong to a strict Context?
+ * @return true if this global belongs to a strict Context
+ */
+ public boolean isStrictContext();
+
+ /**
* Initialize standard builtin objects like "Object", "Array", "Function" etc.
* as well as our extension builtin objects like "Java", "JSAdapter" as properties
* of the global scope object.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/JSObjectListAdapter.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. 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.nashorn.internal.runtime;
+
+import jdk.nashorn.api.scripting.JSObject;
+
+/**
+ * A ListAdapter that can wraps a JSObject.
+ */
+public final class JSObjectListAdapter extends ListAdapter {
+ /**
+ * Creates a new list wrapper for the specified JSObject.
+ * @param obj JSOcript the object to wrap
+ */
+ public JSObjectListAdapter(final JSObject obj) {
+ super(obj);
+ }
+
+ @Override
+ public int size() {
+ return JSType.toInt32(((JSObject)obj).getMember("length"));
+ }
+
+ @Override
+ protected Object getAt(int index) {
+ return ((JSObject)obj).getSlot(index);
+ }
+
+ @Override
+ protected void setAt(int index, Object element) {
+ ((JSObject)obj).setSlot(index, element);
+ }
+}
--- a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java Sat Sep 14 20:43:34 2013 +0100
@@ -28,11 +28,14 @@
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
-import java.util.Locale;
+import java.lang.reflect.Array;
import jdk.internal.dynalink.beans.StaticClass;
+import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.parser.Lexer;
+import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
/**
@@ -40,25 +43,28 @@
*/
public enum JSType {
/** The undefined type */
- UNDEFINED,
+ UNDEFINED("undefined"),
/** The null type */
- NULL,
+ NULL("object"),
/** The boolean type */
- BOOLEAN,
+ BOOLEAN("boolean"),
/** The number type */
- NUMBER,
+ NUMBER("number"),
/** The string type */
- STRING,
+ STRING("string"),
/** The object type */
- OBJECT,
+ OBJECT("object"),
/** The function type */
- FUNCTION;
+ FUNCTION("function");
+
+ /** The type name as returned by ECMAScript "typeof" operator*/
+ private final String typeName;
/** Max value for an uint32 in JavaScript */
public static final long MAX_UINT = 0xFFFF_FFFFL;
@@ -110,13 +116,21 @@
private static final double INT32_LIMIT = 4294967296.0;
/**
+ * Constructor
+ *
+ * @param typeName the type name
+ */
+ private JSType(final String typeName) {
+ this.typeName = typeName;
+ }
+
+ /**
* The external type name as returned by ECMAScript "typeof" operator
*
* @return type name for this type
*/
public final String typeName() {
- // For NULL, "object" has to be returned!
- return ((this == NULL) ? OBJECT : this).name().toLowerCase(Locale.ENGLISH);
+ return this.typeName;
}
/**
@@ -127,31 +141,32 @@
* @return the JSType for the object
*/
public static JSType of(final Object obj) {
- if (obj == ScriptRuntime.UNDEFINED) {
- return JSType.UNDEFINED;
+ // Order of these statements is tuned for performance (see JDK-8024476)
+ if (obj == null) {
+ return JSType.NULL;
}
- if (obj == null) {
- return JSType.NULL;
+ if (obj instanceof ScriptObject) {
+ return (obj instanceof ScriptFunction) ? JSType.FUNCTION : JSType.OBJECT;
}
if (obj instanceof Boolean) {
return JSType.BOOLEAN;
}
+ if (obj instanceof String || obj instanceof ConsString) {
+ return JSType.STRING;
+ }
+
if (obj instanceof Number) {
return JSType.NUMBER;
}
- if (obj instanceof String || obj instanceof ConsString) {
- return JSType.STRING;
+ if (obj == ScriptRuntime.UNDEFINED) {
+ return JSType.UNDEFINED;
}
- if (Bootstrap.isCallable(obj)) {
- return JSType.FUNCTION;
- }
-
- return JSType.OBJECT;
+ return Bootstrap.isCallable(obj) ? JSType.FUNCTION : JSType.OBJECT;
}
/**
@@ -849,6 +864,53 @@
}
/**
+ * Script object to Java array conversion.
+ *
+ * @param obj script object to be converted to Java array
+ * @param componentType component type of the destination array required
+ * @return converted Java array
+ */
+ public static Object toJavaArray(final Object obj, final Class<?> componentType) {
+ if (obj instanceof ScriptObject) {
+ return convertArray(((ScriptObject)obj).getArray().asObjectArray(), componentType);
+ } else if (obj instanceof JSObject) {
+ final ArrayLikeIterator itr = ArrayLikeIterator.arrayLikeIterator(obj);
+ final int len = (int) itr.getLength();
+ final Object[] res = new Object[len];
+ int idx = 0;
+ while (itr.hasNext()) {
+ res[idx++] = itr.next();
+ }
+ return convertArray(res, componentType);
+ } else {
+ throw new IllegalArgumentException("not a script object");
+ }
+ }
+
+ /**
+ * Java array to java array conversion - but using type conversions implemented by linker.
+ *
+ * @param src source array
+ * @param componentType component type of the destination array required
+ * @return converted Java array
+ */
+ public static Object convertArray(final Object[] src, final Class<?> componentType) {
+ final int l = src.length;
+ final Object dst = Array.newInstance(componentType, l);
+ final MethodHandle converter = Bootstrap.getLinkerServices().getTypeConverter(Object.class, componentType);
+ try {
+ for (int i = 0; i < src.length; i++) {
+ Array.set(dst, i, invoke(converter, src[i]));
+ }
+ } catch (final RuntimeException | Error e) {
+ throw e;
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ }
+ return dst;
+ }
+
+ /**
* Check if an object is null or undefined
*
* @param obj object to check
@@ -953,4 +1015,13 @@
return Double.NaN;
}
+ private static Object invoke(final MethodHandle mh, final Object arg) {
+ try {
+ return mh.invoke(arg);
+ } catch (final RuntimeException | Error e) {
+ throw e;
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java Sat Sep 14 20:43:34 2013 +0100
@@ -32,6 +32,7 @@
import java.util.NoSuchElementException;
import java.util.RandomAccess;
import java.util.concurrent.Callable;
+import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
@@ -48,7 +49,7 @@
* operations respectively, while {@link #addLast(Object)} and {@link #removeLast()} will translate to {@code push} and
* {@code pop}.
*/
-public final class ListAdapter extends AbstractList<Object> implements RandomAccess, Deque<Object> {
+public abstract class ListAdapter extends AbstractList<Object> implements RandomAccess, Deque<Object> {
// These add to the back and front of the list
private static final Object PUSH = new Object();
private static InvokeByName getPUSH() {
@@ -56,7 +57,7 @@
new Callable<InvokeByName>() {
@Override
public InvokeByName call() {
- return new InvokeByName("push", ScriptObject.class, void.class, Object.class);
+ return new InvokeByName("push", Object.class, void.class, Object.class);
}
});
}
@@ -67,7 +68,7 @@
new Callable<InvokeByName>() {
@Override
public InvokeByName call() {
- return new InvokeByName("unshift", ScriptObject.class, void.class, Object.class);
+ return new InvokeByName("unshift", Object.class, void.class, Object.class);
}
});
}
@@ -79,7 +80,7 @@
new Callable<InvokeByName>() {
@Override
public InvokeByName call() {
- return new InvokeByName("pop", ScriptObject.class, Object.class);
+ return new InvokeByName("pop", Object.class, Object.class);
}
});
}
@@ -90,7 +91,7 @@
new Callable<InvokeByName>() {
@Override
public InvokeByName call() {
- return new InvokeByName("shift", ScriptObject.class, Object.class);
+ return new InvokeByName("shift", Object.class, Object.class);
}
});
}
@@ -102,7 +103,7 @@
new Callable<InvokeByName>() {
@Override
public InvokeByName call() {
- return new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class, Object.class);
+ return new InvokeByName("splice", Object.class, void.class, int.class, int.class, Object.class);
}
});
}
@@ -113,40 +114,52 @@
new Callable<InvokeByName>() {
@Override
public InvokeByName call() {
- return new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class);
+ return new InvokeByName("splice", Object.class, void.class, int.class, int.class);
}
});
}
- private final ScriptObject obj;
+ protected final Object obj;
- /**
- * Creates a new list wrapper for the specified script object.
- * @param obj script the object to wrap
- */
- public ListAdapter(ScriptObject obj) {
+ // allow subclasses only in this package
+ ListAdapter(Object obj) {
this.obj = obj;
}
- @Override
- public int size() {
- return JSType.toInt32(obj.getLength());
+ /**
+ * Factory to create a ListAdapter for a given script object.
+ *
+ * @param obj script object to wrap as a ListAdapter
+ * @return A ListAdapter wrapper object
+ */
+ public static ListAdapter create(final Object obj) {
+ if (obj instanceof ScriptObject) {
+ return new ScriptObjectListAdapter((ScriptObject)obj);
+ } else if (obj instanceof JSObject) {
+ return new JSObjectListAdapter((JSObject)obj);
+ } else {
+ throw new IllegalArgumentException("ScriptObject or JSObject expected");
+ }
}
@Override
- public Object get(int index) {
+ public final Object get(int index) {
checkRange(index);
- return obj.get(index);
+ return getAt(index);
}
+ protected abstract Object getAt(final int index);
+
@Override
public Object set(int index, Object element) {
checkRange(index);
- final Object prevValue = get(index);
- obj.set(index, element, false);
+ final Object prevValue = getAt(index);
+ setAt(index, element);
return prevValue;
}
+ protected abstract void setAt(int index, Object element);
+
private void checkRange(int index) {
if(index < 0 || index >= size()) {
throw invalidIndex(index);
@@ -154,18 +167,18 @@
}
@Override
- public void push(Object e) {
+ public final void push(Object e) {
addFirst(e);
}
@Override
- public boolean add(Object e) {
+ public final boolean add(Object e) {
addLast(e);
return true;
}
@Override
- public void addFirst(Object e) {
+ public final void addFirst(Object e) {
try {
final InvokeByName unshiftInvoker = getUNSHIFT();
final Object fn = unshiftInvoker.getGetter().invokeExact(obj);
@@ -179,7 +192,7 @@
}
@Override
- public void addLast(Object e) {
+ public final void addLast(Object e) {
try {
final InvokeByName pushInvoker = getPUSH();
final Object fn = pushInvoker.getGetter().invokeExact(obj);
@@ -193,7 +206,7 @@
}
@Override
- public void add(int index, Object e) {
+ public final void add(int index, Object e) {
try {
if(index < 0) {
throw invalidIndex(index);
@@ -229,40 +242,40 @@
}
@Override
- public boolean offer(Object e) {
+ public final boolean offer(Object e) {
return offerLast(e);
}
@Override
- public boolean offerFirst(Object e) {
+ public final boolean offerFirst(Object e) {
addFirst(e);
return true;
}
@Override
- public boolean offerLast(Object e) {
+ public final boolean offerLast(Object e) {
addLast(e);
return true;
}
@Override
- public Object pop() {
+ public final Object pop() {
return removeFirst();
}
@Override
- public Object remove() {
+ public final Object remove() {
return removeFirst();
}
@Override
- public Object removeFirst() {
+ public final Object removeFirst() {
checkNonEmpty();
return invokeShift();
}
@Override
- public Object removeLast() {
+ public final Object removeLast() {
checkNonEmpty();
return invokePop();
}
@@ -274,7 +287,7 @@
}
@Override
- public Object remove(int index) {
+ public final Object remove(int index) {
if(index < 0) {
throw invalidIndex(index);
} else if (index == 0) {
@@ -320,7 +333,7 @@
}
@Override
- protected void removeRange(int fromIndex, int toIndex) {
+ protected final void removeRange(int fromIndex, int toIndex) {
invokeSpliceRemove(fromIndex, toIndex - fromIndex);
}
@@ -338,54 +351,54 @@
}
@Override
- public Object poll() {
+ public final Object poll() {
return pollFirst();
}
@Override
- public Object pollFirst() {
+ public final Object pollFirst() {
return isEmpty() ? null : invokeShift();
}
@Override
- public Object pollLast() {
+ public final Object pollLast() {
return isEmpty() ? null : invokePop();
}
@Override
- public Object peek() {
+ public final Object peek() {
return peekFirst();
}
@Override
- public Object peekFirst() {
+ public final Object peekFirst() {
return isEmpty() ? null : get(0);
}
@Override
- public Object peekLast() {
+ public final Object peekLast() {
return isEmpty() ? null : get(size() - 1);
}
@Override
- public Object element() {
+ public final Object element() {
return getFirst();
}
@Override
- public Object getFirst() {
+ public final Object getFirst() {
checkNonEmpty();
return get(0);
}
@Override
- public Object getLast() {
+ public final Object getLast() {
checkNonEmpty();
return get(size() - 1);
}
@Override
- public Iterator<Object> descendingIterator() {
+ public final Iterator<Object> descendingIterator() {
final ListIterator<Object> it = listIterator(size());
return new Iterator<Object>() {
@Override
@@ -406,12 +419,12 @@
}
@Override
- public boolean removeFirstOccurrence(Object o) {
+ public final boolean removeFirstOccurrence(Object o) {
return removeOccurrence(o, iterator());
}
@Override
- public boolean removeLastOccurrence(Object o) {
+ public final boolean removeLastOccurrence(Object o) {
return removeOccurrence(o, descendingIterator());
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/NashornLoader.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/NashornLoader.java Sat Sep 14 20:43:34 2013 +0100
@@ -38,10 +38,7 @@
import jdk.nashorn.tools.Shell;
/**
- * Superclass for Nashorn class loader classes. This stores Context
- * instance as an instance field. The current context can be
- * efficiently accessed from a given Class via it's ClassLoader.
- *
+ * Superclass for Nashorn class loader classes.
*/
abstract class NashornLoader extends SecureClassLoader {
private static final String OBJECTS_PKG = "jdk.nashorn.internal.objects";
@@ -69,27 +66,8 @@
};
}
- private final Context context;
-
- final Context getContext() {
- return context;
- }
-
- NashornLoader(final ClassLoader parent, final Context context) {
+ NashornLoader(final ClassLoader parent) {
super(parent);
- this.context = context;
- }
-
-
- /**
- * Called by subclass after package access check is done
- * @param name name of the class to be loaded
- * @param resolve whether the class should be resolved or not
- * @return Class object
- * @throws ClassNotFoundException if class cannot be loaded
- */
- protected final Class<?> loadClassTrusted(final String name, final boolean resolve) throws ClassNotFoundException {
- return super.loadClass(name, resolve);
}
protected static void checkPackageAccess(final String name) {
@@ -122,10 +100,6 @@
return permCollection;
}
- static boolean isStructureClass(final String fullName) {
- return fullName.startsWith(SCRIPTS_PKG);
- }
-
/**
* Create a secure URL class loader for the given classpath
* @param classPath classpath for the loader to search from
--- a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java Sat Sep 14 20:43:34 2013 +0100
@@ -198,7 +198,7 @@
final String propertyName = desc.getNameToken(2);
final String fullName = name.isEmpty() ? propertyName : name + "." + propertyName;
- final Context context = getContext();
+ final Context context = Context.getContextTrusted();
Class<?> javaClass = null;
try {
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java Sat Sep 14 20:43:34 2013 +0100
@@ -33,17 +33,42 @@
*
*/
final class ScriptLoader extends NashornLoader {
+ private static final String NASHORN_PKG_PREFIX = "jdk.nashorn.internal.";
+
+ private final Context context;
+
+ /*package-private*/ Context getContext() {
+ return context;
+ }
+
/**
* Constructor.
*/
- ScriptLoader(final StructureLoader parent, final Context context) {
- super(parent, context);
+ ScriptLoader(final ClassLoader parent, final Context context) {
+ super(parent);
+ this.context = context;
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
checkPackageAccess(name);
- return super.loadClassTrusted(name, resolve);
+ try {
+ return super.loadClass(name, resolve);
+ } catch (final ClassNotFoundException | SecurityException e) {
+ // We'll get ClassNotFoundException for Nashorn 'struct' classes.
+ // Also, we'll get SecurityException for jdk.nashorn.internal.*
+ // classes. So, load these using to context's 'shared' loader.
+ // All these classes start with "jdk.nashorn.internal." prefix.
+ try {
+ if (name.startsWith(NASHORN_PKG_PREFIX)) {
+ return context.getSharedLoader().loadClass(name);
+ }
+ } catch (final ClassNotFoundException ignored) {
+ }
+
+ // throw the original exception from here
+ throw e;
+ }
}
// package-private and private stuff below this point
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Sat Sep 14 20:43:34 2013 +0100
@@ -87,6 +87,8 @@
*/
public abstract class ScriptObject extends PropertyListenerManager implements PropertyAccess {
+ /** __proto__ special property name */
+ public static final String PROTO_PROPERTY_NAME = "__proto__";
/** Search fall back routine name for "no such method" */
static final String NO_SUCH_METHOD_NAME = "__noSuchMethod__";
@@ -118,9 +120,6 @@
/** objects proto. */
private ScriptObject proto;
- /** Context of the object, lazily cached. */
- private Context context;
-
/** Object flags. */
private int flags;
@@ -130,6 +129,9 @@
/** Indexed array data. */
private ArrayData arrayData;
+ static final MethodHandle GETPROTO = findOwnMH("getProto", ScriptObject.class);
+ static final MethodHandle SETPROTOCHECK = findOwnMH("setProtoCheck", void.class, Object.class);
+
static final MethodHandle SETFIELD = findOwnMH("setField", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, Object.class, Object.class);
static final MethodHandle SETSPILL = findOwnMH("setSpill", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
static final MethodHandle SETSPILLWITHNEW = findOwnMH("setSpillWithNew", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
@@ -150,6 +152,9 @@
/** Method handle for setting the proto of a ScriptObject */
public static final Call SET_PROTO = virtualCallNoLookup(ScriptObject.class, "setProto", void.class, ScriptObject.class);
+ /** Method handle for setting the proto of a ScriptObject after checking argument */
+ public static final Call SET_PROTO_CHECK = virtualCallNoLookup(ScriptObject.class, "setProtoCheck", void.class, Object.class);
+
/** Method handle for setting the user accessors of a ScriptObject */
public static final Call SET_USER_ACCESSORS = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setUserAccessors", void.class, String.class, ScriptFunction.class, ScriptFunction.class);
@@ -1035,40 +1040,11 @@
}
/**
- * Return true if the script object context is strict
- * @return true if strict context
- */
- public final boolean isStrictContext() {
- return getContext()._strict;
- }
-
- /**
- * Checks if this object belongs to the given context
- * @param ctx context to check against
- * @return true if this object belongs to the given context
- */
- public final boolean isOfContext(final Context ctx) {
- return context == ctx;
- }
-
- /**
* Return the current context from the object's map.
* @return Current context.
*/
- protected final Context getContext() {
- if (context == null) {
- context = Context.fromClass(getClass());
- }
- return context;
- }
-
- /**
- * Set the current context.
- * @param ctx context instance to set
- */
- protected final void setContext(final Context ctx) {
- ctx.getClass();
- this.context = ctx;
+ protected Context getContext() {
+ return Context.fromClass(getClass());
}
/**
@@ -1474,9 +1450,10 @@
/**
* Clears the properties from a ScriptObject
* (java.util.Map-like method to help ScriptObjectMirror implementation)
+ *
+ * @param strict strict mode or not
*/
- public void clear() {
- final boolean strict = isStrictContext();
+ public void clear(final boolean strict) {
final Iterator<String> iter = propertyIterator();
while (iter.hasNext()) {
delete(iter.next(), strict);
@@ -1560,11 +1537,12 @@
*
* @param key property key
* @param value property value
+ * @param strict strict mode or not
* @return oldValue if property with same key existed already
*/
- public Object put(final Object key, final Object value) {
+ public Object put(final Object key, final Object value, final boolean strict) {
final Object oldValue = get(key);
- set(key, value, isStrictContext());
+ set(key, value, strict);
return oldValue;
}
@@ -1574,9 +1552,9 @@
* (java.util.Map-like method to help ScriptObjectMirror implementation)
*
* @param otherMap a {@literal <key,value>} map of properties to add
+ * @param strict strict mode or not
*/
- public void putAll(final Map<?, ?> otherMap) {
- final boolean strict = isStrictContext();
+ public void putAll(final Map<?, ?> otherMap, final boolean strict) {
for (final Map.Entry<?, ?> entry : otherMap.entrySet()) {
set(entry.getKey(), entry.getValue(), strict);
}
@@ -1587,26 +1565,16 @@
* (java.util.Map-like method to help ScriptObjectMirror implementation)
*
* @param key the key of the property
+ * @param strict strict mode or not
* @return the oldValue of the removed property
*/
- public Object remove(final Object key) {
+ public Object remove(final Object key, final boolean strict) {
final Object oldValue = get(key);
- delete(key, isStrictContext());
+ delete(key, strict);
return oldValue;
}
/**
- * Delete a property from the ScriptObject.
- * (to help ScriptObjectMirror implementation)
- *
- * @param key the key of the property
- * @return if the delete was successful or not
- */
- public boolean delete(final Object key) {
- return delete(key, isStrictContext());
- }
-
- /**
* Return the size of the ScriptObject - i.e. the number of properties
* it contains
* (java.util.Map-like method to help ScriptObjectMirror implementation)
@@ -1745,6 +1713,10 @@
MethodHandle methodHandle;
if (find == null) {
+ if (PROTO_PROPERTY_NAME.equals(name)) {
+ return new GuardedInvocation(GETPROTO, NashornGuards.getScriptObjectGuard());
+ }
+
if ("getProp".equals(operator)) {
return noSuchProperty(desc, request);
} else if ("getMethod".equals(operator)) {
@@ -1851,6 +1823,7 @@
* toString = function() { print("global toString"); } // don't affect Object.prototype.toString
*/
FindProperty find = findProperty(name, true, scope, this);
+
// If it's not a scope search, then we don't want any inherited properties except those with user defined accessors.
if (!scope && find != null && find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
// We should still check if inherited data property is not writable
@@ -1866,9 +1839,12 @@
// Existing, non-writable property
return createEmptySetMethod(desc, "property.not.writable", true);
}
- } else if (!isExtensible()) {
- // Non-existing property on a non-extensible object
- return createEmptySetMethod(desc, "object.non.extensible", false);
+ } else {
+ if (PROTO_PROPERTY_NAME.equals(name)) {
+ return new GuardedInvocation(SETPROTOCHECK, NashornGuards.getScriptObjectGuard());
+ } else if (! isExtensible()) {
+ return createEmptySetMethod(desc, "object.non.extensible", false);
+ }
}
return new SetMethodCreator(this, find, desc).createGuardedInvocation();
@@ -2317,11 +2293,9 @@
return;
}
- final boolean isStrict = isStrictContext();
-
if (newLength > arrayLength) {
setArray(getArray().ensure(newLength - 1));
- if (getArray().canDelete(arrayLength, (newLength - 1), isStrict)) {
+ if (getArray().canDelete(arrayLength, (newLength - 1), false)) {
setArray(getArray().delete(arrayLength, (newLength - 1)));
}
return;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObjectListAdapter.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. 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.nashorn.internal.runtime;
+
+/**
+ * A ListAdapter that can wrap a ScriptObject.
+ */
+public final class ScriptObjectListAdapter extends ListAdapter {
+ /**
+ * Creates a new list wrapper for the specified ScriptObject.
+ * @param obj script the object to wrap
+ */
+ public ScriptObjectListAdapter(final ScriptObject obj) {
+ super(obj);
+ }
+
+ @Override
+ public int size() {
+ return JSType.toInt32(((ScriptObject)obj).getLength());
+ }
+
+ @Override
+ protected Object getAt(int index) {
+ return ((ScriptObject)obj).get(index);
+ }
+
+ @Override
+ protected void setAt(int index, Object element) {
+ ((ScriptObject)obj).set(index, element, false);
+ }
+}
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java Sat Sep 14 20:43:34 2013 +0100
@@ -43,6 +43,7 @@
import java.util.NoSuchElementException;
import java.util.Objects;
import jdk.internal.dynalink.beans.StaticClass;
+import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.ir.debug.JSONWriter;
@@ -190,8 +191,8 @@
case FUNCTION:
if (self instanceof ScriptObject) {
className = ((ScriptObject)self).getClassName();
- } else if (self instanceof ScriptObjectMirror) {
- className = ((ScriptObjectMirror)self).getClassName();
+ } else if (self instanceof JSObject) {
+ className = ((JSObject)self).getClassName();
} else {
className = self.getClass().getName();
}
@@ -245,8 +246,8 @@
return new RangeIterator(Array.getLength(obj));
}
- if (obj instanceof ScriptObjectMirror) {
- return ((ScriptObjectMirror)obj).keySet().iterator();
+ if (obj instanceof JSObject) {
+ return ((JSObject)obj).keySet().iterator();
}
if (obj instanceof List) {
@@ -323,8 +324,8 @@
};
}
- if (obj instanceof ScriptObjectMirror) {
- return ((ScriptObjectMirror)obj).values().iterator();
+ if (obj instanceof JSObject) {
+ return ((JSObject)obj).values().iterator();
}
if (obj instanceof Map) {
@@ -352,35 +353,6 @@
}
/**
- * Check that the target function is associated with current Context. And also make sure that 'self', if
- * ScriptObject, is from current context.
- *
- * Call a function given self and args. If the number of the arguments is known in advance, you can likely achieve
- * better performance by {@link Bootstrap#createDynamicInvoker(String, Class, Class...) creating a dynamic invoker}
- * for operation {@code "dyn:call"}, then using its {@link MethodHandle#invokeExact(Object...)} method instead.
- *
- * @param target ScriptFunction object.
- * @param self Receiver in call.
- * @param args Call arguments.
- * @return Call result.
- */
- public static Object checkAndApply(final ScriptFunction target, final Object self, final Object... args) {
- final ScriptObject global = Context.getGlobalTrusted();
- assert (global instanceof GlobalObject): "No current global set";
-
- if (target.getContext() != global.getContext()) {
- throw new IllegalArgumentException("'target' function is not from current Context");
- }
-
- if (self instanceof ScriptObject && ((ScriptObject)self).getContext() != global.getContext()) {
- throw new IllegalArgumentException("'self' object is not from current Context");
- }
-
- // all in order - call real 'apply'
- return apply(target, self, args);
- }
-
- /**
* Call a function given self and args. If the number of the arguments is known in advance, you can likely achieve
* better performance by {@link Bootstrap#createDynamicInvoker(String, Class, Class...) creating a dynamic invoker}
* for operation {@code "dyn:call"}, then using its {@link MethodHandle#invokeExact(Object...)} method instead.
@@ -401,28 +373,6 @@
}
/**
- * Check that the target function is associated with current Context.
- * And also make sure that 'self', if ScriptObject, is from current context.
- *
- * Call a function as a constructor given args.
- *
- * @param target ScriptFunction object.
- * @param args Call arguments.
- * @return Constructor call result.
- */
- public static Object checkAndConstruct(final ScriptFunction target, final Object... args) {
- final ScriptObject global = Context.getGlobalTrusted();
- assert (global instanceof GlobalObject): "No current global set";
-
- if (target.getContext() != global.getContext()) {
- throw new IllegalArgumentException("'target' function is not from current Context");
- }
-
- // all in order - call real 'construct'
- return construct(target, args);
- }
-
- /**
* Call a script function as a constructor with given args.
*
* @param target ScriptFunction object.
@@ -520,9 +470,12 @@
throw typeError(global, "cant.apply.with.to.null");
}
- final ScriptObject withObject = new WithObject(scope, JSType.toScriptObject(global, expression));
+ final Object wrappedExpr = JSType.toScriptObject(global, expression);
+ if (wrappedExpr instanceof ScriptObject) {
+ return new WithObject(scope, (ScriptObject)wrappedExpr);
+ }
- return withObject;
+ throw typeError(global, "cant.apply.with.to.non.scriptobject");
}
/**
@@ -534,7 +487,7 @@
*/
public static ScriptObject closeWith(final ScriptObject scope) {
if (scope instanceof WithObject) {
- return scope.getProto();
+ return ((WithObject)scope).getParentScope();
}
return scope;
}
@@ -619,8 +572,8 @@
throw typeError("cant.get.property", safeToString(property), "null");
} else if (JSType.isPrimitive(obj)) {
obj = ((ScriptObject)JSType.toScriptObject(obj)).get(property);
- } else if (obj instanceof ScriptObjectMirror) {
- obj = ((ScriptObjectMirror)obj).getMember(property.toString());
+ } else if (obj instanceof JSObject) {
+ obj = ((JSObject)obj).getMember(property.toString());
} else {
obj = UNDEFINED;
}
@@ -672,6 +625,11 @@
return ((ScriptObject) JSType.toScriptObject(obj)).delete(property, Boolean.TRUE.equals(strict));
}
+ if (obj instanceof JSObject) {
+ ((JSObject)obj).removeMember(Objects.toString(property));
+ return true;
+ }
+
// if object is not reference type, vacuously delete is successful.
return true;
}
@@ -863,6 +821,10 @@
return ((ScriptObject)obj).has(property);
}
+ if (obj instanceof JSObject) {
+ return ((JSObject)obj).hasMember(Objects.toString(property));
+ }
+
return false;
}
@@ -889,11 +851,13 @@
return ((StaticClass)clazz).getRepresentedClass().isInstance(obj);
}
- if (clazz instanceof ScriptObjectMirror) {
- if (obj instanceof ScriptObjectMirror) {
- return ((ScriptObjectMirror)clazz).isInstance((ScriptObjectMirror)obj);
- }
- return false;
+ if (clazz instanceof JSObject) {
+ return ((JSObject)clazz).isInstance(obj);
+ }
+
+ // provide for reverse hook
+ if (obj instanceof JSObject) {
+ return ((JSObject)obj).isInstanceOf(clazz);
}
throw typeError("instanceof.on.non.object");
--- a/nashorn/src/jdk/nashorn/internal/runtime/StructureLoader.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/StructureLoader.java Sat Sep 14 20:43:34 2013 +0100
@@ -34,7 +34,6 @@
/**
* Responsible for on the fly construction of structure classes.
- *
*/
final class StructureLoader extends NashornLoader {
private static final String JS_OBJECT_PREFIX_EXTERNAL = binaryName(SCRIPTS_PACKAGE) + '.' + JS_OBJECT_PREFIX.symbolName();
@@ -42,27 +41,17 @@
/**
* Constructor.
*/
- StructureLoader(final ClassLoader parent, final Context context) {
- super(parent, context);
+ StructureLoader(final ClassLoader parent) {
+ super(parent);
}
- @Override
- protected synchronized Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
- // check the cache first
- final Class<?> loadedClass = findLoadedClass(name);
- if (loadedClass != null) {
- if (resolve) {
- resolveClass(loadedClass);
- }
- return loadedClass;
- }
-
- return super.loadClassTrusted(name, resolve);
+ static boolean isStructureClass(final String name) {
+ return name.startsWith(JS_OBJECT_PREFIX_EXTERNAL);
}
@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
- if (name.startsWith(JS_OBJECT_PREFIX_EXTERNAL)) {
+ if (isStructureClass(name)) {
return generateClass(name, name.substring(JS_OBJECT_PREFIX_EXTERNAL.length()));
}
return super.findClass(name);
@@ -75,11 +64,7 @@
* @return Generated class.
*/
private Class<?> generateClass(final String name, final String descriptor) {
- Context context = getContext();
-
- if (context == null) {
- context = Context.getContextTrusted();
- }
+ final Context context = Context.getContextTrusted();
final byte[] code = new ObjectClassGenerator(context).generate(descriptor);
return defineClass(name, code, 0, code.length, new ProtectionDomain(null, getPermissions(null)));
--- a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java Sat Sep 14 20:43:34 2013 +0100
@@ -30,26 +30,26 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.lang.invoke.SwitchPoint;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
-
/**
* This class supports the handling of scope in a with body.
*
*/
public final class WithObject extends ScriptObject implements Scope {
-
+ private static final MethodHandle WITHEXPRESSIONGUARD = findOwnMH("withExpressionGuard", boolean.class, Object.class, PropertyMap.class, SwitchPoint.class);
private static final MethodHandle WITHEXPRESSIONFILTER = findOwnMH("withFilterExpression", Object.class, Object.class);
private static final MethodHandle WITHSCOPEFILTER = findOwnMH("withFilterScope", Object.class, Object.class);
private static final MethodHandle BIND_TO_EXPRESSION_OBJ = findOwnMH("bindToExpression", Object.class, Object.class, Object.class);
private static final MethodHandle BIND_TO_EXPRESSION_FN = findOwnMH("bindToExpression", Object.class, ScriptFunction.class, Object.class);
/** With expression object. */
- private final Object expression;
+ private final ScriptObject expression;
/**
* Constructor
@@ -57,12 +57,13 @@
* @param scope scope object
* @param expression with expression
*/
- WithObject(final ScriptObject scope, final Object expression) {
+ WithObject(final ScriptObject scope, final ScriptObject expression) {
super(scope, null);
setIsScope();
this.expression = expression;
}
+
/**
* Delete a property based on a key.
* @param key Any valid JavaScript value.
@@ -71,15 +72,13 @@
*/
@Override
public boolean delete(final Object key, final boolean strict) {
- if (expression instanceof ScriptObject) {
- final ScriptObject self = (ScriptObject)expression;
- final String propName = JSType.toString(key);
+ final ScriptObject self = expression;
+ final String propName = JSType.toString(key);
- final FindProperty find = self.findProperty(propName, true);
+ final FindProperty find = self.findProperty(propName, true);
- if (find != null) {
- return self.delete(propName, strict);
- }
+ if (find != null) {
+ return self.delete(propName, strict);
}
return false;
@@ -105,18 +104,16 @@
name = null;
}
- if (expression instanceof ScriptObject) {
- self = (ScriptObject)expression;
- if (isNamedOperation) {
- find = self.findProperty(name, true);
- }
+ self = expression;
+ if (isNamedOperation) {
+ find = self.findProperty(name, true);
+ }
- if (find != null) {
- link = self.lookup(desc, request);
+ if (find != null) {
+ link = self.lookup(desc, request);
- if (link != null) {
- return fixExpressionCallSite(ndesc, link);
- }
+ if (link != null) {
+ return fixExpressionCallSite(ndesc, link);
}
}
@@ -126,7 +123,7 @@
}
if (find != null) {
- return fixScopeCallSite(scope.lookup(desc, request));
+ return fixScopeCallSite(scope.lookup(desc, request), name);
}
// the property is not found - now check for
@@ -178,7 +175,7 @@
link = scope.lookup(desc, request);
if (link != null) {
- return fixScopeCallSite(link);
+ return fixScopeCallSite(link, name);
}
return null;
@@ -197,11 +194,9 @@
*/
@Override
FindProperty findProperty(final String key, final boolean deep, final boolean stopOnNonScope, final ScriptObject start) {
- if (expression instanceof ScriptObject) {
- final FindProperty exprProperty = ((ScriptObject)expression).findProperty(key, deep, stopOnNonScope, start);
- if(exprProperty != null) {
- return exprProperty;
- }
+ final FindProperty exprProperty = expression.findProperty(key, deep, stopOnNonScope, start);
+ if (exprProperty != null) {
+ return exprProperty;
}
return super.findProperty(key, deep, stopOnNonScope, start);
}
@@ -220,16 +215,17 @@
* Get first parent scope that is not an instance of WithObject.
*/
private Scope getNonWithParent() {
- ScriptObject proto = getProto();
+ ScriptObject proto = getParentScope();
while (proto != null && proto instanceof WithObject) {
- proto = proto.getProto();
+ proto = ((WithObject)proto).getParentScope();
}
assert proto instanceof Scope : "with scope without parent scope";
return (Scope) proto;
}
+
private static GuardedInvocation fixReceiverType(final GuardedInvocation link, final MethodHandle filter) {
// The receiver may be an Object or a ScriptObject.
final MethodType invType = link.getInvocation().type();
@@ -256,9 +252,13 @@
filterGuard(link, WITHEXPRESSIONFILTER));
}
- private static GuardedInvocation fixScopeCallSite(final GuardedInvocation link) {
+ private GuardedInvocation fixScopeCallSite(final GuardedInvocation link, final String name) {
final GuardedInvocation newLink = fixReceiverType(link, WITHSCOPEFILTER);
- return link.replaceMethods(filter(newLink.getInvocation(), WITHSCOPEFILTER), filterGuard(newLink, WITHSCOPEFILTER));
+ return link.replaceMethods(filter(newLink.getInvocation(), WITHSCOPEFILTER),
+ MH.guardWithTest(
+ expressionGuard(name),
+ filterGuard(newLink, WITHSCOPEFILTER),
+ MH.dropArguments(MH.constant(boolean.class, false), 0, Object.class)));
}
private static MethodHandle filterGuard(final GuardedInvocation link, final MethodHandle filter) {
@@ -279,7 +279,6 @@
return ((WithObject)receiver).expression;
}
-
@SuppressWarnings("unused")
private static Object bindToExpression(final Object fn, final Object receiver) {
return fn instanceof ScriptFunction ? bindToExpression((ScriptFunction) fn, receiver) : fn;
@@ -289,6 +288,17 @@
return fn.makeBoundFunction(withFilterExpression(receiver), new Object[0]);
}
+ private MethodHandle expressionGuard(final String name) {
+ final PropertyMap map = expression.getMap();
+ final SwitchPoint sp = map.getProtoGetSwitchPoint(expression.getProto(), name);
+ return MH.insertArguments(WITHEXPRESSIONGUARD, 1, map, sp);
+ }
+
+ @SuppressWarnings("unused")
+ private static boolean withExpressionGuard(final Object receiver, final PropertyMap map, final SwitchPoint sp) {
+ return ((WithObject)receiver).expression.getMap() == map && (sp == null || !sp.hasBeenInvalidated());
+ }
+
/**
* Drops the WithObject wrapper from the scope.
* @param receiver WithObject wrapper.
@@ -302,10 +312,14 @@
* Get the with expression for this {@code WithObject}
* @return the with expression
*/
- public Object getExpression() {
+ public ScriptObject getExpression() {
return expression;
}
+ public ScriptObject getParentScope() {
+ return getProto();
+ }
+
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
return MH.findStatic(MethodHandles.lookup(), WithObject.class, name, MH.type(rtype, types));
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java Sat Sep 14 20:43:34 2013 +0100
@@ -26,10 +26,9 @@
package jdk.nashorn.internal.runtime.arrays;
import java.lang.invoke.MethodHandle;
-import java.lang.reflect.Array;
import jdk.nashorn.internal.runtime.GlobalObject;
+import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyDescriptor;
-import jdk.nashorn.internal.runtime.linker.Bootstrap;
/**
* ArrayData - abstraction for wrapping array elements
@@ -204,20 +203,7 @@
* @return and array of the given type
*/
public Object asArrayOfType(final Class<?> componentType) {
- final Object[] src = asObjectArray();
- final int l = src.length;
- final Object dst = Array.newInstance(componentType, l);
- final MethodHandle converter = Bootstrap.getLinkerServices().getTypeConverter(Object.class, componentType);
- try {
- for (int i = 0; i < src.length; i++) {
- Array.set(dst, i, invoke(converter, src[i]));
- }
- } catch (final RuntimeException | Error e) {
- throw e;
- } catch (final Throwable t) {
- throw new RuntimeException(t);
- }
- return dst;
+ return JSType.convertArray(asObjectArray(), componentType);
}
/**
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java Sat Sep 14 20:43:34 2013 +0100
@@ -27,7 +27,7 @@
import java.util.Iterator;
import java.util.List;
-import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptObject;
@@ -127,8 +127,8 @@
return new ScriptObjectIterator((ScriptObject)obj, includeUndefined);
}
- if (obj instanceof ScriptObjectMirror) {
- return new ScriptObjectMirrorIterator((ScriptObjectMirror)obj, includeUndefined);
+ if (obj instanceof JSObject) {
+ return new JSObjectIterator((JSObject)obj, includeUndefined);
}
if (obj instanceof List) {
@@ -160,8 +160,8 @@
return new ReverseScriptObjectIterator((ScriptObject)obj, includeUndefined);
}
- if (obj instanceof ScriptObjectMirror) {
- return new ReverseScriptObjectMirrorIterator((ScriptObjectMirror)obj, includeUndefined);
+ if (obj instanceof JSObject) {
+ return new ReverseJSObjectIterator((JSObject)obj, includeUndefined);
}
if (obj instanceof List) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java Sat Sep 14 20:43:34 2013 +0100
@@ -27,7 +27,7 @@
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
-import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptRuntime;
@@ -101,9 +101,9 @@
final boolean strict;
if (callbackfn instanceof ScriptFunction) {
strict = ((ScriptFunction)callbackfn).isStrict();
- } else if (callbackfn instanceof ScriptObjectMirror &&
- ((ScriptObjectMirror)callbackfn).isFunction()) {
- strict = ((ScriptObjectMirror)callbackfn).isStrictFunction();
+ } else if (callbackfn instanceof JSObject &&
+ ((JSObject)callbackfn).isFunction()) {
+ strict = ((JSObject)callbackfn).isStrictFunction();
} else if (Bootstrap.isDynamicMethod(callbackfn) || Bootstrap.isFunctionalInterfaceObject(callbackfn)) {
strict = false;
} else {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/JSObjectIterator.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. 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.nashorn.internal.runtime.arrays;
+
+import java.util.NoSuchElementException;
+import jdk.nashorn.api.scripting.JSObject;
+import jdk.nashorn.internal.runtime.JSType;
+
+/**
+ * Iterator over a ScriptObjectMirror
+ */
+class JSObjectIterator extends ArrayLikeIterator<Object> {
+
+ protected final JSObject obj;
+ private final long length;
+
+ JSObjectIterator(final JSObject obj, final boolean includeUndefined) {
+ super(includeUndefined);
+ this.obj = obj;
+ this.length = JSType.toUint32(obj.hasMember("length")? obj.getMember("length") : 0);
+ this.index = 0;
+ }
+
+ protected boolean indexInArray() {
+ return index < length;
+ }
+
+ @Override
+ public long getLength() {
+ return length;
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (length == 0L) {
+ return false; //return empty string if toUint32(length) == 0
+ }
+
+ while (indexInArray()) {
+ if (obj.hasSlot((int)index) || includeUndefined) {
+ break;
+ }
+ bumpIndex();
+ }
+
+ return indexInArray();
+ }
+
+ @Override
+ public Object next() {
+ if (indexInArray()) {
+ return obj.getSlot((int)bumpIndex());
+ }
+
+ throw new NoSuchElementException();
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseJSObjectIterator.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. 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.nashorn.internal.runtime.arrays;
+
+import jdk.nashorn.api.scripting.JSObject;
+import jdk.nashorn.internal.runtime.JSType;
+
+/**
+ * Reverse iterator over a ScriptObjectMirror
+ */
+final class ReverseJSObjectIterator extends JSObjectIterator {
+
+ ReverseJSObjectIterator(final JSObject obj, final boolean includeUndefined) {
+ super(obj, includeUndefined);
+ this.index = JSType.toUint32(obj.hasMember("length")? obj.getMember("length") : 0) - 1;
+ }
+
+ @Override
+ public boolean isReverse() {
+ return true;
+ }
+
+ @Override
+ protected boolean indexInArray() {
+ return index >= 0;
+ }
+
+ @Override
+ protected long bumpIndex() {
+ return index--;
+ }
+}
+
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseScriptObjectMirrorIterator.java Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. 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.nashorn.internal.runtime.arrays;
-
-import jdk.nashorn.api.scripting.ScriptObjectMirror;
-import jdk.nashorn.internal.runtime.JSType;
-
-/**
- * Reverse iterator over a ScriptObjectMirror
- */
-final class ReverseScriptObjectMirrorIterator extends ScriptObjectMirrorIterator {
-
- ReverseScriptObjectMirrorIterator(final ScriptObjectMirror obj, final boolean includeUndefined) {
- super(obj, includeUndefined);
- this.index = JSType.toUint32(obj.containsKey("length")? obj.getMember("length") : 0) - 1;
- }
-
- @Override
- public boolean isReverse() {
- return true;
- }
-
- @Override
- protected boolean indexInArray() {
- return index >= 0;
- }
-
- @Override
- protected long bumpIndex() {
- return index--;
- }
-}
-
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ScriptObjectMirrorIterator.java Fri Sep 06 09:55:59 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. 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.nashorn.internal.runtime.arrays;
-
-import java.util.NoSuchElementException;
-import jdk.nashorn.api.scripting.ScriptObjectMirror;
-import jdk.nashorn.internal.runtime.JSType;
-
-/**
- * Iterator over a ScriptObjectMirror
- */
-class ScriptObjectMirrorIterator extends ArrayLikeIterator<Object> {
-
- protected final ScriptObjectMirror obj;
- private final long length;
-
- ScriptObjectMirrorIterator(final ScriptObjectMirror obj, final boolean includeUndefined) {
- super(includeUndefined);
- this.obj = obj;
- this.length = JSType.toUint32(obj.containsKey("length")? obj.getMember("length") : 0);
- this.index = 0;
- }
-
- protected boolean indexInArray() {
- return index < length;
- }
-
- @Override
- public long getLength() {
- return length;
- }
-
- @Override
- public boolean hasNext() {
- if (length == 0L) {
- return false; //return empty string if toUint32(length) == 0
- }
-
- while (indexInArray()) {
- if (obj.containsKey(index) || includeUndefined) {
- break;
- }
- bumpIndex();
- }
-
- return indexInArray();
- }
-
- @Override
- public Object next() {
- if (indexInArray()) {
- return obj.get(bumpIndex());
- }
-
- throw new NoSuchElementException();
- }
-}
-
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Sat Sep 14 20:43:34 2013 +0100
@@ -39,7 +39,7 @@
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkerServices;
-import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.codegen.RuntimeCallSite;
import jdk.nashorn.internal.runtime.JSType;
@@ -87,7 +87,7 @@
}
return obj instanceof ScriptFunction ||
- ((obj instanceof ScriptObjectMirror) && ((ScriptObjectMirror)obj).isFunction()) ||
+ ((obj instanceof JSObject) && ((JSObject)obj).isFunction()) ||
isDynamicMethod(obj) ||
isFunctionalInterfaceObject(obj) ||
obj instanceof StaticClass;
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Sat Sep 14 20:43:34 2013 +0100
@@ -30,7 +30,6 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
-import java.util.Objects;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
@@ -88,8 +87,9 @@
case "setElem":
return c > 2 ? findSetMethod(desc) : findSetIndexMethod();
case "call":
+ return findCallMethod(desc, operator);
case "callMethod":
- return findCallMethod(desc, operator);
+ return findCallMethodMethod(desc, operator);
case "new":
return findNewMethod(desc);
default:
@@ -98,33 +98,37 @@
}
private static GuardedInvocation findGetMethod(final CallSiteDescriptor desc) {
- final MethodHandle getter = MH.insertArguments(JSOBJECT_GET, 1, desc.getNameToken(2));
+ final MethodHandle getter = MH.insertArguments(JSOBJECT_GETMEMBER, 1, desc.getNameToken(2));
return new GuardedInvocation(getter, null, IS_JSOBJECT_GUARD);
}
private static GuardedInvocation findGetIndexMethod() {
- return new GuardedInvocation(JSOBJECT_GET, null, IS_JSOBJECT_GUARD);
+ return new GuardedInvocation(JSOBJECTLINKER_GET, null, IS_JSOBJECT_GUARD);
}
private static GuardedInvocation findSetMethod(final CallSiteDescriptor desc) {
- final MethodHandle getter = MH.insertArguments(JSOBJECT_PUT, 1, desc.getNameToken(2));
+ final MethodHandle getter = MH.insertArguments(JSOBJECT_SETMEMBER, 1, desc.getNameToken(2));
return new GuardedInvocation(getter, null, IS_JSOBJECT_GUARD);
}
private static GuardedInvocation findSetIndexMethod() {
- return new GuardedInvocation(JSOBJECT_PUT, null, IS_JSOBJECT_GUARD);
+ return new GuardedInvocation(JSOBJECTLINKER_PUT, null, IS_JSOBJECT_GUARD);
}
- private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final String operator) {
- // if operator is "call", then 'self' is a JSObject function object already. Use 'call' as the method name
- final String methodName = "callMethod".equals(operator)? desc.getNameToken(2) : "call";
- MethodHandle func = MH.insertArguments(JSOBJECT_CALL, 1, methodName);
+ private static GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final String operator) {
+ final String methodName = desc.getNameToken(2);
+ MethodHandle func = MH.insertArguments(JSOBJECT_CALLMEMBER, 1, methodName);
func = MH.asCollector(func, Object[].class, desc.getMethodType().parameterCount() - 1);
return new GuardedInvocation(func, null, IS_JSOBJECT_GUARD);
}
+ private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final String operator) {
+ final MethodHandle func = MH.asCollector(JSOBJECT_CALL, Object[].class, desc.getMethodType().parameterCount() - 2);
+ return new GuardedInvocation(func, null, IS_JSOBJECT_GUARD);
+ }
+
private static GuardedInvocation findNewMethod(final CallSiteDescriptor desc) {
- MethodHandle func = MH.asCollector(JSOBJECT_NEW, Object[].class, desc.getMethodType().parameterCount() - 1);
+ final MethodHandle func = MH.asCollector(JSOBJECT_NEW, Object[].class, desc.getMethodType().parameterCount() - 1);
return new GuardedInvocation(func, null, IS_JSOBJECT_GUARD);
}
@@ -135,36 +139,30 @@
@SuppressWarnings("unused")
private static Object get(final Object jsobj, final Object key) {
- if (key instanceof String) {
- return ((JSObject)jsobj).getMember((String)key);
+ if (key instanceof Integer) {
+ return ((JSObject)jsobj).getSlot((int)(Integer)key);
} else if (key instanceof Number) {
final int index = getIndex((Number)key);
if (index > -1) {
return ((JSObject)jsobj).getSlot(index);
}
+ } else if (key instanceof String) {
+ return ((JSObject)jsobj).getMember((String)key);
}
return null;
}
@SuppressWarnings("unused")
private static void put(final Object jsobj, final Object key, final Object value) {
- if (key instanceof String) {
- ((JSObject)jsobj).setMember((String)key, value);
+ if (key instanceof Integer) {
+ ((JSObject)jsobj).setSlot((int)(Integer)key, value);
} else if (key instanceof Number) {
((JSObject)jsobj).setSlot(getIndex((Number)key), value);
+ } else if (key instanceof String) {
+ ((JSObject)jsobj).setMember((String)key, value);
}
}
- @SuppressWarnings("unused")
- private static Object call(final Object jsobj, final Object method, final Object... args) {
- return ((JSObject)jsobj).call(Objects.toString(method), args);
- }
-
- @SuppressWarnings("unused")
- private static Object newObject(final Object jsobj, final Object... args) {
- return ((JSObject)jsobj).newObject(null, args);
- }
-
private static int getIndex(final Number n) {
final double value = n.doubleValue();
return JSType.isRepresentableAsInt(value) ? (int)value : -1;
@@ -172,11 +170,17 @@
private static final MethodHandleFunctionality MH = MethodHandleFactory.getFunctionality();
- private static final MethodHandle IS_JSOBJECT_GUARD = findOwnMH("isJSObject", boolean.class, Object.class);
- private static final MethodHandle JSOBJECT_GET = findOwnMH("get", Object.class, Object.class, Object.class);
- private static final MethodHandle JSOBJECT_PUT = findOwnMH("put", Void.TYPE, Object.class, Object.class, Object.class);
- private static final MethodHandle JSOBJECT_CALL = findOwnMH("call", Object.class, Object.class, Object.class, Object[].class);
- private static final MethodHandle JSOBJECT_NEW = findOwnMH("newObject", Object.class, Object.class, Object[].class);
+ // method handles of the current class
+ private static final MethodHandle IS_JSOBJECT_GUARD = findOwnMH("isJSObject", boolean.class, Object.class);
+ private static final MethodHandle JSOBJECTLINKER_GET = findOwnMH("get", Object.class, Object.class, Object.class);
+ private static final MethodHandle JSOBJECTLINKER_PUT = findOwnMH("put", Void.TYPE, Object.class, Object.class, Object.class);
+
+ // method handles of JSObject class
+ private static final MethodHandle JSOBJECT_GETMEMBER = findJSObjectMH("getMember", Object.class, String.class);
+ private static final MethodHandle JSOBJECT_SETMEMBER = findJSObjectMH("setMember", Void.TYPE, String.class, Object.class);
+ private static final MethodHandle JSOBJECT_CALLMEMBER = findJSObjectMH("callMember", Object.class, String.class, Object[].class);
+ private static final MethodHandle JSOBJECT_CALL = findJSObjectMH("call", Object.class, Object.class, Object[].class);
+ private static final MethodHandle JSOBJECT_NEW = findJSObjectMH("newObject", Object.class, Object[].class);
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
final Class<?> own = JSObjectLinker.class;
@@ -187,4 +191,14 @@
return MH.findVirtual(MethodHandles.lookup(), own, name, mt);
}
}
+
+ private static MethodHandle findJSObjectMH(final String name, final Class<?> rtype, final Class<?>... types) {
+ final Class<?> own = JSObject.class;
+ final MethodType mt = MH.type(rtype, types);
+ try {
+ return MH.findVirtual(MethodHandles.publicLookup(), own, name, mt);
+ } catch (final MethodHandleFactory.LookupException e) {
+ return MH.findVirtual(MethodHandles.lookup(), own, name, mt);
+ }
+ }
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java Sat Sep 14 20:43:34 2013 +0100
@@ -263,15 +263,6 @@
}
if (atom()) {
- // Check for character classes that never or always match
- if (sb.toString().endsWith("[]")) {
- sb.setLength(sb.length() - 1);
- sb.append("^\\s\\S]");
- } else if (sb.toString().endsWith("[^]")) {
- sb.setLength(sb.length() - 2);
- sb.append("\\s\\S]");
- }
-
quantifier();
return true;
}
@@ -767,7 +758,18 @@
if (classRanges() && ch0 == ']') {
pop(']');
- return commit(1);
+ commit(1);
+
+ // Substitute empty character classes [] and [^] that never or always match
+ if (position == startIn + 2) {
+ sb.setLength(sb.length() - 1);
+ sb.append("^\\s\\S]");
+ } else if (position == startIn + 3 && inNegativeClass) {
+ sb.setLength(sb.length() - 2);
+ sb.append("\\s\\S]");
+ }
+
+ return true;
}
} finally {
inCharClass = false; // no nested character classes in JavaScript
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties Sat Sep 14 20:43:34 2013 +0100
@@ -110,6 +110,7 @@
type.error.cannot.get.default.number=Cannot get default number value
type.error.cant.apply.with.to.null=Cannot apply "with" to null
type.error.cant.apply.with.to.undefined=Cannot apply "with" to undefined
+type.error.cant.apply.with.to.non.scriptobject=Cannot apply "with" to non script object
type.error.in.with.non.object=Right hand side of "in" cannot be non-Object, found {0}
type.error.prototype.not.an.object="prototype" of {0} is not an Object, it is {1}
type.error.cant.load.script=Cannot load script from {0}
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/base.js Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/base.js Sat Sep 14 20:43:34 2013 +0100
@@ -23,204 +23,126 @@
* questions.
*/
-Scene = Java.type("javafx.scene.Scene");
-Group = Java.type("javafx.scene.Group");
-Stage = Java.type("javafx.stage.Stage");
+var JFX_BASE_CLASSES = [];
+var JFX_GRAPHICS_CLASSES = [];
+var JFX_CONTROLS_CLASSES = [];
+var JFX_FXML_CLASSES = [];
+var JFX_WEB_CLASSES = [];
+var JFX_MEDIA_CLASSES = [];
+var JFX_SWING_CLASSES = [];
+var JFX_SWT_CLASSES = [];
+
+function LOAD_FX_CLASSES(clsList) {
+
+ for each (var cls in clsList) {
+ // Ex. Stage = Java.type("javafx.stage.Stage");
+ this[cls[cls.length - 1]] = Java.type(cls.join("."));
+ }
+}
+
+(function() {
+ var System = Java.type("java.lang.System");
+ var ZipFile = Java.type("java.util.zip.ZipFile");
+
+ var SUFFIX_LENGTH = ".class".length;
+
+ try {
+ var jfxrtJar = new ZipFile(System.getProperty("java.home") + "/lib/ext/jfxrt.jar");
+ } catch (ex) {
+ throw new Error("JavaFX runtime not found");
+ }
+
+ var entries = jfxrtJar.entries();
+
+ while (entries.hasMoreElements()) {
+ var entry = entries.nextElement();
+
+ if (entry.isDirectory()) {
+ continue;
+ }
+
+ var name = entry.name;
+
+ if (!name.endsWith(".class")) {
+ continue;
+ }
+
+ name = name.substring(0, name.length - SUFFIX_LENGTH);
+ cls = name.split("/");
+
+ if (cls[0] != "javafx") {
+ continue;
+ }
+
+ var last = cls[cls.length - 1];
+ var nested = last.lastIndexOf("$");
+
+ // If class name ends with $nnn
+ if (nested != -1 && !(last.substring(nested) - 0)) {
+ continue;
+ }
-Binding = Java.type("javafx.beans.binding.Binding");
-Bindings = Java.type("javafx.beans.binding.Bindings");
-BooleanBinding = Java.type("javafx.beans.binding.BooleanBinding");
-BooleanExpression = Java.type("javafx.beans.binding.BooleanExpression");
-DoubleBinding = Java.type("javafx.beans.binding.DoubleBinding");
-DoubleExpression = Java.type("javafx.beans.binding.DoubleExpression");
-FloatBinding = Java.type("javafx.beans.binding.FloatBinding");
-FloatExpression = Java.type("javafx.beans.binding.FloatExpression");
-IntegerBinding = Java.type("javafx.beans.binding.IntegerBinding");
-IntegerExpression = Java.type("javafx.beans.binding.IntegerExpression");
-ListBinding = Java.type("javafx.beans.binding.ListBinding");
-ListExpression = Java.type("javafx.beans.binding.ListExpression");
-LongBinding = Java.type("javafx.beans.binding.LongBinding");
-LongExpression = Java.type("javafx.beans.binding.LongExpression");
-MapBinding = Java.type("javafx.beans.binding.MapBinding");
-MapExpression = Java.type("javafx.beans.binding.MapExpression");
-NumberBinding = Java.type("javafx.beans.binding.NumberBinding");
-NumberExpression = Java.type("javafx.beans.binding.NumberExpression");
-NumberExpressionBase = Java.type("javafx.beans.binding.NumberExpressionBase");
-ObjectBinding = Java.type("javafx.beans.binding.ObjectBinding");
-ObjectExpression = Java.type("javafx.beans.binding.ObjectExpression");
-SetBinding = Java.type("javafx.beans.binding.SetBinding");
-SetExpression = Java.type("javafx.beans.binding.SetExpression");
-StringBinding = Java.type("javafx.beans.binding.StringBinding");
-StringExpression = Java.type("javafx.beans.binding.StringExpression");
-When = Java.type("javafx.beans.binding.When");
-DefaultProperty = Java.type("javafx.beans.DefaultProperty");
-InvalidationListener = Java.type("javafx.beans.InvalidationListener");
-Observable = Java.type("javafx.beans.Observable");
-JavaBeanBooleanProperty = Java.type("javafx.beans.property.adapter.JavaBeanBooleanProperty");
-JavaBeanBooleanPropertyBuilder = Java.type("javafx.beans.property.adapter.JavaBeanBooleanPropertyBuilder");
-JavaBeanDoubleProperty = Java.type("javafx.beans.property.adapter.JavaBeanDoubleProperty");
-JavaBeanDoublePropertyBuilder = Java.type("javafx.beans.property.adapter.JavaBeanDoublePropertyBuilder");
-JavaBeanFloatProperty = Java.type("javafx.beans.property.adapter.JavaBeanFloatProperty");
-JavaBeanFloatPropertyBuilder = Java.type("javafx.beans.property.adapter.JavaBeanFloatPropertyBuilder");
-JavaBeanIntegerProperty = Java.type("javafx.beans.property.adapter.JavaBeanIntegerProperty");
-JavaBeanIntegerPropertyBuilder = Java.type("javafx.beans.property.adapter.JavaBeanIntegerPropertyBuilder");
-JavaBeanLongProperty = Java.type("javafx.beans.property.adapter.JavaBeanLongProperty");
-JavaBeanLongPropertyBuilder = Java.type("javafx.beans.property.adapter.JavaBeanLongPropertyBuilder");
-JavaBeanObjectProperty = Java.type("javafx.beans.property.adapter.JavaBeanObjectProperty");
-JavaBeanObjectPropertyBuilder = Java.type("javafx.beans.property.adapter.JavaBeanObjectPropertyBuilder");
-JavaBeanProperty = Java.type("javafx.beans.property.adapter.JavaBeanProperty");
-JavaBeanStringProperty = Java.type("javafx.beans.property.adapter.JavaBeanStringProperty");
-JavaBeanStringPropertyBuilder = Java.type("javafx.beans.property.adapter.JavaBeanStringPropertyBuilder");
-ReadOnlyJavaBeanBooleanProperty = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanBooleanProperty");
-ReadOnlyJavaBeanBooleanPropertyBuilder = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanBooleanPropertyBuilder");
-ReadOnlyJavaBeanDoubleProperty = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanDoubleProperty");
-ReadOnlyJavaBeanDoublePropertyBuilder = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanDoublePropertyBuilder");
-ReadOnlyJavaBeanFloatProperty = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanFloatProperty");
-ReadOnlyJavaBeanFloatPropertyBuilder = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanFloatPropertyBuilder");
-ReadOnlyJavaBeanIntegerProperty = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanIntegerProperty");
-ReadOnlyJavaBeanIntegerPropertyBuilder = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanIntegerPropertyBuilder");
-ReadOnlyJavaBeanLongProperty = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanLongProperty");
-ReadOnlyJavaBeanLongPropertyBuilder = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanLongPropertyBuilder");
-ReadOnlyJavaBeanObjectProperty = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanObjectProperty");
-ReadOnlyJavaBeanObjectPropertyBuilder = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanObjectPropertyBuilder");
-ReadOnlyJavaBeanProperty = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanProperty");
-ReadOnlyJavaBeanStringProperty = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanStringProperty");
-ReadOnlyJavaBeanStringPropertyBuilder = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanStringPropertyBuilder");
-BooleanProperty = Java.type("javafx.beans.property.BooleanProperty");
-BooleanPropertyBase = Java.type("javafx.beans.property.BooleanPropertyBase");
-DoubleProperty = Java.type("javafx.beans.property.DoubleProperty");
-DoublePropertyBase = Java.type("javafx.beans.property.DoublePropertyBase");
-FloatProperty = Java.type("javafx.beans.property.FloatProperty");
-FloatPropertyBase = Java.type("javafx.beans.property.FloatPropertyBase");
-IntegerProperty = Java.type("javafx.beans.property.IntegerProperty");
-IntegerPropertyBase = Java.type("javafx.beans.property.IntegerPropertyBase");
-ListProperty = Java.type("javafx.beans.property.ListProperty");
-ListPropertyBase = Java.type("javafx.beans.property.ListPropertyBase");
-LongProperty = Java.type("javafx.beans.property.LongProperty");
-LongPropertyBase = Java.type("javafx.beans.property.LongPropertyBase");
-MapProperty = Java.type("javafx.beans.property.MapProperty");
-MapPropertyBase = Java.type("javafx.beans.property.MapPropertyBase");
-ObjectProperty = Java.type("javafx.beans.property.ObjectProperty");
-ObjectPropertyBase = Java.type("javafx.beans.property.ObjectPropertyBase");
-Property = Java.type("javafx.beans.property.Property");
-ReadOnlyBooleanProperty = Java.type("javafx.beans.property.ReadOnlyBooleanProperty");
-ReadOnlyBooleanPropertyBase = Java.type("javafx.beans.property.ReadOnlyBooleanPropertyBase");
-ReadOnlyBooleanWrapper = Java.type("javafx.beans.property.ReadOnlyBooleanWrapper");
-ReadOnlyDoubleProperty = Java.type("javafx.beans.property.ReadOnlyDoubleProperty");
-ReadOnlyDoublePropertyBase = Java.type("javafx.beans.property.ReadOnlyDoublePropertyBase");
-ReadOnlyDoubleWrapper = Java.type("javafx.beans.property.ReadOnlyDoubleWrapper");
-ReadOnlyFloatProperty = Java.type("javafx.beans.property.ReadOnlyFloatProperty");
-ReadOnlyFloatPropertyBase = Java.type("javafx.beans.property.ReadOnlyFloatPropertyBase");
-ReadOnlyFloatWrapper = Java.type("javafx.beans.property.ReadOnlyFloatWrapper");
-ReadOnlyIntegerProperty = Java.type("javafx.beans.property.ReadOnlyIntegerProperty");
-ReadOnlyIntegerPropertyBase = Java.type("javafx.beans.property.ReadOnlyIntegerPropertyBase");
-ReadOnlyIntegerWrapper = Java.type("javafx.beans.property.ReadOnlyIntegerWrapper");
-ReadOnlyListProperty = Java.type("javafx.beans.property.ReadOnlyListProperty");
-ReadOnlyListPropertyBase = Java.type("javafx.beans.property.ReadOnlyListPropertyBase");
-ReadOnlyListWrapper = Java.type("javafx.beans.property.ReadOnlyListWrapper");
-ReadOnlyLongProperty = Java.type("javafx.beans.property.ReadOnlyLongProperty");
-ReadOnlyLongPropertyBase = Java.type("javafx.beans.property.ReadOnlyLongPropertyBase");
-ReadOnlyLongWrapper = Java.type("javafx.beans.property.ReadOnlyLongWrapper");
-ReadOnlyMapProperty = Java.type("javafx.beans.property.ReadOnlyMapProperty");
-ReadOnlyMapPropertyBase = Java.type("javafx.beans.property.ReadOnlyMapPropertyBase");
-ReadOnlyMapWrapper = Java.type("javafx.beans.property.ReadOnlyMapWrapper");
-ReadOnlyObjectProperty = Java.type("javafx.beans.property.ReadOnlyObjectProperty");
-ReadOnlyObjectPropertyBase = Java.type("javafx.beans.property.ReadOnlyObjectPropertyBase");
-ReadOnlyObjectWrapper = Java.type("javafx.beans.property.ReadOnlyObjectWrapper");
-ReadOnlyProperty = Java.type("javafx.beans.property.ReadOnlyProperty");
-ReadOnlySetProperty = Java.type("javafx.beans.property.ReadOnlySetProperty");
-ReadOnlySetPropertyBase = Java.type("javafx.beans.property.ReadOnlySetPropertyBase");
-ReadOnlySetWrapper = Java.type("javafx.beans.property.ReadOnlySetWrapper");
-ReadOnlyStringProperty = Java.type("javafx.beans.property.ReadOnlyStringProperty");
-ReadOnlyStringPropertyBase = Java.type("javafx.beans.property.ReadOnlyStringPropertyBase");
-ReadOnlyStringWrapper = Java.type("javafx.beans.property.ReadOnlyStringWrapper");
-SetProperty = Java.type("javafx.beans.property.SetProperty");
-SetPropertyBase = Java.type("javafx.beans.property.SetPropertyBase");
-SimpleBooleanProperty = Java.type("javafx.beans.property.SimpleBooleanProperty");
-SimpleDoubleProperty = Java.type("javafx.beans.property.SimpleDoubleProperty");
-SimpleFloatProperty = Java.type("javafx.beans.property.SimpleFloatProperty");
-SimpleIntegerProperty = Java.type("javafx.beans.property.SimpleIntegerProperty");
-SimpleListProperty = Java.type("javafx.beans.property.SimpleListProperty");
-SimpleLongProperty = Java.type("javafx.beans.property.SimpleLongProperty");
-SimpleMapProperty = Java.type("javafx.beans.property.SimpleMapProperty");
-SimpleObjectProperty = Java.type("javafx.beans.property.SimpleObjectProperty");
-SimpleSetProperty = Java.type("javafx.beans.property.SimpleSetProperty");
-SimpleStringProperty = Java.type("javafx.beans.property.SimpleStringProperty");
-StringProperty = Java.type("javafx.beans.property.StringProperty");
-StringPropertyBase = Java.type("javafx.beans.property.StringPropertyBase");
-ChangeListener = Java.type("javafx.beans.value.ChangeListener");
-ObservableBooleanValue = Java.type("javafx.beans.value.ObservableBooleanValue");
-ObservableDoubleValue = Java.type("javafx.beans.value.ObservableDoubleValue");
-ObservableFloatValue = Java.type("javafx.beans.value.ObservableFloatValue");
-ObservableIntegerValue = Java.type("javafx.beans.value.ObservableIntegerValue");
-ObservableListValue = Java.type("javafx.beans.value.ObservableListValue");
-ObservableLongValue = Java.type("javafx.beans.value.ObservableLongValue");
-ObservableMapValue = Java.type("javafx.beans.value.ObservableMapValue");
-ObservableNumberValue = Java.type("javafx.beans.value.ObservableNumberValue");
-ObservableObjectValue = Java.type("javafx.beans.value.ObservableObjectValue");
-ObservableSetValue = Java.type("javafx.beans.value.ObservableSetValue");
-ObservableStringValue = Java.type("javafx.beans.value.ObservableStringValue");
-ObservableValue = Java.type("javafx.beans.value.ObservableValue");
-ObservableValueBase = Java.type("javafx.beans.value.ObservableValueBase");
-WeakChangeListener = Java.type("javafx.beans.value.WeakChangeListener");
-WritableBooleanValue = Java.type("javafx.beans.value.WritableBooleanValue");
-WritableDoubleValue = Java.type("javafx.beans.value.WritableDoubleValue");
-WritableFloatValue = Java.type("javafx.beans.value.WritableFloatValue");
-WritableIntegerValue = Java.type("javafx.beans.value.WritableIntegerValue");
-WritableListValue = Java.type("javafx.beans.value.WritableListValue");
-WritableLongValue = Java.type("javafx.beans.value.WritableLongValue");
-WritableMapValue = Java.type("javafx.beans.value.WritableMapValue");
-WritableNumberValue = Java.type("javafx.beans.value.WritableNumberValue");
-WritableObjectValue = Java.type("javafx.beans.value.WritableObjectValue");
-WritableSetValue = Java.type("javafx.beans.value.WritableSetValue");
-WritableStringValue = Java.type("javafx.beans.value.WritableStringValue");
-WritableValue = Java.type("javafx.beans.value.WritableValue");
-WeakInvalidationListener = Java.type("javafx.beans.WeakInvalidationListener");
-WeakListener = Java.type("javafx.beans.WeakListener");
-FXCollections = Java.type("javafx.collections.FXCollections");
-ListChangeListener = Java.type("javafx.collections.ListChangeListener");
-ListChangeListener$Change = Java.type("javafx.collections.ListChangeListener$Change");
-MapChangeListener = Java.type("javafx.collections.MapChangeListener");
-MapChangeListener$Change = Java.type("javafx.collections.MapChangeListener$Change");
-ModifiableObservableListBase = Java.type("javafx.collections.ModifiableObservableListBase");
-ObservableList = Java.type("javafx.collections.ObservableList");
-ObservableListBase = Java.type("javafx.collections.ObservableListBase");
-ObservableMap = Java.type("javafx.collections.ObservableMap");
-ObservableSet = Java.type("javafx.collections.ObservableSet");
-SetChangeListener = Java.type("javafx.collections.SetChangeListener");
-SetChangeListener$Change = Java.type("javafx.collections.SetChangeListener$Change");
-WeakListChangeListener = Java.type("javafx.collections.WeakListChangeListener");
-WeakMapChangeListener = Java.type("javafx.collections.WeakMapChangeListener");
-WeakSetChangeListener = Java.type("javafx.collections.WeakSetChangeListener");
-ActionEvent = Java.type("javafx.event.ActionEvent");
-Event = Java.type("javafx.event.Event");
-EventDispatchChain = Java.type("javafx.event.EventDispatchChain");
-EventDispatcher = Java.type("javafx.event.EventDispatcher");
-EventHandler = Java.type("javafx.event.EventHandler");
-EventTarget = Java.type("javafx.event.EventTarget");
-EventType = Java.type("javafx.event.EventType");
-WeakEventHandler = Java.type("javafx.event.WeakEventHandler");
-Builder = Java.type("javafx.util.Builder");
-BuilderFactory = Java.type("javafx.util.BuilderFactory");
-Callback = Java.type("javafx.util.Callback");
-BigDecimalStringConverter = Java.type("javafx.util.converter.BigDecimalStringConverter");
-BigIntegerStringConverter = Java.type("javafx.util.converter.BigIntegerStringConverter");
-BooleanStringConverter = Java.type("javafx.util.converter.BooleanStringConverter");
-ByteStringConverter = Java.type("javafx.util.converter.ByteStringConverter");
-CharacterStringConverter = Java.type("javafx.util.converter.CharacterStringConverter");
-CurrencyStringConverter = Java.type("javafx.util.converter.CurrencyStringConverter");
-DateStringConverter = Java.type("javafx.util.converter.DateStringConverter");
-DateTimeStringConverter = Java.type("javafx.util.converter.DateTimeStringConverter");
-DefaultStringConverter = Java.type("javafx.util.converter.DefaultStringConverter");
-DoubleStringConverter = Java.type("javafx.util.converter.DoubleStringConverter");
-FloatStringConverter = Java.type("javafx.util.converter.FloatStringConverter");
-FormatStringConverter = Java.type("javafx.util.converter.FormatStringConverter");
-IntegerStringConverter = Java.type("javafx.util.converter.IntegerStringConverter");
-LongStringConverter = Java.type("javafx.util.converter.LongStringConverter");
-NumberStringConverter = Java.type("javafx.util.converter.NumberStringConverter");
-PercentageStringConverter = Java.type("javafx.util.converter.PercentageStringConverter");
-ShortStringConverter = Java.type("javafx.util.converter.ShortStringConverter");
-TimeStringConverter = Java.type("javafx.util.converter.TimeStringConverter");
-Duration = Java.type("javafx.util.Duration");
-Pair = Java.type("javafx.util.Pair");
-StringConverter = Java.type("javafx.util.StringConverter");
+ switch (cls[1]) {
+ case "stage":
+ if (cls[2] == "Stage") {
+ JFX_BASE_CLASSES.push(cls);
+ } else {
+ JFX_GRAPHICS_CLASSES.push(cls);
+ }
+ break;
+
+ case "scene":
+ switch (cls[2]) {
+ case "Scene":
+ case "Group":
+ JFX_BASE_CLASSES.push(cls);
+ break;
+
+ case "chart":
+ case "control":
+ JFX_CONTROLS_CLASSES.push(cls);
+ break;
+
+ case "web":
+ JFX_WEB_CLASSES.push(cls);
+ break;
+
+ case "media":
+ JFX_MEDIA_CLASSES.push(cls);
+ break;
+
+ default:
+ JFX_GRAPHICS_CLASSES.push(cls);
+ break;
+ }
+ break;
+
+ case "beans":
+ case "collections":
+ case "events":
+ case "util":
+ JFX_BASE_CLASSES.push(cls);
+ break;
+
+ case "animation":
+ case "application":
+ case "concurrent":
+ case "css":
+ case "geometry":
+ JFX_GRAPHICS_CLASSES.push(cls);
+ break;
+
+ case "fxml":
+ JFX_FXML_CLASSES.push(cls);
+ break;
+
+ case "embed":
+ if (cls[2] == "swing") {
+ JFX_SWING_CLASSES.push(cls);
+ } else {
+ JFX_SWT_CLASSES.push(cls);
+ }
+ break;
+ }
+ }
+})();
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/controls.js Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/controls.js Sat Sep 14 20:43:34 2013 +0100
@@ -23,242 +23,8 @@
* questions.
*/
-AreaChart = Java.type("javafx.scene.chart.AreaChart");
-AreaChartBuilder = Java.type("javafx.scene.chart.AreaChartBuilder");
-Axis = Java.type("javafx.scene.chart.Axis");
-Axis$TickMark = Java.type("javafx.scene.chart.Axis$TickMark");
-AxisBuilder = Java.type("javafx.scene.chart.AxisBuilder");
-BarChart = Java.type("javafx.scene.chart.BarChart");
-BarChartBuilder = Java.type("javafx.scene.chart.BarChartBuilder");
-BubbleChart = Java.type("javafx.scene.chart.BubbleChart");
-BubbleChartBuilder = Java.type("javafx.scene.chart.BubbleChartBuilder");
-CategoryAxis = Java.type("javafx.scene.chart.CategoryAxis");
-CategoryAxisBuilder = Java.type("javafx.scene.chart.CategoryAxisBuilder");
-Chart = Java.type("javafx.scene.chart.Chart");
-ChartBuilder = Java.type("javafx.scene.chart.ChartBuilder");
-LineChart = Java.type("javafx.scene.chart.LineChart");
-LineChartBuilder = Java.type("javafx.scene.chart.LineChartBuilder");
-NumberAxis = Java.type("javafx.scene.chart.NumberAxis");
-NumberAxis$DefaultFormatter = Java.type("javafx.scene.chart.NumberAxis$DefaultFormatter");
-NumberAxisBuilder = Java.type("javafx.scene.chart.NumberAxisBuilder");
-PieChart = Java.type("javafx.scene.chart.PieChart");
-PieChart$Data = Java.type("javafx.scene.chart.PieChart$Data");
-PieChartBuilder = Java.type("javafx.scene.chart.PieChartBuilder");
-ScatterChart = Java.type("javafx.scene.chart.ScatterChart");
-ScatterChartBuilder = Java.type("javafx.scene.chart.ScatterChartBuilder");
-StackedAreaChart = Java.type("javafx.scene.chart.StackedAreaChart");
-StackedAreaChartBuilder = Java.type("javafx.scene.chart.StackedAreaChartBuilder");
-StackedBarChart = Java.type("javafx.scene.chart.StackedBarChart");
-StackedBarChartBuilder = Java.type("javafx.scene.chart.StackedBarChartBuilder");
-ValueAxis = Java.type("javafx.scene.chart.ValueAxis");
-ValueAxisBuilder = Java.type("javafx.scene.chart.ValueAxisBuilder");
-XYChart = Java.type("javafx.scene.chart.XYChart");
-XYChart$Data = Java.type("javafx.scene.chart.XYChart$Data");
-XYChart$Series = Java.type("javafx.scene.chart.XYChart$Series");
-XYChartBuilder = Java.type("javafx.scene.chart.XYChartBuilder");
-Accordion = Java.type("javafx.scene.control.Accordion");
-AccordionBuilder = Java.type("javafx.scene.control.AccordionBuilder");
-Button = Java.type("javafx.scene.control.Button");
-ButtonBase = Java.type("javafx.scene.control.ButtonBase");
-ButtonBaseBuilder = Java.type("javafx.scene.control.ButtonBaseBuilder");
-ButtonBuilder = Java.type("javafx.scene.control.ButtonBuilder");
-Cell = Java.type("javafx.scene.control.Cell");
-CheckBoxListCell = Java.type("javafx.scene.control.cell.CheckBoxListCell");
-CheckBoxListCellBuilder = Java.type("javafx.scene.control.cell.CheckBoxListCellBuilder");
-CheckBoxTableCell = Java.type("javafx.scene.control.cell.CheckBoxTableCell");
-CheckBoxTableCellBuilder = Java.type("javafx.scene.control.cell.CheckBoxTableCellBuilder");
-CheckBoxTreeCell = Java.type("javafx.scene.control.cell.CheckBoxTreeCell");
-CheckBoxTreeCellBuilder = Java.type("javafx.scene.control.cell.CheckBoxTreeCellBuilder");
-CheckBoxTreeTableCell = Java.type("javafx.scene.control.cell.CheckBoxTreeTableCell");
-//CheckBoxTreeTableCellBuilder = Java.type("javafx.scene.control.cell.CheckBoxTreeTableCellBuilder");
-ChoiceBoxListCell = Java.type("javafx.scene.control.cell.ChoiceBoxListCell");
-ChoiceBoxListCellBuilder = Java.type("javafx.scene.control.cell.ChoiceBoxListCellBuilder");
-ChoiceBoxTableCell = Java.type("javafx.scene.control.cell.ChoiceBoxTableCell");
-ChoiceBoxTableCellBuilder = Java.type("javafx.scene.control.cell.ChoiceBoxTableCellBuilder");
-ChoiceBoxTreeCell = Java.type("javafx.scene.control.cell.ChoiceBoxTreeCell");
-ChoiceBoxTreeCellBuilder = Java.type("javafx.scene.control.cell.ChoiceBoxTreeCellBuilder");
-ChoiceBoxTreeTableCell = Java.type("javafx.scene.control.cell.ChoiceBoxTreeTableCell");
-//ChoiceBoxTreeTableCellBuilder = Java.type("javafx.scene.control.cell.ChoiceBoxTreeTableCellBuilder");
-ComboBoxListCell = Java.type("javafx.scene.control.cell.ComboBoxListCell");
-ComboBoxListCellBuilder = Java.type("javafx.scene.control.cell.ComboBoxListCellBuilder");
-ComboBoxTableCell = Java.type("javafx.scene.control.cell.ComboBoxTableCell");
-ComboBoxTableCellBuilder = Java.type("javafx.scene.control.cell.ComboBoxTableCellBuilder");
-ComboBoxTreeCell = Java.type("javafx.scene.control.cell.ComboBoxTreeCell");
-ComboBoxTreeCellBuilder = Java.type("javafx.scene.control.cell.ComboBoxTreeCellBuilder");
-ComboBoxTreeTableCell = Java.type("javafx.scene.control.cell.ComboBoxTreeTableCell");
-//ComboBoxTreeTableCellBuilder = Java.type("javafx.scene.control.cell.ComboBoxTreeTableCellBuilder");
-MapValueFactory = Java.type("javafx.scene.control.cell.MapValueFactory");
-ProgressBarTableCell = Java.type("javafx.scene.control.cell.ProgressBarTableCell");
-ProgressBarTreeTableCell = Java.type("javafx.scene.control.cell.ProgressBarTreeTableCell");
-PropertyValueFactory = Java.type("javafx.scene.control.cell.PropertyValueFactory");
-PropertyValueFactoryBuilder = Java.type("javafx.scene.control.cell.PropertyValueFactoryBuilder");
-TextFieldListCell = Java.type("javafx.scene.control.cell.TextFieldListCell");
-TextFieldListCellBuilder = Java.type("javafx.scene.control.cell.TextFieldListCellBuilder");
-TextFieldTableCell = Java.type("javafx.scene.control.cell.TextFieldTableCell");
-TextFieldTableCellBuilder = Java.type("javafx.scene.control.cell.TextFieldTableCellBuilder");
-TextFieldTreeCell = Java.type("javafx.scene.control.cell.TextFieldTreeCell");
-TextFieldTreeCellBuilder = Java.type("javafx.scene.control.cell.TextFieldTreeCellBuilder");
-TextFieldTreeTableCell = Java.type("javafx.scene.control.cell.TextFieldTreeTableCell");
-//TextFieldTreeTableCellBuilder = Java.type("javafx.scene.control.cell.TextFieldTreeTableCellBuilder");
-TreeItemPropertyValueFactory = Java.type("javafx.scene.control.cell.TreeItemPropertyValueFactory");
-//TreeItemPropertyValueFactoryBuilder = Java.type("javafx.scene.control.cell.TreeItemPropertyValueFactoryBuilder");
-CellBuilder = Java.type("javafx.scene.control.CellBuilder");
-CheckBox = Java.type("javafx.scene.control.CheckBox");
-CheckBoxBuilder = Java.type("javafx.scene.control.CheckBoxBuilder");
-CheckBoxTreeItem = Java.type("javafx.scene.control.CheckBoxTreeItem");
-CheckBoxTreeItem$TreeModificationEvent = Java.type("javafx.scene.control.CheckBoxTreeItem$TreeModificationEvent");
-CheckBoxTreeItemBuilder = Java.type("javafx.scene.control.CheckBoxTreeItemBuilder");
-CheckMenuItem = Java.type("javafx.scene.control.CheckMenuItem");
-CheckMenuItemBuilder = Java.type("javafx.scene.control.CheckMenuItemBuilder");
-ChoiceBox = Java.type("javafx.scene.control.ChoiceBox");
-ChoiceBoxBuilder = Java.type("javafx.scene.control.ChoiceBoxBuilder");
-ColorPicker = Java.type("javafx.scene.control.ColorPicker");
-ColorPickerBuilder = Java.type("javafx.scene.control.ColorPickerBuilder");
-ComboBox = Java.type("javafx.scene.control.ComboBox");
-ComboBoxBase = Java.type("javafx.scene.control.ComboBoxBase");
-ComboBoxBaseBuilder = Java.type("javafx.scene.control.ComboBoxBaseBuilder");
-ComboBoxBuilder = Java.type("javafx.scene.control.ComboBoxBuilder");
-ContentDisplay = Java.type("javafx.scene.control.ContentDisplay");
-ContextMenu = Java.type("javafx.scene.control.ContextMenu");
-ContextMenuBuilder = Java.type("javafx.scene.control.ContextMenuBuilder");
-Control = Java.type("javafx.scene.control.Control");
-ControlBuilder = Java.type("javafx.scene.control.ControlBuilder");
-CustomMenuItem = Java.type("javafx.scene.control.CustomMenuItem");
-CustomMenuItemBuilder = Java.type("javafx.scene.control.CustomMenuItemBuilder");
-FocusModel = Java.type("javafx.scene.control.FocusModel");
-Hyperlink = Java.type("javafx.scene.control.Hyperlink");
-HyperlinkBuilder = Java.type("javafx.scene.control.HyperlinkBuilder");
-IndexedCell = Java.type("javafx.scene.control.IndexedCell");
-IndexedCellBuilder = Java.type("javafx.scene.control.IndexedCellBuilder");
-IndexRange = Java.type("javafx.scene.control.IndexRange");
-IndexRangeBuilder = Java.type("javafx.scene.control.IndexRangeBuilder");
-Label = Java.type("javafx.scene.control.Label");
-LabelBuilder = Java.type("javafx.scene.control.LabelBuilder");
-Labeled = Java.type("javafx.scene.control.Labeled");
-LabeledBuilder = Java.type("javafx.scene.control.LabeledBuilder");
-ListCell = Java.type("javafx.scene.control.ListCell");
-ListCellBuilder = Java.type("javafx.scene.control.ListCellBuilder");
-ListView = Java.type("javafx.scene.control.ListView");
-ListView$EditEvent = Java.type("javafx.scene.control.ListView$EditEvent");
-ListViewBuilder = Java.type("javafx.scene.control.ListViewBuilder");
-Menu = Java.type("javafx.scene.control.Menu");
-MenuBar = Java.type("javafx.scene.control.MenuBar");
-MenuBarBuilder = Java.type("javafx.scene.control.MenuBarBuilder");
-MenuBuilder = Java.type("javafx.scene.control.MenuBuilder");
-MenuButton = Java.type("javafx.scene.control.MenuButton");
-MenuButtonBuilder = Java.type("javafx.scene.control.MenuButtonBuilder");
-MenuItem = Java.type("javafx.scene.control.MenuItem");
-MenuItemBuilder = Java.type("javafx.scene.control.MenuItemBuilder");
-MultipleSelectionModel = Java.type("javafx.scene.control.MultipleSelectionModel");
-MultipleSelectionModelBuilder = Java.type("javafx.scene.control.MultipleSelectionModelBuilder");
-OverrunStyle = Java.type("javafx.scene.control.OverrunStyle");
-Pagination = Java.type("javafx.scene.control.Pagination");
-PaginationBuilder = Java.type("javafx.scene.control.PaginationBuilder");
-PasswordField = Java.type("javafx.scene.control.PasswordField");
-PasswordFieldBuilder = Java.type("javafx.scene.control.PasswordFieldBuilder");
-PopupControl = Java.type("javafx.scene.control.PopupControl");
-PopupControlBuilder = Java.type("javafx.scene.control.PopupControlBuilder");
-ProgressBar = Java.type("javafx.scene.control.ProgressBar");
-ProgressBarBuilder = Java.type("javafx.scene.control.ProgressBarBuilder");
-ProgressIndicator = Java.type("javafx.scene.control.ProgressIndicator");
-ProgressIndicatorBuilder = Java.type("javafx.scene.control.ProgressIndicatorBuilder");
-RadioButton = Java.type("javafx.scene.control.RadioButton");
-RadioButtonBuilder = Java.type("javafx.scene.control.RadioButtonBuilder");
-RadioMenuItem = Java.type("javafx.scene.control.RadioMenuItem");
-RadioMenuItemBuilder = Java.type("javafx.scene.control.RadioMenuItemBuilder");
-ResizeFeaturesBase = Java.type("javafx.scene.control.ResizeFeaturesBase");
-//ResizeFeaturesBaseBuilder = Java.type("javafx.scene.control.ResizeFeaturesBaseBuilder");
-ScrollBar = Java.type("javafx.scene.control.ScrollBar");
-ScrollBarBuilder = Java.type("javafx.scene.control.ScrollBarBuilder");
-ScrollPane = Java.type("javafx.scene.control.ScrollPane");
-ScrollPane$ScrollBarPolicy = Java.type("javafx.scene.control.ScrollPane$ScrollBarPolicy");
-ScrollPaneBuilder = Java.type("javafx.scene.control.ScrollPaneBuilder");
-ScrollToEvent = Java.type("javafx.scene.control.ScrollToEvent");
-SelectionMode = Java.type("javafx.scene.control.SelectionMode");
-SelectionModel = Java.type("javafx.scene.control.SelectionModel");
-Separator = Java.type("javafx.scene.control.Separator");
-SeparatorBuilder = Java.type("javafx.scene.control.SeparatorBuilder");
-SeparatorMenuItem = Java.type("javafx.scene.control.SeparatorMenuItem");
-SeparatorMenuItemBuilder = Java.type("javafx.scene.control.SeparatorMenuItemBuilder");
-SingleSelectionModel = Java.type("javafx.scene.control.SingleSelectionModel");
-Skin = Java.type("javafx.scene.control.Skin");
-SkinBase = Java.type("javafx.scene.control.SkinBase");
-//SkinBaseBuilder = Java.type("javafx.scene.control.SkinBaseBuilder");
-Skinnable = Java.type("javafx.scene.control.Skinnable");
-Slider = Java.type("javafx.scene.control.Slider");
-SliderBuilder = Java.type("javafx.scene.control.SliderBuilder");
-SortEvent = Java.type("javafx.scene.control.SortEvent");
-SplitMenuButton = Java.type("javafx.scene.control.SplitMenuButton");
-SplitMenuButtonBuilder = Java.type("javafx.scene.control.SplitMenuButtonBuilder");
-SplitPane = Java.type("javafx.scene.control.SplitPane");
-SplitPane$Divider = Java.type("javafx.scene.control.SplitPane$Divider");
-SplitPaneBuilder = Java.type("javafx.scene.control.SplitPaneBuilder");
-Tab = Java.type("javafx.scene.control.Tab");
-TabBuilder = Java.type("javafx.scene.control.TabBuilder");
-TableCell = Java.type("javafx.scene.control.TableCell");
-TableCellBuilder = Java.type("javafx.scene.control.TableCellBuilder");
-TableColumn = Java.type("javafx.scene.control.TableColumn");
-TableColumn$CellDataFeatures = Java.type("javafx.scene.control.TableColumn$CellDataFeatures");
-TableColumn$CellEditEvent = Java.type("javafx.scene.control.TableColumn$CellEditEvent");
-TableColumn$SortType = Java.type("javafx.scene.control.TableColumn$SortType");
-TableColumnBase = Java.type("javafx.scene.control.TableColumnBase");
-//TableColumnBaseBuilder = Java.type("javafx.scene.control.TableColumnBaseBuilder");
-TableColumnBuilder = Java.type("javafx.scene.control.TableColumnBuilder");
-TableFocusModel = Java.type("javafx.scene.control.TableFocusModel");
-TablePosition = Java.type("javafx.scene.control.TablePosition");
-TablePositionBase = Java.type("javafx.scene.control.TablePositionBase");
-TableRow = Java.type("javafx.scene.control.TableRow");
-TableRowBuilder = Java.type("javafx.scene.control.TableRowBuilder");
-TableSelectionModel = Java.type("javafx.scene.control.TableSelectionModel");
-//TableSelectionModelBuilder = Java.type("javafx.scene.control.TableSelectionModelBuilder");
-TableView = Java.type("javafx.scene.control.TableView");
-TableView$ResizeFeatures = Java.type("javafx.scene.control.TableView$ResizeFeatures");
-TableView$TableViewFocusModel = Java.type("javafx.scene.control.TableView$TableViewFocusModel");
-TableView$TableViewSelectionModel = Java.type("javafx.scene.control.TableView$TableViewSelectionModel");
-TableViewBuilder = Java.type("javafx.scene.control.TableViewBuilder");
-TabPane = Java.type("javafx.scene.control.TabPane");
-TabPane$TabClosingPolicy = Java.type("javafx.scene.control.TabPane$TabClosingPolicy");
-TabPaneBuilder = Java.type("javafx.scene.control.TabPaneBuilder");
-TextArea = Java.type("javafx.scene.control.TextArea");
-TextAreaBuilder = Java.type("javafx.scene.control.TextAreaBuilder");
-TextField = Java.type("javafx.scene.control.TextField");
-TextFieldBuilder = Java.type("javafx.scene.control.TextFieldBuilder");
-TextInputControl = Java.type("javafx.scene.control.TextInputControl");
-TextInputControl$Content = Java.type("javafx.scene.control.TextInputControl$Content");
-TextInputControlBuilder = Java.type("javafx.scene.control.TextInputControlBuilder");
-TitledPane = Java.type("javafx.scene.control.TitledPane");
-TitledPaneBuilder = Java.type("javafx.scene.control.TitledPaneBuilder");
-Toggle = Java.type("javafx.scene.control.Toggle");
-ToggleButton = Java.type("javafx.scene.control.ToggleButton");
-ToggleButtonBuilder = Java.type("javafx.scene.control.ToggleButtonBuilder");
-ToggleGroup = Java.type("javafx.scene.control.ToggleGroup");
-ToggleGroupBuilder = Java.type("javafx.scene.control.ToggleGroupBuilder");
-ToolBar = Java.type("javafx.scene.control.ToolBar");
-ToolBarBuilder = Java.type("javafx.scene.control.ToolBarBuilder");
-Tooltip = Java.type("javafx.scene.control.Tooltip");
-TooltipBuilder = Java.type("javafx.scene.control.TooltipBuilder");
-TreeCell = Java.type("javafx.scene.control.TreeCell");
-TreeCellBuilder = Java.type("javafx.scene.control.TreeCellBuilder");
-TreeItem = Java.type("javafx.scene.control.TreeItem");
-TreeItem$TreeModificationEvent = Java.type("javafx.scene.control.TreeItem$TreeModificationEvent");
-TreeItemBuilder = Java.type("javafx.scene.control.TreeItemBuilder");
-TreeSortMode = Java.type("javafx.scene.control.TreeSortMode");
-TreeTableCell = Java.type("javafx.scene.control.TreeTableCell");
-//TreeTableCellBuilder = Java.type("javafx.scene.control.TreeTableCellBuilder");
-TreeTableColumn = Java.type("javafx.scene.control.TreeTableColumn");
-TreeTableColumn$CellDataFeatures = Java.type("javafx.scene.control.TreeTableColumn$CellDataFeatures");
-TreeTableColumn$CellEditEvent = Java.type("javafx.scene.control.TreeTableColumn$CellEditEvent");
-TreeTableColumn$SortType = Java.type("javafx.scene.control.TreeTableColumn$SortType");
-//TreeTableColumnBuilder = Java.type("javafx.scene.control.TreeTableColumnBuilder");
-TreeTablePosition = Java.type("javafx.scene.control.TreeTablePosition");
-TreeTableRow = Java.type("javafx.scene.control.TreeTableRow");
-//TreeTableRowBuilder = Java.type("javafx.scene.control.TreeTableRowBuilder");
-TreeTableView = Java.type("javafx.scene.control.TreeTableView");
-TreeTableView$EditEvent = Java.type("javafx.scene.control.TreeTableView$EditEvent");
-TreeTableView$ResizeFeatures = Java.type("javafx.scene.control.TreeTableView$ResizeFeatures");
-TreeTableView$TreeTableViewFocusModel = Java.type("javafx.scene.control.TreeTableView$TreeTableViewFocusModel");
-TreeTableView$TreeTableViewSelectionModel = Java.type("javafx.scene.control.TreeTableView$TreeTableViewSelectionModel");
-//TreeTableViewBuilder = Java.type("javafx.scene.control.TreeTableViewBuilder");
-TreeView = Java.type("javafx.scene.control.TreeView");
-TreeView$EditEvent = Java.type("javafx.scene.control.TreeView$EditEvent");
-TreeViewBuilder = Java.type("javafx.scene.control.TreeViewBuilder");
+if (!this.JFX_BASE_CLASSES) {
+ load("fx:base.js")
+}
+
+LOAD_FX_CLASSES(JFX_CONTROLS_CLASSES);
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/fxml.js Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/fxml.js Sat Sep 14 20:43:34 2013 +0100
@@ -23,8 +23,8 @@
* questions.
*/
-FXML = Java.type("javafx.fxml.FXML");
-FXMLLoader = Java.type("javafx.fxml.FXMLLoader");
-Initializable = Java.type("javafx.fxml.Initializable");
-JavaFXBuilderFactory = Java.type("javafx.fxml.JavaFXBuilderFactory");
-LoadException = Java.type("javafx.fxml.LoadException");
+if (!this.JFX_BASE_CLASSES) {
+ load("fx:base.js")
+}
+
+LOAD_FX_CLASSES(JFX_FXML_CLASSES);
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/graphics.js Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/graphics.js Sat Sep 14 20:43:34 2013 +0100
@@ -23,409 +23,10 @@
* questions.
*/
-Animation = Java.type("javafx.animation.Animation");
-Animation$Status = Java.type("javafx.animation.Animation$Status");
-AnimationBuilder = Java.type("javafx.animation.AnimationBuilder");
-AnimationTimer = Java.type("javafx.animation.AnimationTimer");
-FadeTransition = Java.type("javafx.animation.FadeTransition");
-FadeTransitionBuilder = Java.type("javafx.animation.FadeTransitionBuilder");
-FillTransition = Java.type("javafx.animation.FillTransition");
-FillTransitionBuilder = Java.type("javafx.animation.FillTransitionBuilder");
-Interpolatable = Java.type("javafx.animation.Interpolatable");
-Interpolator = Java.type("javafx.animation.Interpolator");
-KeyFrame = Java.type("javafx.animation.KeyFrame");
-KeyValue = Java.type("javafx.animation.KeyValue");
-ParallelTransition = Java.type("javafx.animation.ParallelTransition");
-ParallelTransitionBuilder = Java.type("javafx.animation.ParallelTransitionBuilder");
-PathTransition = Java.type("javafx.animation.PathTransition");
-PathTransition$OrientationType = Java.type("javafx.animation.PathTransition$OrientationType");
-PathTransitionBuilder = Java.type("javafx.animation.PathTransitionBuilder");
-PauseTransition = Java.type("javafx.animation.PauseTransition");
-PauseTransitionBuilder = Java.type("javafx.animation.PauseTransitionBuilder");
-RotateTransition = Java.type("javafx.animation.RotateTransition");
-RotateTransitionBuilder = Java.type("javafx.animation.RotateTransitionBuilder");
-ScaleTransition = Java.type("javafx.animation.ScaleTransition");
-ScaleTransitionBuilder = Java.type("javafx.animation.ScaleTransitionBuilder");
-SequentialTransition = Java.type("javafx.animation.SequentialTransition");
-SequentialTransitionBuilder = Java.type("javafx.animation.SequentialTransitionBuilder");
-StrokeTransition = Java.type("javafx.animation.StrokeTransition");
-StrokeTransitionBuilder = Java.type("javafx.animation.StrokeTransitionBuilder");
-Timeline = Java.type("javafx.animation.Timeline");
-TimelineBuilder = Java.type("javafx.animation.TimelineBuilder");
-Transition = Java.type("javafx.animation.Transition");
-TransitionBuilder = Java.type("javafx.animation.TransitionBuilder");
-TranslateTransition = Java.type("javafx.animation.TranslateTransition");
-TranslateTransitionBuilder = Java.type("javafx.animation.TranslateTransitionBuilder");
-Application = Java.type("javafx.application.Application");
-Application$Parameters = Java.type("javafx.application.Application$Parameters");
-ConditionalFeature = Java.type("javafx.application.ConditionalFeature");
-HostServices = Java.type("javafx.application.HostServices");
-Platform = Java.type("javafx.application.Platform");
-Preloader = Java.type("javafx.application.Preloader");
-Preloader$ErrorNotification = Java.type("javafx.application.Preloader$ErrorNotification");
-Preloader$PreloaderNotification = Java.type("javafx.application.Preloader$PreloaderNotification");
-Preloader$ProgressNotification = Java.type("javafx.application.Preloader$ProgressNotification");
-Preloader$StateChangeNotification = Java.type("javafx.application.Preloader$StateChangeNotification");
-Preloader$StateChangeNotification$Type = Java.type("javafx.application.Preloader$StateChangeNotification$Type");
-ScheduledService = Java.type("javafx.concurrent.ScheduledService");
-Service = Java.type("javafx.concurrent.Service");
-Task = Java.type("javafx.concurrent.Task");
-Worker = Java.type("javafx.concurrent.Worker");
-Worker$State = Java.type("javafx.concurrent.Worker$State");
-WorkerStateEvent = Java.type("javafx.concurrent.WorkerStateEvent");
-CssMetaData = Java.type("javafx.css.CssMetaData");
-FontCssMetaData = Java.type("javafx.css.FontCssMetaData");
-ParsedValue = Java.type("javafx.css.ParsedValue");
-PseudoClass = Java.type("javafx.css.PseudoClass");
-SimpleStyleableBooleanProperty = Java.type("javafx.css.SimpleStyleableBooleanProperty");
-SimpleStyleableDoubleProperty = Java.type("javafx.css.SimpleStyleableDoubleProperty");
-SimpleStyleableFloatProperty = Java.type("javafx.css.SimpleStyleableFloatProperty");
-SimpleStyleableIntegerProperty = Java.type("javafx.css.SimpleStyleableIntegerProperty");
-SimpleStyleableLongProperty = Java.type("javafx.css.SimpleStyleableLongProperty");
-SimpleStyleableObjectProperty = Java.type("javafx.css.SimpleStyleableObjectProperty");
-SimpleStyleableStringProperty = Java.type("javafx.css.SimpleStyleableStringProperty");
-Styleable = Java.type("javafx.css.Styleable");
-StyleableBooleanProperty = Java.type("javafx.css.StyleableBooleanProperty");
-StyleableDoubleProperty = Java.type("javafx.css.StyleableDoubleProperty");
-StyleableFloatProperty = Java.type("javafx.css.StyleableFloatProperty");
-StyleableIntegerProperty = Java.type("javafx.css.StyleableIntegerProperty");
-StyleableLongProperty = Java.type("javafx.css.StyleableLongProperty");
-StyleableObjectProperty = Java.type("javafx.css.StyleableObjectProperty");
-StyleableProperty = Java.type("javafx.css.StyleableProperty");
-StyleableStringProperty = Java.type("javafx.css.StyleableStringProperty");
-StyleConverter = Java.type("javafx.css.StyleConverter");
-StyleOrigin = Java.type("javafx.css.StyleOrigin");
-BoundingBox = Java.type("javafx.geometry.BoundingBox");
-BoundingBoxBuilder = Java.type("javafx.geometry.BoundingBoxBuilder");
-Bounds = Java.type("javafx.geometry.Bounds");
-Dimension2D = Java.type("javafx.geometry.Dimension2D");
-Dimension2DBuilder = Java.type("javafx.geometry.Dimension2DBuilder");
-HorizontalDirection = Java.type("javafx.geometry.HorizontalDirection");
-HPos = Java.type("javafx.geometry.HPos");
-Insets = Java.type("javafx.geometry.Insets");
-InsetsBuilder = Java.type("javafx.geometry.InsetsBuilder");
-NodeOrientation = Java.type("javafx.geometry.NodeOrientation");
-Orientation = Java.type("javafx.geometry.Orientation");
-Point2D = Java.type("javafx.geometry.Point2D");
-Point2DBuilder = Java.type("javafx.geometry.Point2DBuilder");
-Point3D = Java.type("javafx.geometry.Point3D");
-Point3DBuilder = Java.type("javafx.geometry.Point3DBuilder");
-Pos = Java.type("javafx.geometry.Pos");
-Rectangle2D = Java.type("javafx.geometry.Rectangle2D");
-Rectangle2DBuilder = Java.type("javafx.geometry.Rectangle2DBuilder");
-Side = Java.type("javafx.geometry.Side");
-VerticalDirection = Java.type("javafx.geometry.VerticalDirection");
-VPos = Java.type("javafx.geometry.VPos");
-Collation = Java.type("javafx.print.Collation");
-JobSettings = Java.type("javafx.print.JobSettings");
-PageLayout = Java.type("javafx.print.PageLayout");
-PageOrientation = Java.type("javafx.print.PageOrientation");
-PageRange = Java.type("javafx.print.PageRange");
-Paper = Java.type("javafx.print.Paper");
-Paper$Units = Java.type("javafx.print.Paper$Units");
-PaperSource = Java.type("javafx.print.PaperSource");
-PrintColor = Java.type("javafx.print.PrintColor");
-Printer = Java.type("javafx.print.Printer");
-Printer$MarginType = Java.type("javafx.print.Printer$MarginType");
-PrinterAttributes = Java.type("javafx.print.PrinterAttributes");
-PrinterJob = Java.type("javafx.print.PrinterJob");
-PrinterJob$JobStatus = Java.type("javafx.print.PrinterJob$JobStatus");
-PrintQuality = Java.type("javafx.print.PrintQuality");
-PrintResolution = Java.type("javafx.print.PrintResolution");
-PrintSides = Java.type("javafx.print.PrintSides");
-AmbientLight = Java.type("javafx.scene.AmbientLight");
-//AmbientLightBuilder = Java.type("javafx.scene.AmbientLightBuilder");
-CacheHint = Java.type("javafx.scene.CacheHint");
-Camera = Java.type("javafx.scene.Camera");
-//CameraBuilder = Java.type("javafx.scene.CameraBuilder");
-Canvas = Java.type("javafx.scene.canvas.Canvas");
-CanvasBuilder = Java.type("javafx.scene.canvas.CanvasBuilder");
-GraphicsContext = Java.type("javafx.scene.canvas.GraphicsContext");
-Cursor = Java.type("javafx.scene.Cursor");
-DepthTest = Java.type("javafx.scene.DepthTest");
-Blend = Java.type("javafx.scene.effect.Blend");
-BlendBuilder = Java.type("javafx.scene.effect.BlendBuilder");
-BlendMode = Java.type("javafx.scene.effect.BlendMode");
-Bloom = Java.type("javafx.scene.effect.Bloom");
-BloomBuilder = Java.type("javafx.scene.effect.BloomBuilder");
-BlurType = Java.type("javafx.scene.effect.BlurType");
-BoxBlur = Java.type("javafx.scene.effect.BoxBlur");
-BoxBlurBuilder = Java.type("javafx.scene.effect.BoxBlurBuilder");
-ColorAdjust = Java.type("javafx.scene.effect.ColorAdjust");
-ColorAdjustBuilder = Java.type("javafx.scene.effect.ColorAdjustBuilder");
-ColorInput = Java.type("javafx.scene.effect.ColorInput");
-ColorInputBuilder = Java.type("javafx.scene.effect.ColorInputBuilder");
-DisplacementMap = Java.type("javafx.scene.effect.DisplacementMap");
-DisplacementMapBuilder = Java.type("javafx.scene.effect.DisplacementMapBuilder");
-DropShadow = Java.type("javafx.scene.effect.DropShadow");
-DropShadowBuilder = Java.type("javafx.scene.effect.DropShadowBuilder");
-Effect = Java.type("javafx.scene.effect.Effect");
-FloatMap = Java.type("javafx.scene.effect.FloatMap");
-FloatMapBuilder = Java.type("javafx.scene.effect.FloatMapBuilder");
-GaussianBlur = Java.type("javafx.scene.effect.GaussianBlur");
-GaussianBlurBuilder = Java.type("javafx.scene.effect.GaussianBlurBuilder");
-Glow = Java.type("javafx.scene.effect.Glow");
-GlowBuilder = Java.type("javafx.scene.effect.GlowBuilder");
-ImageInput = Java.type("javafx.scene.effect.ImageInput");
-ImageInputBuilder = Java.type("javafx.scene.effect.ImageInputBuilder");
-InnerShadow = Java.type("javafx.scene.effect.InnerShadow");
-InnerShadowBuilder = Java.type("javafx.scene.effect.InnerShadowBuilder");
-Light = Java.type("javafx.scene.effect.Light");
-Light$Distant = Java.type("javafx.scene.effect.Light$Distant");
-Light$Point = Java.type("javafx.scene.effect.Light$Point");
-Light$Spot = Java.type("javafx.scene.effect.Light$Spot");
-LightBuilder = Java.type("javafx.scene.effect.LightBuilder");
-Lighting = Java.type("javafx.scene.effect.Lighting");
-LightingBuilder = Java.type("javafx.scene.effect.LightingBuilder");
-MotionBlur = Java.type("javafx.scene.effect.MotionBlur");
-MotionBlurBuilder = Java.type("javafx.scene.effect.MotionBlurBuilder");
-PerspectiveTransform = Java.type("javafx.scene.effect.PerspectiveTransform");
-PerspectiveTransformBuilder = Java.type("javafx.scene.effect.PerspectiveTransformBuilder");
-Reflection = Java.type("javafx.scene.effect.Reflection");
-ReflectionBuilder = Java.type("javafx.scene.effect.ReflectionBuilder");
-SepiaTone = Java.type("javafx.scene.effect.SepiaTone");
-SepiaToneBuilder = Java.type("javafx.scene.effect.SepiaToneBuilder");
-Shadow = Java.type("javafx.scene.effect.Shadow");
-ShadowBuilder = Java.type("javafx.scene.effect.ShadowBuilder");
-//Group = Java.type("javafx.scene.Group");
-GroupBuilder = Java.type("javafx.scene.GroupBuilder");
-Image = Java.type("javafx.scene.image.Image");
-ImageView = Java.type("javafx.scene.image.ImageView");
-ImageViewBuilder = Java.type("javafx.scene.image.ImageViewBuilder");
-PixelFormat = Java.type("javafx.scene.image.PixelFormat");
-PixelFormat$Type = Java.type("javafx.scene.image.PixelFormat$Type");
-PixelReader = Java.type("javafx.scene.image.PixelReader");
-PixelWriter = Java.type("javafx.scene.image.PixelWriter");
-WritableImage = Java.type("javafx.scene.image.WritableImage");
-WritablePixelFormat = Java.type("javafx.scene.image.WritablePixelFormat");
-ImageCursor = Java.type("javafx.scene.ImageCursor");
-ImageCursorBuilder = Java.type("javafx.scene.ImageCursorBuilder");
-Clipboard = Java.type("javafx.scene.input.Clipboard");
-ClipboardContent = Java.type("javafx.scene.input.ClipboardContent");
-ClipboardContentBuilder = Java.type("javafx.scene.input.ClipboardContentBuilder");
-ContextMenuEvent = Java.type("javafx.scene.input.ContextMenuEvent");
-DataFormat = Java.type("javafx.scene.input.DataFormat");
-Dragboard = Java.type("javafx.scene.input.Dragboard");
-DragEvent = Java.type("javafx.scene.input.DragEvent");
-GestureEvent = Java.type("javafx.scene.input.GestureEvent");
-InputEvent = Java.type("javafx.scene.input.InputEvent");
-//InputEventBuilder = Java.type("javafx.scene.input.InputEventBuilder");
-InputMethodEvent = Java.type("javafx.scene.input.InputMethodEvent");
-InputMethodHighlight = Java.type("javafx.scene.input.InputMethodHighlight");
-InputMethodRequests = Java.type("javafx.scene.input.InputMethodRequests");
-InputMethodTextRun = Java.type("javafx.scene.input.InputMethodTextRun");
-//InputMethodTextRunBuilder = Java.type("javafx.scene.input.InputMethodTextRunBuilder");
-KeyCharacterCombination = Java.type("javafx.scene.input.KeyCharacterCombination");
-KeyCharacterCombinationBuilder = Java.type("javafx.scene.input.KeyCharacterCombinationBuilder");
-KeyCode = Java.type("javafx.scene.input.KeyCode");
-KeyCodeCombination = Java.type("javafx.scene.input.KeyCodeCombination");
-KeyCodeCombinationBuilder = Java.type("javafx.scene.input.KeyCodeCombinationBuilder");
-KeyCombination = Java.type("javafx.scene.input.KeyCombination");
-KeyCombination$Modifier = Java.type("javafx.scene.input.KeyCombination$Modifier");
-KeyCombination$ModifierValue = Java.type("javafx.scene.input.KeyCombination$ModifierValue");
-KeyEvent = Java.type("javafx.scene.input.KeyEvent");
-Mnemonic = Java.type("javafx.scene.input.Mnemonic");
-MnemonicBuilder = Java.type("javafx.scene.input.MnemonicBuilder");
-MouseButton = Java.type("javafx.scene.input.MouseButton");
-MouseDragEvent = Java.type("javafx.scene.input.MouseDragEvent");
-MouseEvent = Java.type("javafx.scene.input.MouseEvent");
-PickResult = Java.type("javafx.scene.input.PickResult");
-RotateEvent = Java.type("javafx.scene.input.RotateEvent");
-ScrollEvent = Java.type("javafx.scene.input.ScrollEvent");
-ScrollEvent$HorizontalTextScrollUnits = Java.type("javafx.scene.input.ScrollEvent$HorizontalTextScrollUnits");
-ScrollEvent$VerticalTextScrollUnits = Java.type("javafx.scene.input.ScrollEvent$VerticalTextScrollUnits");
-SwipeEvent = Java.type("javafx.scene.input.SwipeEvent");
-TouchEvent = Java.type("javafx.scene.input.TouchEvent");
-TouchPoint = Java.type("javafx.scene.input.TouchPoint");
-TouchPoint$State = Java.type("javafx.scene.input.TouchPoint$State");
-//TouchPointBuilder = Java.type("javafx.scene.input.TouchPointBuilder");
-TransferMode = Java.type("javafx.scene.input.TransferMode");
-ZoomEvent = Java.type("javafx.scene.input.ZoomEvent");
-AnchorPane = Java.type("javafx.scene.layout.AnchorPane");
-AnchorPaneBuilder = Java.type("javafx.scene.layout.AnchorPaneBuilder");
-Background = Java.type("javafx.scene.layout.Background");
-//BackgroundBuilder = Java.type("javafx.scene.layout.BackgroundBuilder");
-BackgroundFill = Java.type("javafx.scene.layout.BackgroundFill");
-//BackgroundFillBuilder = Java.type("javafx.scene.layout.BackgroundFillBuilder");
-BackgroundImage = Java.type("javafx.scene.layout.BackgroundImage");
-//BackgroundImageBuilder = Java.type("javafx.scene.layout.BackgroundImageBuilder");
-BackgroundPosition = Java.type("javafx.scene.layout.BackgroundPosition");
-//BackgroundPositionBuilder = Java.type("javafx.scene.layout.BackgroundPositionBuilder");
-BackgroundRepeat = Java.type("javafx.scene.layout.BackgroundRepeat");
-BackgroundSize = Java.type("javafx.scene.layout.BackgroundSize");
-//BackgroundSizeBuilder = Java.type("javafx.scene.layout.BackgroundSizeBuilder");
-Border = Java.type("javafx.scene.layout.Border");
-//BorderBuilder = Java.type("javafx.scene.layout.BorderBuilder");
-BorderImage = Java.type("javafx.scene.layout.BorderImage");
-//BorderImageBuilder = Java.type("javafx.scene.layout.BorderImageBuilder");
-BorderPane = Java.type("javafx.scene.layout.BorderPane");
-BorderPaneBuilder = Java.type("javafx.scene.layout.BorderPaneBuilder");
-BorderRepeat = Java.type("javafx.scene.layout.BorderRepeat");
-BorderStroke = Java.type("javafx.scene.layout.BorderStroke");
-//BorderStrokeBuilder = Java.type("javafx.scene.layout.BorderStrokeBuilder");
-BorderStrokeStyle = Java.type("javafx.scene.layout.BorderStrokeStyle");
-//BorderStrokeStyleBuilder = Java.type("javafx.scene.layout.BorderStrokeStyleBuilder");
-BorderWidths = Java.type("javafx.scene.layout.BorderWidths");
-//BorderWidthsBuilder = Java.type("javafx.scene.layout.BorderWidthsBuilder");
-ColumnConstraints = Java.type("javafx.scene.layout.ColumnConstraints");
-ColumnConstraintsBuilder = Java.type("javafx.scene.layout.ColumnConstraintsBuilder");
-ConstraintsBase = Java.type("javafx.scene.layout.ConstraintsBase");
-CornerRadii = Java.type("javafx.scene.layout.CornerRadii");
-FlowPane = Java.type("javafx.scene.layout.FlowPane");
-FlowPaneBuilder = Java.type("javafx.scene.layout.FlowPaneBuilder");
-GridPane = Java.type("javafx.scene.layout.GridPane");
-GridPaneBuilder = Java.type("javafx.scene.layout.GridPaneBuilder");
-HBox = Java.type("javafx.scene.layout.HBox");
-HBoxBuilder = Java.type("javafx.scene.layout.HBoxBuilder");
-Pane = Java.type("javafx.scene.layout.Pane");
-PaneBuilder = Java.type("javafx.scene.layout.PaneBuilder");
-Priority = Java.type("javafx.scene.layout.Priority");
-Region = Java.type("javafx.scene.layout.Region");
-RegionBuilder = Java.type("javafx.scene.layout.RegionBuilder");
-RowConstraints = Java.type("javafx.scene.layout.RowConstraints");
-RowConstraintsBuilder = Java.type("javafx.scene.layout.RowConstraintsBuilder");
-StackPane = Java.type("javafx.scene.layout.StackPane");
-StackPaneBuilder = Java.type("javafx.scene.layout.StackPaneBuilder");
-TilePane = Java.type("javafx.scene.layout.TilePane");
-TilePaneBuilder = Java.type("javafx.scene.layout.TilePaneBuilder");
-VBox = Java.type("javafx.scene.layout.VBox");
-VBoxBuilder = Java.type("javafx.scene.layout.VBoxBuilder");
-LightBase = Java.type("javafx.scene.LightBase");
-//LightBaseBuilder = Java.type("javafx.scene.LightBaseBuilder");
-Node = Java.type("javafx.scene.Node");
-NodeBuilder = Java.type("javafx.scene.NodeBuilder");
-Color = Java.type("javafx.scene.paint.Color");
-ColorBuilder = Java.type("javafx.scene.paint.ColorBuilder");
-CycleMethod = Java.type("javafx.scene.paint.CycleMethod");
-ImagePattern = Java.type("javafx.scene.paint.ImagePattern");
-ImagePatternBuilder = Java.type("javafx.scene.paint.ImagePatternBuilder");
-LinearGradient = Java.type("javafx.scene.paint.LinearGradient");
-LinearGradientBuilder = Java.type("javafx.scene.paint.LinearGradientBuilder");
-Material = Java.type("javafx.scene.paint.Material");
-Paint = Java.type("javafx.scene.paint.Paint");
-PhongMaterial = Java.type("javafx.scene.paint.PhongMaterial");
-//PhongMaterialBuilder = Java.type("javafx.scene.paint.PhongMaterialBuilder");
-RadialGradient = Java.type("javafx.scene.paint.RadialGradient");
-RadialGradientBuilder = Java.type("javafx.scene.paint.RadialGradientBuilder");
-Stop = Java.type("javafx.scene.paint.Stop");
-StopBuilder = Java.type("javafx.scene.paint.StopBuilder");
-ParallelCamera = Java.type("javafx.scene.ParallelCamera");
-//ParallelCameraBuilder = Java.type("javafx.scene.ParallelCameraBuilder");
-Parent = Java.type("javafx.scene.Parent");
-ParentBuilder = Java.type("javafx.scene.ParentBuilder");
-PerspectiveCamera = Java.type("javafx.scene.PerspectiveCamera");
-PerspectiveCameraBuilder = Java.type("javafx.scene.PerspectiveCameraBuilder");
-PointLight = Java.type("javafx.scene.PointLight");
-//PointLightBuilder = Java.type("javafx.scene.PointLightBuilder");
-//Scene = Java.type("javafx.scene.Scene");
-SceneBuilder = Java.type("javafx.scene.SceneBuilder");
-Arc = Java.type("javafx.scene.shape.Arc");
-ArcBuilder = Java.type("javafx.scene.shape.ArcBuilder");
-ArcTo = Java.type("javafx.scene.shape.ArcTo");
-ArcToBuilder = Java.type("javafx.scene.shape.ArcToBuilder");
-ArcType = Java.type("javafx.scene.shape.ArcType");
-Box = Java.type("javafx.scene.shape.Box");
-//BoxBuilder = Java.type("javafx.scene.shape.BoxBuilder");
-Circle = Java.type("javafx.scene.shape.Circle");
-CircleBuilder = Java.type("javafx.scene.shape.CircleBuilder");
-ClosePath = Java.type("javafx.scene.shape.ClosePath");
-ClosePathBuilder = Java.type("javafx.scene.shape.ClosePathBuilder");
-CubicCurve = Java.type("javafx.scene.shape.CubicCurve");
-CubicCurveBuilder = Java.type("javafx.scene.shape.CubicCurveBuilder");
-CubicCurveTo = Java.type("javafx.scene.shape.CubicCurveTo");
-CubicCurveToBuilder = Java.type("javafx.scene.shape.CubicCurveToBuilder");
-CullFace = Java.type("javafx.scene.shape.CullFace");
-Cylinder = Java.type("javafx.scene.shape.Cylinder");
-//CylinderBuilder = Java.type("javafx.scene.shape.CylinderBuilder");
-DrawMode = Java.type("javafx.scene.shape.DrawMode");
-Ellipse = Java.type("javafx.scene.shape.Ellipse");
-EllipseBuilder = Java.type("javafx.scene.shape.EllipseBuilder");
-FillRule = Java.type("javafx.scene.shape.FillRule");
-HLineTo = Java.type("javafx.scene.shape.HLineTo");
-HLineToBuilder = Java.type("javafx.scene.shape.HLineToBuilder");
-Line = Java.type("javafx.scene.shape.Line");
-LineBuilder = Java.type("javafx.scene.shape.LineBuilder");
-LineTo = Java.type("javafx.scene.shape.LineTo");
-LineToBuilder = Java.type("javafx.scene.shape.LineToBuilder");
-Mesh = Java.type("javafx.scene.shape.Mesh");
-MeshView = Java.type("javafx.scene.shape.MeshView");
-//MeshViewBuilder = Java.type("javafx.scene.shape.MeshViewBuilder");
-MoveTo = Java.type("javafx.scene.shape.MoveTo");
-MoveToBuilder = Java.type("javafx.scene.shape.MoveToBuilder");
-Path = Java.type("javafx.scene.shape.Path");
-PathBuilder = Java.type("javafx.scene.shape.PathBuilder");
-PathElement = Java.type("javafx.scene.shape.PathElement");
-PathElementBuilder = Java.type("javafx.scene.shape.PathElementBuilder");
-Polygon = Java.type("javafx.scene.shape.Polygon");
-PolygonBuilder = Java.type("javafx.scene.shape.PolygonBuilder");
-Polyline = Java.type("javafx.scene.shape.Polyline");
-PolylineBuilder = Java.type("javafx.scene.shape.PolylineBuilder");
-QuadCurve = Java.type("javafx.scene.shape.QuadCurve");
-QuadCurveBuilder = Java.type("javafx.scene.shape.QuadCurveBuilder");
-QuadCurveTo = Java.type("javafx.scene.shape.QuadCurveTo");
-QuadCurveToBuilder = Java.type("javafx.scene.shape.QuadCurveToBuilder");
-Rectangle = Java.type("javafx.scene.shape.Rectangle");
-RectangleBuilder = Java.type("javafx.scene.shape.RectangleBuilder");
-Shape = Java.type("javafx.scene.shape.Shape");
-Shape3D = Java.type("javafx.scene.shape.Shape3D");
-//Shape3DBuilder = Java.type("javafx.scene.shape.Shape3DBuilder");
-ShapeBuilder = Java.type("javafx.scene.shape.ShapeBuilder");
-Sphere = Java.type("javafx.scene.shape.Sphere");
-//SphereBuilder = Java.type("javafx.scene.shape.SphereBuilder");
-StrokeLineCap = Java.type("javafx.scene.shape.StrokeLineCap");
-StrokeLineJoin = Java.type("javafx.scene.shape.StrokeLineJoin");
-StrokeType = Java.type("javafx.scene.shape.StrokeType");
-SVGPath = Java.type("javafx.scene.shape.SVGPath");
-SVGPathBuilder = Java.type("javafx.scene.shape.SVGPathBuilder");
-TriangleMesh = Java.type("javafx.scene.shape.TriangleMesh");
-VLineTo = Java.type("javafx.scene.shape.VLineTo");
-VLineToBuilder = Java.type("javafx.scene.shape.VLineToBuilder");
-SnapshotParameters = Java.type("javafx.scene.SnapshotParameters");
-SnapshotParametersBuilder = Java.type("javafx.scene.SnapshotParametersBuilder");
-SnapshotResult = Java.type("javafx.scene.SnapshotResult");
-SubScene = Java.type("javafx.scene.SubScene");
-//SubSceneBuilder = Java.type("javafx.scene.SubSceneBuilder");
-Font = Java.type("javafx.scene.text.Font");
-FontBuilder = Java.type("javafx.scene.text.FontBuilder");
-FontPosture = Java.type("javafx.scene.text.FontPosture");
-FontSmoothingType = Java.type("javafx.scene.text.FontSmoothingType");
-FontWeight = Java.type("javafx.scene.text.FontWeight");
-Text = Java.type("javafx.scene.text.Text");
-TextAlignment = Java.type("javafx.scene.text.TextAlignment");
-TextBoundsType = Java.type("javafx.scene.text.TextBoundsType");
-TextBuilder = Java.type("javafx.scene.text.TextBuilder");
-TextFlow = Java.type("javafx.scene.text.TextFlow");
-//TextFlowBuilder = Java.type("javafx.scene.text.TextFlowBuilder");
-Affine = Java.type("javafx.scene.transform.Affine");
-AffineBuilder = Java.type("javafx.scene.transform.AffineBuilder");
-MatrixType = Java.type("javafx.scene.transform.MatrixType");
-NonInvertibleTransformException = Java.type("javafx.scene.transform.NonInvertibleTransformException");
-Rotate = Java.type("javafx.scene.transform.Rotate");
-RotateBuilder = Java.type("javafx.scene.transform.RotateBuilder");
-Scale = Java.type("javafx.scene.transform.Scale");
-ScaleBuilder = Java.type("javafx.scene.transform.ScaleBuilder");
-Shear = Java.type("javafx.scene.transform.Shear");
-ShearBuilder = Java.type("javafx.scene.transform.ShearBuilder");
-Transform = Java.type("javafx.scene.transform.Transform");
-//TransformBuilder = Java.type("javafx.scene.transform.TransformBuilder");
-TransformChangedEvent = Java.type("javafx.scene.transform.TransformChangedEvent");
-Translate = Java.type("javafx.scene.transform.Translate");
-TranslateBuilder = Java.type("javafx.scene.transform.TranslateBuilder");
-DirectoryChooser = Java.type("javafx.stage.DirectoryChooser");
-DirectoryChooserBuilder = Java.type("javafx.stage.DirectoryChooserBuilder");
-FileChooser = Java.type("javafx.stage.FileChooser");
-FileChooser$ExtensionFilter = Java.type("javafx.stage.FileChooser$ExtensionFilter");
-FileChooserBuilder = Java.type("javafx.stage.FileChooserBuilder");
-Modality = Java.type("javafx.stage.Modality");
-Popup = Java.type("javafx.stage.Popup");
-PopupBuilder = Java.type("javafx.stage.PopupBuilder");
-PopupWindow = Java.type("javafx.stage.PopupWindow");
-PopupWindowBuilder = Java.type("javafx.stage.PopupWindowBuilder");
-Screen = Java.type("javafx.stage.Screen");
-//Stage = Java.type("javafx.stage.Stage");
-StageBuilder = Java.type("javafx.stage.StageBuilder");
-StageStyle = Java.type("javafx.stage.StageStyle");
-Window = Java.type("javafx.stage.Window");
-WindowBuilder = Java.type("javafx.stage.WindowBuilder");
-WindowEvent = Java.type("javafx.stage.WindowEvent");
+if (!this.JFX_BASE_CLASSES) {
+ load("fx:base.js")
+}
+LOAD_FX_CLASSES(JFX_GRAPHICS_CLASSES);
+
+
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/media.js Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/media.js Sat Sep 14 20:43:34 2013 +0100
@@ -23,23 +23,8 @@
* questions.
*/
-AudioClip = Java.type("javafx.scene.media.AudioClip");
-AudioClipBuilder = Java.type("javafx.scene.media.AudioClipBuilder");
-AudioEqualizer = Java.type("javafx.scene.media.AudioEqualizer");
-AudioSpectrumListener = Java.type("javafx.scene.media.AudioSpectrumListener");
-AudioTrack = Java.type("javafx.scene.media.AudioTrack");
-EqualizerBand = Java.type("javafx.scene.media.EqualizerBand");
-Media = Java.type("javafx.scene.media.Media");
-MediaBuilder = Java.type("javafx.scene.media.MediaBuilder");
-MediaErrorEvent = Java.type("javafx.scene.media.MediaErrorEvent");
-MediaException = Java.type("javafx.scene.media.MediaException");
-MediaException$Type = Java.type("javafx.scene.media.MediaException$Type");
-MediaMarkerEvent = Java.type("javafx.scene.media.MediaMarkerEvent");
-MediaPlayer = Java.type("javafx.scene.media.MediaPlayer");
-MediaPlayer$Status = Java.type("javafx.scene.media.MediaPlayer$Status");
-MediaPlayerBuilder = Java.type("javafx.scene.media.MediaPlayerBuilder");
-MediaView = Java.type("javafx.scene.media.MediaView");
-MediaViewBuilder = Java.type("javafx.scene.media.MediaViewBuilder");
-SubtitleTrack = Java.type("javafx.scene.media.SubtitleTrack");
-Track = Java.type("javafx.scene.media.Track");
-VideoTrack = Java.type("javafx.scene.media.VideoTrack");
+if (!this.JFX_BASE_CLASSES) {
+ load("fx:base.js")
+}
+
+LOAD_FX_CLASSES(JFX_MEDIA_CLASSES);
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/swing.js Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/swing.js Sat Sep 14 20:43:34 2013 +0100
@@ -23,7 +23,8 @@
* questions.
*/
-JFXPanel = Java.type("javafx.embed.swing.JFXPanel");
-JFXPanelBuilder = Java.type("javafx.embed.swing.JFXPanelBuilder");
-SwingFXUtils = Java.type("javafx.embed.swing.SwingFXUtils");
-SwingNode = Java.type("javafx.embed.swing.SwingNode");
+if (!this.JFX_BASE_CLASSES) {
+ load("fx:base.js")
+}
+
+LOAD_FX_CLASSES(JFX_SWING_CLASSES);
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/swt.js Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/swt.js Sat Sep 14 20:43:34 2013 +0100
@@ -23,7 +23,8 @@
* questions.
*/
-CustomTransfer = Java.type("javafx.embed.swt.CustomTransfer");
-//CustomTransferBuilder = Java.type("javafx.embed.swt.CustomTransferBuilder");
-FXCanvas = Java.type("javafx.embed.swt.FXCanvas");
-SWTFXUtils = Java.type("javafx.embed.swt.SWTFXUtils");
+if (!this.JFX_BASE_CLASSES) {
+ load("fx:base.js")
+}
+
+LOAD_FX_CLASSES(JFX_SWT_CLASSES);
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/web.js Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/web.js Sat Sep 14 20:43:34 2013 +0100
@@ -23,14 +23,8 @@
* questions.
*/
-HTMLEditor = Java.type("javafx.scene.web.HTMLEditor");
-//HTMLEditorBuilder = Java.type("javafx.scene.web.HTMLEditorBuilder");
-PopupFeatures = Java.type("javafx.scene.web.PopupFeatures");
-PromptData = Java.type("javafx.scene.web.PromptData");
-//PromptDataBuilder = Java.type("javafx.scene.web.PromptDataBuilder");
-WebEngine = Java.type("javafx.scene.web.WebEngine");
-WebEngineBuilder = Java.type("javafx.scene.web.WebEngineBuilder");
-WebEvent = Java.type("javafx.scene.web.WebEvent");
-WebHistory = Java.type("javafx.scene.web.WebHistory");
-WebView = Java.type("javafx.scene.web.WebView");
-WebViewBuilder = Java.type("javafx.scene.web.WebViewBuilder");
+if (!this.JFX_BASE_CLASSES) {
+ load("fx:base.js")
+}
+
+LOAD_FX_CLASSES(JFX_WEB_CLASSES);
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js Sat Sep 14 20:43:34 2013 +0100
@@ -137,17 +137,6 @@
}
});
-// Object.prototype.__proto__ (read-only)
-Object.defineProperty(Object.prototype, "__proto__", {
- configurable: true, enumerable: false,
- get: function() {
- return Object.getPrototypeOf(this);
- },
- set: function(x) {
- Object.setPrototypeOf(this, x);
- }
-});
-
// Object.prototype.toSource
Object.defineProperty(Object.prototype, "toSource", {
configurable: true, enumerable: false, writable: true,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/global_var_delete.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8024180: Incorrect handling of expression and parent scope in 'with' statements
+ *
+ * @test
+ * @run
+ */
+
+
+this.x = 44;
+
+function func() {
+ with({ }) {
+ print(x);
+ }
+}
+
+func();
+
+// delete global 'x'
+delete this.x;
+
+try {
+ func();
+} catch(e) {
+ // expect ReferenceError
+ print(e);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/global_var_delete.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,2 @@
+44
+ReferenceError: "x" is not defined
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/global_var_shadow.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8024180: Incorrect handling of expression and parent scope in 'with' statements
+ *
+ * @test
+ * @run
+ */
+
+// global variable is shadowed by with 'expression' property
+var user = { name: 'foo' };
+
+function func(locals) {
+ with (locals) {
+ print(user.name);
+ }
+}
+
+// global user.name 'foo' printed
+func({});
+
+// local user.name 'toto' printed
+func({ user: { name: 'toto' } });
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/global_var_shadow.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,2 @@
+foo
+toto
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/scope_no_such_prop.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8024180: Incorrect handling of expression and parent scope in 'with' statements
+ *
+ * @test
+ * @run
+ */
+
+// __noSuchProperty__ defined here confuses 'with'
+// results in ReferenceError even when 'with' expression has
+// the property
+
+load("nashorn:mozilla_compat.js")
+
+function func(locals) {
+ with (locals) {
+ print(user.name);
+ }
+}
+
+try {
+ func({});
+} catch (e) {
+ print(e);
+}
+
+// 'toto' expected in the call below
+func({ user: { name: 'toto' } });
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/scope_no_such_prop.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,2 @@
+ReferenceError: user is not defined
+toto
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/with_expr_prop_add.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8024180: Incorrect handling of expression and parent scope in 'with' statements
+ *
+ * @test
+ * @run
+ */
+
+var obj = {};
+var x = "global x";
+
+// adding property to 'with' xpression object should reflect
+// as variable inside the 'with' block.
+function func() {
+ with(obj) {
+ for (i = 0; i < 2; i++) {
+ print(x);
+ if (i == 0) {
+ obj.x = "obj.x";
+ }
+ }
+ }
+}
+
+func();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/with_expr_prop_add.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,2 @@
+global x
+obj.x
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/with_expr_proto_prop_add.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8024180: Incorrect handling of expression and parent scope in 'with' statements
+ *
+ * @test
+ * @run
+ */
+
+var p = { };
+var obj = Object.create(p);
+
+var x = "global x";
+
+// adding property to __proto__ of 'with' expression should
+// reflect as a variable immediately.
+function func() {
+ with(obj) {
+ for (i = 0; i < 2; i++) {
+ print(x);
+ if (i == 0) {
+ p.x = "p.x";
+ }
+ }
+ }
+}
+
+func();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/with_expr_proto_prop_add.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,2 @@
+global x
+p.x
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/with_java_object.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8024180: Incorrect handling of expression and parent scope in 'with' statements
+ *
+ * @test
+ * @run
+ */
+
+// TypeError for with expression being non script object
+try {
+ with(new java.lang.Object()) {}
+} catch (e) {
+ print(e);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/8024180/with_java_object.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,1 @@
+TypeError: Cannot apply "with" to non script object
--- a/nashorn/test/script/basic/JDK-8023368.js Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/test/script/basic/JDK-8023368.js Sat Sep 14 20:43:34 2013 +0100
@@ -28,8 +28,6 @@
* @run
*/
-load("nashorn:mozilla_compat.js");
-
// function to force same callsites
function check(obj) {
print(obj.func());
--- a/nashorn/test/script/basic/JDK-8023368.js.EXPECTED Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/test/script/basic/JDK-8023368.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -4,15 +4,15 @@
Func.prototype.func
hello
[object Object]
-obj.__proto__.func @ 57
+obj.__proto__.func @ 55
344
[object Object]
-obj.__proto__.func @ 57
+obj.__proto__.func @ 55
344
[object Object]
-obj.__proto__.func @ 57
+obj.__proto__.func @ 55
344
new object.toString
-obj.__proto__.func @ 57
+obj.__proto__.func @ 55
344
new object.toString
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8024120.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8024120: Setting __proto__ to null removes the __proto__ property
+ *
+ * @test
+ * @run
+ */
+
+var obj = {};
+
+obj.__proto__ = null;
+
+if (obj.__proto__ !== null || typeof(obj.__proto__) != 'object') {
+ fail("obj.__proto__ is expected to be null");
+}
+
+var p = Object.getPrototypeOf(obj);
+if (p !== null || typeof(p) != 'object') {
+ fail("Object.getPrototypeOf(obj) is expected to be null");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8024174.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8024174: Setting __proto__ property in Object literal should be supported *
+ * @test
+ * @run
+ */
+
+var p = { foo: function() { print("p.foo"); } };
+
+var obj = {
+ __proto__ : p,
+ bar: 44
+};
+
+if (obj.__proto__ !== p || Object.getPrototypeOf(obj) !== p) {
+ fail("obj.__proto__ was not set inside literal");
+}
+
+if (typeof(obj.foo) !== 'function' || obj.foo !== p.foo) {
+ fail("'obj' failed to inherit 'foo' from 'p'");
+}
+
+var obj2 = {
+ __proto__: null
+};
+
+if (obj2.__proto__ !== null || Object.getPrototypeOf(obj2) !== null) {
+ fail("obj2.__proto__ was not set to null inside literal");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8024255.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8024255: When a keyword is used as object property name, the property can not be deleted
+ *
+ * @test
+ * @run
+ */
+
+function check(obj, name) {
+ var desc = Object.getOwnPropertyDescriptor(obj, name);
+ if (! desc.configurable) {
+ fail("Property " + name + " is not configurable");
+ }
+
+ if (! (delete obj[name])) {
+ fail("Property " + name + " can not be deleted");
+ }
+}
+
+var obj = {
+ default: 344,
+ in: 'hello',
+ if: false,
+ class: 4.223
+}
+
+for (var p in obj) {
+ check(obj, p);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8024512.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8024512: Regex /[^\[]/ doesn't match
+ *
+ * @test
+ * @run
+ */
+
+print("[M]".match(/(\[[^\[]*\])/));
+print("[[]".match(/(\[[^\[]*\])/));
+
+print("[M]".match(/(\[[^\[^]*\])/));
+print("[[]".match(/(\[[^\[^]*\])/));
+print("[^]".match(/(\[[^\[^]*\])/));
+
+print("[M]".match(/(\[[^\[]\])/));
+print("[[]".match(/(\[[^\[]\])/));
+
+print("[M]".match(/(\[[^\[^]\])/));
+print("[[]".match(/(\[[^\[^]\])/));
+print("[^]".match(/(\[[^\[^]\])/));
+
+print("M".match(/[^\[]/));
+print("[".match(/[^\[]/));
+print("^".match(/[^\[]/));
+
+// Repeat above without escaping inner square bracket
+print("[M]".match(/(\[[^[]\])/));
+print("[[]".match(/(\[[^[]\])/));
+
+print("[M]".match(/(\[[^[^]\])/));
+print("[[]".match(/(\[[^[^]\])/));
+print("[^]".match(/(\[[^[^]\])/));
+
+print("M".match(/[^[]/));
+print("[".match(/[^[]/));
+print("^".match(/[^[]/));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8024512.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,21 @@
+[M],[M]
+[],[]
+[M],[M]
+[],[]
+null
+[M],[M]
+null
+[M],[M]
+null
+null
+M
+null
+^
+[M],[M]
+null
+[M],[M]
+null
+null
+M
+null
+^
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8024619.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8024619: JDBC java.sql.DriverManager is not usable from JS script
+ *
+ * @test
+ * @run
+ */
+
+var DriverManager = Java.type("java.sql.DriverManager");
+var e = DriverManager.getDrivers();
+
+var driverFound = false;
+// check for Nashorn SQL driver
+while (e.hasMoreElements()) {
+ var driver = e.nextElement();
+ if (driver.acceptsURL("jdbc:nashorn:")) {
+ driverFound = true;
+ break;
+ }
+}
+
+if (! driverFound) {
+ fail("Nashorn JDBC Driver not found!");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8024846.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8024846: keep separate internal arguments variable
+ *
+ * @test
+ */
+
+function f() { print(arguments); }
+
+function func(obj) {
+ var arguments = obj;
+ for (var i in arguments) {
+ }
+ return obj;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8024847.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8024847: Java.to should accept mirror and external JSObjects as array-like objects as well
+ *
+ * @test
+ * @run
+ */
+
+var global = loadWithNewGlobal({ name: "test", script:"this" });
+var arr = new global.Array(2, 4, 6, 8);
+var jarr = Java.to(arr, "int[]");
+for (var i in jarr) {
+ print(jarr[i]);
+}
+
+arr = null;
+jarr = null;
+
+// external JSObjects
+var JSObject = Java.type("jdk.nashorn.api.scripting.JSObject");
+var arr = new JSObject() {
+ getMember: function(name) {
+ return name == "length"? 4 : undefined;
+ },
+
+ hasMember: function(name) {
+ return name == "length";
+ },
+
+ getSlot: function(idx) {
+ return idx*idx;
+ },
+
+ hasSlot: function(idx) {
+ return true;
+ }
+};
+
+var jarr = Java.to(arr, "int[]");
+for (var i in jarr) {
+ print(jarr[i]);
+}
+
+arr = null;
+jarr = null;
+
+// List conversion
+var arr = global.Array("hello", "world");
+var jlist = Java.to(arr, java.util.List);
+print(jlist instanceof java.util.List);
+print(jlist);
+
+arr = null;
+jlist = null;
+
+// external JSObject
+var __array__ = [ "nashorn", "js" ];
+
+var obj = new JSObject() {
+
+ hasMember: function(name) {
+ return name in __array__;
+ },
+
+ hasSlot: function(idx) {
+ return idx in __array__;
+ },
+
+ getMember: function(name) {
+ return __array__[name];
+ },
+
+ getSlot: function(idx) {
+ return __array__[idx];
+ }
+}
+
+var jlist = Java.to(obj, java.util.List);
+print(jlist instanceof java.util.List);
+print(jlist);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8024847.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,12 @@
+2
+4
+6
+8
+0
+1
+4
+9
+true
+[hello, world]
+true
+[nashorn, js]
--- a/nashorn/test/script/basic/NASHORN-737.js Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/test/script/basic/NASHORN-737.js Sat Sep 14 20:43:34 2013 +0100
@@ -30,4 +30,4 @@
load("nashorn:parser.js");
var ast = parse("label: while(true) break label;");
-print(JSON.stringify(ast));
+print(JSON.stringify(ast, null, " "));
--- a/nashorn/test/script/basic/NASHORN-737.js.EXPECTED Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/test/script/basic/NASHORN-737.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -1,1 +1,36 @@
-{"type":"Program","rest":null,"body":[{"type":"LabeledStatement","label":{"type":"Identifier","name":"label"},"body":{"type":"BlockStatement","body":[{"type":"WhileStatement","test":{"type":"Literal","value":true},"block":{"type":"BlockStatement","body":[{"type":"BreakStatement","label":"label"}]}}]}}]}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "LabeledStatement",
+ "label": {
+ "type": "Identifier",
+ "name": "label"
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "WhileStatement",
+ "test": {
+ "type": "Literal",
+ "value": true
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "BreakStatement",
+ "label": {
+ "type": "Identifier",
+ "name": "label"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
--- a/nashorn/test/script/basic/circular_proto.js Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/test/script/basic/circular_proto.js Sat Sep 14 20:43:34 2013 +0100
@@ -29,7 +29,6 @@
*/
// check that we cannot create __proto__ cycle
-load("nashorn:mozilla_compat.js");
var obj = {};
var obj2 = Object.create(obj);
--- a/nashorn/test/script/basic/nonextensible_proto_assign.js Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/test/script/basic/nonextensible_proto_assign.js Sat Sep 14 20:43:34 2013 +0100
@@ -28,8 +28,6 @@
* @run
*/
-load("nashorn:mozilla_compat.js")
-
// check that we cannot assign to __proto__ of a non-extensible object
try {
var obj = {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/assignmentExpr.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check assignment e xyzpressions.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("xyz = 314");
+printParse("xyz += 314");
+printParse("xyz -= 314");
+printParse("xyz *= 314");
+printParse("xyz /= 314");
+printParse("xyz %= 314");
+printParse("xyz <<= 314");
+printParse("xyz >>= 314");
+printParse("xyz >>>= 314");
+printParse("xyz &= 314");
+printParse("xyz ^= 314");
+printParse("xyz |= 314");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/assignmentExpr.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,240 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": "=",
+ "left": {
+ "type": "Identifier",
+ "name": "xyz"
+ },
+ "right": {
+ "type": "Literal",
+ "value": 314
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": "+=",
+ "left": {
+ "type": "Identifier",
+ "name": "xyz"
+ },
+ "right": {
+ "type": "Literal",
+ "value": 314
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": "-=",
+ "left": {
+ "type": "Identifier",
+ "name": "xyz"
+ },
+ "right": {
+ "type": "Literal",
+ "value": 314
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": "*=",
+ "left": {
+ "type": "Identifier",
+ "name": "xyz"
+ },
+ "right": {
+ "type": "Literal",
+ "value": 314
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": "/=",
+ "left": {
+ "type": "Identifier",
+ "name": "xyz"
+ },
+ "right": {
+ "type": "Literal",
+ "value": 314
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": "%=",
+ "left": {
+ "type": "Identifier",
+ "name": "xyz"
+ },
+ "right": {
+ "type": "Literal",
+ "value": 314
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": "<<=",
+ "left": {
+ "type": "Identifier",
+ "name": "xyz"
+ },
+ "right": {
+ "type": "Literal",
+ "value": 314
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": ">>=",
+ "left": {
+ "type": "Identifier",
+ "name": "xyz"
+ },
+ "right": {
+ "type": "Literal",
+ "value": 314
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": ">>>=",
+ "left": {
+ "type": "Identifier",
+ "name": "xyz"
+ },
+ "right": {
+ "type": "Literal",
+ "value": 314
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": "&=",
+ "left": {
+ "type": "Identifier",
+ "name": "xyz"
+ },
+ "right": {
+ "type": "Literal",
+ "value": 314
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": "^=",
+ "left": {
+ "type": "Identifier",
+ "name": "xyz"
+ },
+ "right": {
+ "type": "Literal",
+ "value": 314
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": "|=",
+ "left": {
+ "type": "Identifier",
+ "name": "xyz"
+ },
+ "right": {
+ "type": "Literal",
+ "value": 314
+ }
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/binaryExpr.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check binary operators.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("a * b")
+printParse("a / b");
+printParse("a % b");
+printParse("a + b");
+printParse("a - b");
+printParse("a << b");
+printParse("a >> b");
+printParse("a >>> b");
+printParse("a < b");
+printParse("a > b");
+printParse("a <= b");
+printParse("a >= b");
+printParse("a instanceof b");
+printParse("a == b");
+printParse("a != b");
+printParse("a === b");
+printParse("a !== b");
+printParse("a & b");
+printParse("a ^ b");
+printParse("a | b");
+printParse("a && b");
+printParse("a || b");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/binaryExpr.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,440 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "*",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "/",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "%",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "+",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "-",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "<<",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": ">>",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": ">>>",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "<",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": ">",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "<=",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": ">=",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "instanceof",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "==",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "!=",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "===",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "!==",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "&",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "^",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "|",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "LogicalExpression",
+ "operator": "&&",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "LogicalExpression",
+ "operator": "||",
+ "left": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "b"
+ }
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/breakStat.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check 'break' statement.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("while (true) { break; }");
+printParse("loop: { while (true) { break loop } }");
+printParse("loop: { for (;;) { break loop } }");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/breakStat.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,92 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "WhileStatement",
+ "test": {
+ "type": "Literal",
+ "value": true
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "BreakStatement",
+ "label": null
+ }
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "LabeledStatement",
+ "label": {
+ "type": "Identifier",
+ "name": "loop"
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "WhileStatement",
+ "test": {
+ "type": "Literal",
+ "value": true
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "BreakStatement",
+ "label": {
+ "type": "Identifier",
+ "name": "loop"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "LabeledStatement",
+ "label": {
+ "type": "Identifier",
+ "name": "loop"
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ForStatement",
+ "init": null,
+ "test": null,
+ "update": null,
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "BreakStatement",
+ "label": {
+ "type": "Identifier",
+ "name": "loop"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/condExpr.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check ternary operator.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("a? b : c");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/condExpr.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,23 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "ConditionalExpression",
+ "test": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "consequent": {
+ "type": "Identifier",
+ "name": "b"
+ },
+ "alternate": {
+ "type": "Identifier",
+ "name": "c"
+ }
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/continueStat.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check 'continue' statement.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("while (true) { continue; }");
+printParse("begin: { while (true) { continue begin; } }");
+printParse("start: { for(;;) { continue start; } }");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/continueStat.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,92 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "WhileStatement",
+ "test": {
+ "type": "Literal",
+ "value": true
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ContinueStatement",
+ "label": null
+ }
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "LabeledStatement",
+ "label": {
+ "type": "Identifier",
+ "name": "begin"
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "WhileStatement",
+ "test": {
+ "type": "Literal",
+ "value": true
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ContinueStatement",
+ "label": {
+ "type": "Identifier",
+ "name": "begin"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "LabeledStatement",
+ "label": {
+ "type": "Identifier",
+ "name": "start"
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ForStatement",
+ "init": null,
+ "test": null,
+ "update": null,
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ContinueStatement",
+ "label": {
+ "type": "Identifier",
+ "name": "start"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/debuggerStat.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check debugger statement.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("debugger");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/debuggerStat.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,8 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "DebuggerStatement"
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/functions.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check 'function' statements and expressions.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("function hello() { print('hello') }")
+printParse("function hello(a) { print(a) }")
+printParse("function hello(a, b) { print(a, b) }")
+printParse("var hello = function() { print('hello') };")
+printParse("var hello = function hello() { print('hello') };")
+printParse("(function(){})")
+printParse("function test() { 'use strict' }");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/functions.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,279 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "FunctionDeclaration",
+ "id": {
+ "type": "Identifier",
+ "name": "hello"
+ },
+ "params": [],
+ "defaults": [],
+ "rest": null,
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "print"
+ },
+ "arguments": [
+ {
+ "type": "Literal",
+ "value": "hello"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "generator": false,
+ "expression": false
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "FunctionDeclaration",
+ "id": {
+ "type": "Identifier",
+ "name": "hello"
+ },
+ "params": [
+ {
+ "type": "Identifier",
+ "name": "a"
+ }
+ ],
+ "defaults": [],
+ "rest": null,
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "print"
+ },
+ "arguments": [
+ {
+ "type": "Identifier",
+ "name": "a"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "generator": false,
+ "expression": false
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "FunctionDeclaration",
+ "id": {
+ "type": "Identifier",
+ "name": "hello"
+ },
+ "params": [
+ {
+ "type": "Identifier",
+ "name": "a"
+ },
+ {
+ "type": "Identifier",
+ "name": "b"
+ }
+ ],
+ "defaults": [],
+ "rest": null,
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "print"
+ },
+ "arguments": [
+ {
+ "type": "Identifier",
+ "name": "a"
+ },
+ {
+ "type": "Identifier",
+ "name": "b"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "generator": false,
+ "expression": false
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "VariableDeclaration",
+ "declarations": [
+ {
+ "type": "VariableDeclarator",
+ "id": {
+ "type": "Identifier",
+ "name": "hello"
+ },
+ "init": {
+ "type": "FunctionExpression",
+ "id": null,
+ "params": [],
+ "defaults": [],
+ "rest": null,
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "print"
+ },
+ "arguments": [
+ {
+ "type": "Literal",
+ "value": "hello"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "generator": false,
+ "expression": false
+ }
+ }
+ ]
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "VariableDeclaration",
+ "declarations": [
+ {
+ "type": "VariableDeclarator",
+ "id": {
+ "type": "Identifier",
+ "name": "hello"
+ },
+ "init": {
+ "type": "FunctionExpression",
+ "id": {
+ "type": "Identifier",
+ "name": "hello"
+ },
+ "params": [],
+ "defaults": [],
+ "rest": null,
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "print"
+ },
+ "arguments": [
+ {
+ "type": "Literal",
+ "value": "hello"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "generator": false,
+ "expression": false
+ }
+ }
+ ]
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "FunctionExpression",
+ "id": null,
+ "params": [],
+ "defaults": [],
+ "rest": null,
+ "body": {
+ "type": "BlockStatement",
+ "body": []
+ },
+ "generator": false,
+ "expression": false
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "FunctionDeclaration",
+ "id": {
+ "type": "Identifier",
+ "name": "test"
+ },
+ "params": [],
+ "defaults": [],
+ "rest": null,
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "Literal",
+ "value": "use strict"
+ }
+ }
+ ]
+ },
+ "generator": false,
+ "expression": false
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/ifStat.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check 'if' statement.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("if (js) { nashorn() }");
+printParse("if (js) { nashorn() } else { java() }");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/ifStat.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,73 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "IfStatement",
+ "test": {
+ "type": "Identifier",
+ "name": "js"
+ },
+ "consequent": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "nashorn"
+ },
+ "arguments": []
+ }
+ }
+ ]
+ },
+ "alternate": null
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "IfStatement",
+ "test": {
+ "type": "Identifier",
+ "name": "js"
+ },
+ "consequent": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "nashorn"
+ },
+ "arguments": []
+ }
+ }
+ ]
+ },
+ "alternate": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "java"
+ },
+ "arguments": []
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/labelledStat.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Test for labelled statements.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("begin: { for (;;) break begin }");
+printParse("begin: { while (true) break begin }");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/labelledStat.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,71 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "LabeledStatement",
+ "label": {
+ "type": "Identifier",
+ "name": "begin"
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ForStatement",
+ "init": null,
+ "test": null,
+ "update": null,
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "BreakStatement",
+ "label": {
+ "type": "Identifier",
+ "name": "begin"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "LabeledStatement",
+ "label": {
+ "type": "Identifier",
+ "name": "begin"
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "WhileStatement",
+ "test": {
+ "type": "Literal",
+ "value": true
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "BreakStatement",
+ "label": {
+ "type": "Identifier",
+ "name": "begin"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/lhsExpr.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check left-hand-side expressions
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("a[3]");
+printParse("a[b]");
+printParse("a['foo']");
+printParse("obj.foo");
+printParse("obj.foo.bar");
+printParse("new Type");
+printParse("new Type()");
+printParse("new Type(a, 'hello')");
+printParse("new obj.Type");
+printParse("new obj.Type()");
+printParse("new obj.Type(a, 'hello')");
+printParse("foo()")
+printParse("obj.foo()");
+printParse("foo(a,b)");
+printParse("obj.foo(a, b)");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/lhsExpr.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,344 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "property": {
+ "type": "Literal",
+ "value": 3
+ },
+ "computed": true
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "property": {
+ "type": "Identifier",
+ "name": "b"
+ },
+ "computed": true
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "property": {
+ "type": "Literal",
+ "value": "foo"
+ },
+ "computed": true
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "obj"
+ },
+ "property": {
+ "type": "Identifier",
+ "name": "foo"
+ },
+ "computed": false
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "obj"
+ },
+ "property": {
+ "type": "Identifier",
+ "name": "foo"
+ },
+ "computed": false
+ },
+ "property": {
+ "type": "Identifier",
+ "name": "bar"
+ },
+ "computed": false
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "NewExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "Type"
+ },
+ "arguments": []
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "NewExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "Type"
+ },
+ "arguments": []
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "NewExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "Type"
+ },
+ "arguments": [
+ {
+ "type": "Identifier",
+ "name": "a"
+ },
+ {
+ "type": "Literal",
+ "value": "hello"
+ }
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "NewExpression",
+ "callee": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "obj"
+ },
+ "property": {
+ "type": "Identifier",
+ "name": "Type"
+ },
+ "computed": false
+ },
+ "arguments": []
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "NewExpression",
+ "callee": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "obj"
+ },
+ "property": {
+ "type": "Identifier",
+ "name": "Type"
+ },
+ "computed": false
+ },
+ "arguments": []
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "NewExpression",
+ "callee": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "obj"
+ },
+ "property": {
+ "type": "Identifier",
+ "name": "Type"
+ },
+ "computed": false
+ },
+ "arguments": [
+ {
+ "type": "Identifier",
+ "name": "a"
+ },
+ {
+ "type": "Literal",
+ "value": "hello"
+ }
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "foo"
+ },
+ "arguments": []
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "obj"
+ },
+ "property": {
+ "type": "Identifier",
+ "name": "foo"
+ },
+ "computed": false
+ },
+ "arguments": []
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "foo"
+ },
+ "arguments": [
+ {
+ "type": "Identifier",
+ "name": "a"
+ },
+ {
+ "type": "Identifier",
+ "name": "b"
+ }
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "obj"
+ },
+ "property": {
+ "type": "Identifier",
+ "name": "foo"
+ },
+ "computed": false
+ },
+ "arguments": [
+ {
+ "type": "Identifier",
+ "name": "a"
+ },
+ {
+ "type": "Identifier",
+ "name": "b"
+ }
+ ]
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/loopStat.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests for loop statements.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("while(true) { print('hello') }")
+printParse("do { print('hello') } while(true)")
+printParse("for (i in obj) { print(obj[i]) }")
+printParse("for each (i in obj) { print(i) }")
+printParse("for (i = 0; i < 10; i++) { print(i) }")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/loopStat.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,212 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "WhileStatement",
+ "test": {
+ "type": "Literal",
+ "value": true
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "print"
+ },
+ "arguments": [
+ {
+ "type": "Literal",
+ "value": "hello"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "DoWhileStatement",
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "print"
+ },
+ "arguments": [
+ {
+ "type": "Literal",
+ "value": "hello"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "test": {
+ "type": "Literal",
+ "value": true
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ForInStatement",
+ "left": {
+ "type": "Identifier",
+ "name": "i"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "obj"
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "print"
+ },
+ "arguments": [
+ {
+ "type": "MemberExpression",
+ "object": {
+ "type": "Identifier",
+ "name": "obj"
+ },
+ "property": {
+ "type": "Identifier",
+ "name": "i"
+ },
+ "computed": true
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "each": false
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ForInStatement",
+ "left": {
+ "type": "Identifier",
+ "name": "i"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "obj"
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "print"
+ },
+ "arguments": [
+ {
+ "type": "Identifier",
+ "name": "i"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "each": true
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ForStatement",
+ "init": {
+ "type": "AssignmentExpression",
+ "operator": "=",
+ "left": {
+ "type": "Identifier",
+ "name": "i"
+ },
+ "right": {
+ "type": "Literal",
+ "value": 0
+ }
+ },
+ "test": {
+ "type": "BinaryExpression",
+ "operator": "<",
+ "left": {
+ "type": "Identifier",
+ "name": "i"
+ },
+ "right": {
+ "type": "Literal",
+ "value": 10
+ }
+ },
+ "update": {
+ "type": "UpdateExpression",
+ "operator": "++",
+ "prefix": false,
+ "argument": {
+ "type": "Identifier",
+ "name": "i"
+ }
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "print"
+ },
+ "arguments": [
+ {
+ "type": "Identifier",
+ "name": "i"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/objectLitExpr.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check assignment e xyzpressions.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("obj = {}");
+printParse("p = { x: 10, y: 2 }");
+printParse("p = { 'x': 10, 'y': 2 }");
+printParse("p = { get x() { return xValue }, get y() { return yValue } }");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/objectLitExpr.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,189 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": "=",
+ "left": {
+ "type": "Identifier",
+ "name": "obj"
+ },
+ "right": {
+ "type": "ObjectExpression",
+ "properties": []
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": "=",
+ "left": {
+ "type": "Identifier",
+ "name": "p"
+ },
+ "right": {
+ "type": "ObjectExpression",
+ "properties": [
+ {
+ "key": {
+ "type": "Identifier",
+ "name": "x"
+ },
+ "value": {
+ "type": "Literal",
+ "value": 10
+ },
+ "kind": "init"
+ },
+ {
+ "key": {
+ "type": "Identifier",
+ "name": "y"
+ },
+ "value": {
+ "type": "Literal",
+ "value": 2
+ },
+ "kind": "init"
+ }
+ ]
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": "=",
+ "left": {
+ "type": "Identifier",
+ "name": "p"
+ },
+ "right": {
+ "type": "ObjectExpression",
+ "properties": [
+ {
+ "key": {
+ "type": "Literal",
+ "value": "x"
+ },
+ "value": {
+ "type": "Literal",
+ "value": 10
+ },
+ "kind": "init"
+ },
+ {
+ "key": {
+ "type": "Literal",
+ "value": "y"
+ },
+ "value": {
+ "type": "Literal",
+ "value": 2
+ },
+ "kind": "init"
+ }
+ ]
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": "=",
+ "left": {
+ "type": "Identifier",
+ "name": "p"
+ },
+ "right": {
+ "type": "ObjectExpression",
+ "properties": [
+ {
+ "key": {
+ "type": "Identifier",
+ "name": "x"
+ },
+ "value": {
+ "type": "FunctionExpression",
+ "id": {
+ "type": "Identifier",
+ "name": "get x"
+ },
+ "params": [],
+ "defaults": [],
+ "rest": null,
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ReturnStatement",
+ "argument": {
+ "type": "Identifier",
+ "name": "xValue"
+ }
+ }
+ ]
+ },
+ "generator": false,
+ "expression": false
+ },
+ "kind": "get"
+ },
+ {
+ "key": {
+ "type": "Identifier",
+ "name": "y"
+ },
+ "value": {
+ "type": "FunctionExpression",
+ "id": {
+ "type": "Identifier",
+ "name": "get y"
+ },
+ "params": [],
+ "defaults": [],
+ "rest": null,
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ReturnStatement",
+ "argument": {
+ "type": "Identifier",
+ "name": "yValue"
+ }
+ }
+ ]
+ },
+ "generator": false,
+ "expression": false
+ },
+ "kind": "get"
+ }
+ ]
+ }
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/parenExpr.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests for parenthesis expressions.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("(2) + (1) + 4");
+printParse("3 + (7) << (5)");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/parenExpr.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,56 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "+",
+ "left": {
+ "type": "BinaryExpression",
+ "operator": "+",
+ "left": {
+ "type": "Literal",
+ "value": 2
+ },
+ "right": {
+ "type": "Literal",
+ "value": 1
+ }
+ },
+ "right": {
+ "type": "Literal",
+ "value": 4
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "<<",
+ "left": {
+ "type": "BinaryExpression",
+ "operator": "+",
+ "left": {
+ "type": "Literal",
+ "value": 3
+ },
+ "right": {
+ "type": "Literal",
+ "value": 7
+ }
+ },
+ "right": {
+ "type": "Literal",
+ "value": 5
+ }
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/primaryExpr.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check primary expressions.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("this");
+printParse("foo");
+printParse("null");
+printParse("true");
+printParse("false");
+printParse("33");
+printParse("3.14");
+printParse("(10 + 3)*2");
+printParse("({})");
+printParse("({ x: 3 })");
+printParse("[]");
+printParse("[,,]");
+printParse("[4, 5, 5]");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/primaryExpr.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,199 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "ThisExpression"
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "Identifier",
+ "name": "foo"
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "Literal",
+ "value": null
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "Literal",
+ "value": true
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "Literal",
+ "value": false
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "Literal",
+ "value": 33
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "Literal",
+ "value": 3.14
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "BinaryExpression",
+ "operator": "*",
+ "left": {
+ "type": "BinaryExpression",
+ "operator": "+",
+ "left": {
+ "type": "Literal",
+ "value": 10
+ },
+ "right": {
+ "type": "Literal",
+ "value": 3
+ }
+ },
+ "right": {
+ "type": "Literal",
+ "value": 2
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "ObjectExpression",
+ "properties": []
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "ObjectExpression",
+ "properties": [
+ {
+ "key": {
+ "type": "Identifier",
+ "name": "x"
+ },
+ "value": {
+ "type": "Literal",
+ "value": 3
+ },
+ "kind": "init"
+ }
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "ArrayExpression",
+ "elements": []
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "ArrayExpression",
+ "elements": [
+ null,
+ null
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "ArrayExpression",
+ "elements": [
+ {
+ "type": "Literal",
+ "value": 4
+ },
+ {
+ "type": "Literal",
+ "value": 5
+ },
+ {
+ "type": "Literal",
+ "value": 5
+ }
+ ]
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/returnStat.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check 'return' statement.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("(function() { return })");
+printParse("(function() { return res })");
+printParse("(function() { return foo() })");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/returnStat.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,88 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "FunctionExpression",
+ "id": null,
+ "params": [],
+ "defaults": [],
+ "rest": null,
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ReturnStatement",
+ "argument": null
+ }
+ ]
+ },
+ "generator": false,
+ "expression": false
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "FunctionExpression",
+ "id": null,
+ "params": [],
+ "defaults": [],
+ "rest": null,
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ReturnStatement",
+ "argument": {
+ "type": "Identifier",
+ "name": "res"
+ }
+ }
+ ]
+ },
+ "generator": false,
+ "expression": false
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "FunctionExpression",
+ "id": null,
+ "params": [],
+ "defaults": [],
+ "rest": null,
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ReturnStatement",
+ "argument": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "foo"
+ },
+ "arguments": []
+ }
+ }
+ ]
+ },
+ "generator": false,
+ "expression": false
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/switchStat.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests for switch statement.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("switch (key) {}");
+printParse("switch (key) { case 2: hello(); break; }");
+printParse("switch (key) { case 4: hello(); break; case 2: world(); break; default: break }");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/switchStat.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,123 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "SwitchStatement",
+ "discriminant": {
+ "type": "Identifier",
+ "name": "key"
+ },
+ "cases": []
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "SwitchStatement",
+ "discriminant": {
+ "type": "Identifier",
+ "name": "key"
+ },
+ "cases": [
+ {
+ "type": "SwitchCase",
+ "test": {
+ "type": "Literal",
+ "value": 2
+ },
+ "consequent": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "hello"
+ },
+ "arguments": []
+ }
+ },
+ {
+ "type": "BreakStatement",
+ "label": null
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "SwitchStatement",
+ "discriminant": {
+ "type": "Identifier",
+ "name": "key"
+ },
+ "cases": [
+ {
+ "type": "SwitchCase",
+ "test": {
+ "type": "Literal",
+ "value": 4
+ },
+ "consequent": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "hello"
+ },
+ "arguments": []
+ }
+ },
+ {
+ "type": "BreakStatement",
+ "label": null
+ }
+ ]
+ },
+ {
+ "type": "SwitchCase",
+ "test": {
+ "type": "Literal",
+ "value": 2
+ },
+ "consequent": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "world"
+ },
+ "arguments": []
+ }
+ },
+ {
+ "type": "BreakStatement",
+ "label": null
+ }
+ ]
+ },
+ {
+ "type": "SwitchCase",
+ "test": null,
+ "consequent": [
+ {
+ "type": "BreakStatement",
+ "label": null
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/throwStat.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests for throw statement.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("throw err");
+printParse("throw 'wrong'");
+printParse("throw new TypeError");
+printParse("throw new TypeError('not an array')");
+printParse("throw { msg: 'wrong!' }");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/throwStat.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,85 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ThrowStatement",
+ "argument": {
+ "type": "Identifier",
+ "name": "err"
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ThrowStatement",
+ "argument": {
+ "type": "Literal",
+ "value": "wrong"
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ThrowStatement",
+ "argument": {
+ "type": "NewExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "TypeError"
+ },
+ "arguments": []
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ThrowStatement",
+ "argument": {
+ "type": "NewExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "TypeError"
+ },
+ "arguments": [
+ {
+ "type": "Literal",
+ "value": "not an array"
+ }
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ThrowStatement",
+ "argument": {
+ "type": "ObjectExpression",
+ "properties": [
+ {
+ "key": {
+ "type": "Identifier",
+ "name": "msg"
+ },
+ "value": {
+ "type": "Literal",
+ "value": "wrong!"
+ },
+ "kind": "init"
+ }
+ ]
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/tryCatchStat.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check try..catch statements.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("try { } catch (e) { }");
+printParse("try { } catch (e) { } finally {}");
+printParse("try { } finally {}");
+printParse("try { } catch (e) { handle() }");
+printParse("try { that() } catch (e) { handle() } finally { clean() }");
+printParse("try { that() } catch (e if e instanceof TypeError) { handle() } catch (e) { rest() }");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/tryCatchStat.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,305 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "BlockStatement",
+ "block": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "TryStatement",
+ "block": {
+ "type": "BlockStatement",
+ "body": []
+ },
+ "guardedHandlers": [],
+ "handler": {
+ "type": "CatchClause",
+ "param": {
+ "type": "Identifier",
+ "name": "e"
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": []
+ }
+ },
+ "finalizer": null
+ }
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "BlockStatement",
+ "block": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "TryStatement",
+ "block": {
+ "type": "BlockStatement",
+ "body": []
+ },
+ "guardedHandlers": [],
+ "handler": {
+ "type": "CatchClause",
+ "param": {
+ "type": "Identifier",
+ "name": "e"
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": []
+ }
+ },
+ "finalizer": {
+ "type": "BlockStatement",
+ "body": []
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "BlockStatement",
+ "block": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "TryStatement",
+ "block": {
+ "type": "BlockStatement",
+ "body": []
+ },
+ "guardedHandlers": [],
+ "handler": null,
+ "finalizer": {
+ "type": "BlockStatement",
+ "body": []
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "BlockStatement",
+ "block": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "TryStatement",
+ "block": {
+ "type": "BlockStatement",
+ "body": []
+ },
+ "guardedHandlers": [],
+ "handler": {
+ "type": "CatchClause",
+ "param": {
+ "type": "Identifier",
+ "name": "e"
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "handle"
+ },
+ "arguments": []
+ }
+ }
+ ]
+ }
+ },
+ "finalizer": null
+ }
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "BlockStatement",
+ "block": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "TryStatement",
+ "block": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "that"
+ },
+ "arguments": []
+ }
+ }
+ ]
+ },
+ "guardedHandlers": [],
+ "handler": {
+ "type": "CatchClause",
+ "param": {
+ "type": "Identifier",
+ "name": "e"
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "handle"
+ },
+ "arguments": []
+ }
+ }
+ ]
+ }
+ },
+ "finalizer": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "clean"
+ },
+ "arguments": []
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "BlockStatement",
+ "block": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "TryStatement",
+ "block": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "that"
+ },
+ "arguments": []
+ }
+ }
+ ]
+ },
+ "guardedHandlers": [
+ {
+ "type": "CatchClause",
+ "param": {
+ "type": "Identifier",
+ "name": "e"
+ },
+ "guard": {
+ "type": "BinaryExpression",
+ "operator": "instanceof",
+ "left": {
+ "type": "Identifier",
+ "name": "e"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "TypeError"
+ }
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "handle"
+ },
+ "arguments": []
+ }
+ }
+ ]
+ }
+ }
+ ],
+ "handler": {
+ "type": "CatchClause",
+ "param": {
+ "type": "Identifier",
+ "name": "e"
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "CallExpression",
+ "callee": {
+ "type": "Identifier",
+ "name": "rest"
+ },
+ "arguments": []
+ }
+ }
+ ]
+ }
+ },
+ "finalizer": null
+ }
+ ]
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/unaryExpr.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check unary operators.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("x++");
+printParse("x--");
+printParse("delete x");
+printParse("void x");
+printParse("typeof x");
+printParse("++x");
+printParse("--x");
+printParse("+x");
+printParse("-x");
+printParse("~x");
+printParse("!x");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/unaryExpr.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,187 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "UpdateExpression",
+ "operator": "++",
+ "prefix": false,
+ "argument": {
+ "type": "Identifier",
+ "name": "x"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "UpdateExpression",
+ "operator": "--",
+ "prefix": false,
+ "argument": {
+ "type": "Identifier",
+ "name": "x"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "UnaryExpression",
+ "operator": "delete",
+ "prefix": true,
+ "argument": {
+ "type": "Identifier",
+ "name": "x"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "UnaryExpression",
+ "operator": "void",
+ "prefix": true,
+ "argument": {
+ "type": "Identifier",
+ "name": "x"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "UnaryExpression",
+ "operator": "typeof",
+ "prefix": true,
+ "argument": {
+ "type": "Identifier",
+ "name": "x"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "UpdateExpression",
+ "operator": "++",
+ "prefix": true,
+ "argument": {
+ "type": "Identifier",
+ "name": "x"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "UpdateExpression",
+ "operator": "--",
+ "prefix": true,
+ "argument": {
+ "type": "Identifier",
+ "name": "x"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "UnaryExpression",
+ "operator": "+",
+ "prefix": true,
+ "argument": {
+ "type": "Identifier",
+ "name": "x"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "UnaryExpression",
+ "operator": "-",
+ "prefix": true,
+ "argument": {
+ "type": "Identifier",
+ "name": "x"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "UnaryExpression",
+ "operator": "~",
+ "prefix": true,
+ "argument": {
+ "type": "Identifier",
+ "name": "x"
+ }
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "UnaryExpression",
+ "operator": "!",
+ "prefix": true,
+ "argument": {
+ "type": "Identifier",
+ "name": "x"
+ }
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/useStrict.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check if statement.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("'use strict'");
+printParse("function f() { 'use strict' }");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/useStrict.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,41 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "Literal",
+ "value": "use strict"
+ }
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "FunctionDeclaration",
+ "id": {
+ "type": "Identifier",
+ "name": "f"
+ },
+ "params": [],
+ "defaults": [],
+ "rest": null,
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "Literal",
+ "value": "use strict"
+ }
+ }
+ ]
+ },
+ "generator": false,
+ "expression": false
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/util.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @subtest
+ */
+
+// utilitity for parser tests
+
+load("nashorn:parser.js");
+function printParse(code) {
+ print(JSON.stringify(parse(code), null, ' '));
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/varDecl.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check variable declarations.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+// no initialization
+printParse("var a");
+printParse("var a, b");
+
+// init single, multiple
+printParse("var a = 'hello'");
+printParse("var a = 1, b = 2, c = 3");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/varDecl.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,123 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "VariableDeclaration",
+ "declarations": [
+ {
+ "type": "VariableDeclarator",
+ "id": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "init": null
+ }
+ ]
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "VariableDeclaration",
+ "declarations": [
+ {
+ "type": "VariableDeclarator",
+ "id": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "init": null
+ }
+ ]
+ },
+ {
+ "type": "VariableDeclaration",
+ "declarations": [
+ {
+ "type": "VariableDeclarator",
+ "id": {
+ "type": "Identifier",
+ "name": "b"
+ },
+ "init": null
+ }
+ ]
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "VariableDeclaration",
+ "declarations": [
+ {
+ "type": "VariableDeclarator",
+ "id": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "init": {
+ "type": "Literal",
+ "value": "hello"
+ }
+ }
+ ]
+ }
+ ]
+}
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "VariableDeclaration",
+ "declarations": [
+ {
+ "type": "VariableDeclarator",
+ "id": {
+ "type": "Identifier",
+ "name": "a"
+ },
+ "init": {
+ "type": "Literal",
+ "value": 1
+ }
+ }
+ ]
+ },
+ {
+ "type": "VariableDeclaration",
+ "declarations": [
+ {
+ "type": "VariableDeclarator",
+ "id": {
+ "type": "Identifier",
+ "name": "b"
+ },
+ "init": {
+ "type": "Literal",
+ "value": 2
+ }
+ }
+ ]
+ },
+ {
+ "type": "VariableDeclaration",
+ "declarations": [
+ {
+ "type": "VariableDeclarator",
+ "id": {
+ "type": "Identifier",
+ "name": "c"
+ },
+ "init": {
+ "type": "Literal",
+ "value": 3
+ }
+ }
+ ]
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/withStat.js Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests for 'with' statement.
+ *
+ * @test
+ * @run
+ */
+
+load(__DIR__ + "util.js");
+
+printParse("with (scope) { x = y }");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/parser/withStat.js.EXPECTED Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,32 @@
+{
+ "type": "Program",
+ "body": [
+ {
+ "type": "WithStatement",
+ "object": {
+ "type": "Identifier",
+ "name": "scope"
+ },
+ "body": {
+ "type": "BlockStatement",
+ "body": [
+ {
+ "type": "ExpressionStatement",
+ "expression": {
+ "type": "AssignmentExpression",
+ "operator": "=",
+ "left": {
+ "type": "Identifier",
+ "name": "x"
+ },
+ "right": {
+ "type": "Identifier",
+ "name": "y"
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/META-INF/services/java.sql.Driver Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,1 @@
+jdk.nashorn.api.NashornSQLDriver
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/api/NashornSQLDriver.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. 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.nashorn.api;
+
+import java.sql.*;
+import java.util.Properties;
+import java.util.logging.Logger;
+
+/**
+ * A dummy SQL driver for testing purpose.
+ */
+public final class NashornSQLDriver implements Driver {
+ static {
+ try {
+ DriverManager.registerDriver(new NashornSQLDriver(), null);
+ } catch (SQLException se) {
+ throw new RuntimeException(se);
+ }
+ }
+
+ @Override
+ public boolean acceptsURL(String url) {
+ return url.startsWith("jdbc:nashorn:");
+ }
+
+ @Override
+ public Connection connect(String url, Properties info) {
+ throw new UnsupportedOperationException("I am a dummy!!");
+ }
+
+ @Override
+ public int getMajorVersion() {
+ return -1;
+ }
+
+ @Override
+ public int getMinorVersion() {
+ return -1;
+ }
+
+ @Override
+ public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) {
+ return new DriverPropertyInfo[0];
+ }
+
+ @Override
+ public boolean jdbcCompliant() {
+ // no way!
+ return false;
+ }
+
+ @Override
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ throw new SQLFeatureNotSupportedException();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. 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.nashorn.api.scripting;
+
+import java.nio.IntBuffer;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Set;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.fail;
+import org.testng.annotations.Test;
+
+/**
+ * Tests for pluggable external impls. of jdk.nashorn.api.scripting.JSObject.
+ *
+ * JDK-8024615: Refactor ScriptObjectMirror and JSObject to support external
+ * JSObject implementations.
+ */
+public class PluggableJSObjectTest {
+ public static class MapWrapperObject extends JSObject {
+ private final HashMap<String, Object> map = new LinkedHashMap<>();
+
+ public HashMap<String, Object> getMap() {
+ return map;
+ }
+
+ @Override
+ public Object getMember(String name) {
+ return map.get(name);
+ }
+
+ @Override
+ public void setMember(String name, Object value) {
+ map.put(name, value);
+ }
+
+ @Override
+ public boolean hasMember(String name) {
+ return map.containsKey(name);
+ }
+
+ @Override
+ public void removeMember(String name) {
+ map.remove(name);
+ }
+
+ @Override
+ public Set<String> keySet() {
+ return map.keySet();
+ }
+
+ @Override
+ public Collection<Object> values() {
+ return map.values();
+ }
+ }
+
+ @Test
+ // Named property access on a JSObject
+ public void namedAccessTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ try {
+ final MapWrapperObject obj = new MapWrapperObject();
+ e.put("obj", obj);
+ obj.getMap().put("foo", "bar");
+
+ // property-like access on MapWrapperObject objects
+ assertEquals(e.eval("obj.foo"), "bar");
+ e.eval("obj.foo = 'hello'");
+ assertEquals(e.eval("'foo' in obj"), Boolean.TRUE);
+ assertEquals(e.eval("obj.foo"), "hello");
+ assertEquals(obj.getMap().get("foo"), "hello");
+ e.eval("delete obj.foo");
+ assertFalse(obj.getMap().containsKey("foo"));
+ assertEquals(e.eval("'foo' in obj"), Boolean.FALSE);
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+
+ public static class BufferObject extends JSObject {
+ private final IntBuffer buf;
+
+ public BufferObject(int size) {
+ buf = IntBuffer.allocate(size);
+ }
+
+ public IntBuffer getBuffer() {
+ return buf;
+ }
+
+ @Override
+ public Object getMember(String name) {
+ return name.equals("length")? buf.capacity() : null;
+ }
+
+ @Override
+ public boolean hasSlot(int i) {
+ return i > -1 && i < buf.capacity();
+ }
+
+ @Override
+ public Object getSlot(int i) {
+ return buf.get(i);
+ }
+
+ @Override
+ public void setSlot(int i, Object value) {
+ buf.put(i, ((Number)value).intValue());
+ }
+
+ @Override
+ public boolean isArray() {
+ return true;
+ }
+ }
+
+ @Test
+ // array-like indexed access for a JSObject
+ public void indexedAccessTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ try {
+ final BufferObject buf = new BufferObject(2);
+ e.put("buf", buf);
+
+ // array-like access on BufferObject objects
+ assertEquals(e.eval("buf.length"), buf.getBuffer().capacity());
+ e.eval("buf[0] = 23");
+ assertEquals(buf.getBuffer().get(0), 23);
+ assertEquals(e.eval("buf[0]"), 23);
+ assertEquals(e.eval("buf[1]"), 0);
+ buf.getBuffer().put(1, 42);
+ assertEquals(e.eval("buf[1]"), 42);
+ assertEquals(e.eval("Array.isArray(buf)"), Boolean.TRUE);
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+
+ public static class Adder extends JSObject {
+ @Override
+ public Object call(Object thiz, Object... args) {
+ double res = 0.0;
+ for (Object arg : args) {
+ res += ((Number)arg).doubleValue();
+ }
+ return res;
+ }
+
+ @Override
+ public boolean isFunction() {
+ return true;
+ }
+ }
+
+ @Test
+ // a callable JSObject
+ public void callableJSObjectTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ try {
+ e.put("sum", new Adder());
+ // check callability of Adder objects
+ assertEquals(e.eval("typeof sum"), "function");
+ assertEquals(((Number)e.eval("sum(1, 2, 3, 4, 5)")).intValue(), 15);
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+
+ public static class Factory extends JSObject {
+ @Override
+ public Object newObject(Object... args) {
+ return new HashMap<Object, Object>();
+ }
+
+ @Override
+ public boolean isFunction() {
+ return true;
+ }
+ }
+
+ @Test
+ // a factory JSObject
+ public void factoryJSObjectTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ try {
+ e.put("Factory", new Factory());
+
+ // check new on Factory
+ assertEquals(e.eval("typeof Factory"), "function");
+ assertEquals(e.eval("typeof new Factory()"), "object");
+ assertEquals(e.eval("(new Factory()) instanceof java.util.Map"), Boolean.TRUE);
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+
+ @Test
+ // iteration tests
+ public void iteratingJSObjectTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ try {
+ final MapWrapperObject obj = new MapWrapperObject();
+ obj.setMember("foo", "hello");
+ obj.setMember("bar", "world");
+ e.put("obj", obj);
+
+ // check for..in
+ Object val = e.eval("var str = ''; for (i in obj) str += i; str");
+ assertEquals(val.toString(), "foobar");
+
+ // check for..each..in
+ val = e.eval("var str = ''; for each (i in obj) str += i; str");
+ assertEquals(val.toString(), "helloworld");
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+}
--- a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -140,8 +140,8 @@
fail("obj[1] != 'world'");
}
- if (!obj.call("func", new Object[0]).equals("hello")) {
- fail("obj.call('func') != 'hello'");
+ if (!obj.callMember("func", new Object[0]).equals("hello")) {
+ fail("obj.func() != 'hello'");
}
// try setting properties
@@ -210,8 +210,8 @@
e.eval("function func() {}");
e2.put("foo", e.get("func"));
- final Object e2global = e2.eval("this");
- final Object newObj = ((ScriptObjectMirror) e2global).newObject("foo");
+ final ScriptObjectMirror e2global = (ScriptObjectMirror)e2.eval("this");
+ final Object newObj = ((ScriptObjectMirror)e2global.getMember("foo")).newObject();
assertTrue(newObj instanceof ScriptObjectMirror);
}
@@ -223,8 +223,8 @@
e.eval("function func() {}");
e2.put("func", e.get("func"));
- final Object e2obj = e2.eval("({ foo: func })");
- final Object newObj = ((ScriptObjectMirror) e2obj).newObject("foo");
+ final ScriptObjectMirror e2obj = (ScriptObjectMirror)e2.eval("({ foo: func })");
+ final Object newObj = ((ScriptObjectMirror)e2obj.getMember("foo")).newObject();
assertTrue(newObj instanceof ScriptObjectMirror);
}
}
--- a/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java Fri Sep 06 09:55:59 2013 +0100
+++ b/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java Sat Sep 14 20:43:34 2013 +0100
@@ -64,6 +64,7 @@
final Options options = new Options("");
final ErrorManager errors = new ErrorManager();
final Context cx = new Context(options, errors, Thread.currentThread().getContextClassLoader());
+ final boolean strict = cx.getEnv()._strict;
final ScriptObject oldGlobal = Context.getGlobal();
Context.setGlobal(cx.createGlobal());
@@ -95,7 +96,7 @@
assertEquals(sobj.size(), 2);
// add property
- sobj.put("zee", "hello");
+ sobj.put("zee", "hello", strict);
assertEquals(sobj.get("zee"), "hello");
assertEquals(sobj.size(), 3);