# HG changeset patch # User duke # Date 1499273872 -7200 # Node ID a08d0f5b08bcfae66310b61d093f1069c6102e33 # Parent a233c04832cf6e80958914e598279a6ec44c0088# Parent a700a34fd8394876a3564e90543ba890b1a063b2 Merge diff -r a233c04832cf -r a08d0f5b08bc .hgtags-top-repo --- a/.hgtags-top-repo Thu May 30 10:58:13 2013 -0700 +++ b/.hgtags-top-repo Wed Jul 05 18:57:52 2017 +0200 @@ -213,3 +213,4 @@ 892a0196d10c67f3a12f0eefb0bb536e423d8868 jdk8-b89 69b773a221b956a3386933ecdbfeccee0edeac47 jdk8-b90 cb51fb4789ac0b8be4056482077ddfb8f3bd3805 jdk8-b91 +3a36c926a7aafa9d4a892a45ef3678e87ad8359b jdk8-b92 diff -r a233c04832cf -r a08d0f5b08bc common/autoconf/basics.m4 --- a/common/autoconf/basics.m4 Thu May 30 10:58:13 2013 -0700 +++ b/common/autoconf/basics.m4 Wed Jul 05 18:57:52 2017 +0200 @@ -72,7 +72,7 @@ AC_MSG_ERROR([The path of $1, which resolves as "$path", is not found.]) fi - $1="`cd "$path"; $THEPWDCMD`" + $1="`cd "$path"; $THEPWDCMD -L`" fi ]) @@ -169,10 +169,10 @@ COUNTER=0 sym_link_dir=`$DIRNAME [$]$1` sym_link_file=`$BASENAME [$]$1` - # Use the system pwd and not the shell builtin to resolve directory symlinks cd $sym_link_dir - cd `$THEPWDCMD` - sym_link_dir=`$THEPWDCMD` + # Use -P flag to resolve symlinks in directories. + cd `$THEPWDCMD -P` + sym_link_dir=`$THEPWDCMD -P` # Resolve file symlinks while test $COUNTER -lt 20; do ISLINK=`$LS -l $sym_link_dir/$sym_link_file | $GREP '\->' | $SED -e 's/.*-> \(.*\)/\1/'` @@ -183,7 +183,7 @@ # Again resolve directory symlinks since the target of the just found # link could be in a different directory cd `$DIRNAME $ISLINK` - sym_link_dir=`$THEPWDCMD` + sym_link_dir=`$THEPWDCMD -P` sym_link_file=`$BASENAME $ISLINK` let COUNTER=COUNTER+1 done @@ -264,7 +264,6 @@ BASIC_REQUIRE_PROG(MKTEMP, mktemp) BASIC_REQUIRE_PROG(MV, mv) BASIC_REQUIRE_PROG(PRINTF, printf) -BASIC_REQUIRE_PROG(THEPWDCMD, pwd) BASIC_REQUIRE_PROG(RM, rm) BASIC_REQUIRE_PROG(SH, sh) BASIC_REQUIRE_PROG(SORT, sort) @@ -297,6 +296,10 @@ # Always force rm. RM="$RM -f" +# pwd behaves differently on various platforms and some don't support the -L flag. +# Always use the bash builtin pwd to get uniform behavior. +THEPWDCMD=pwd + # These are not required on all platforms AC_PATH_PROG(CYGPATH, cygpath) AC_PATH_PROG(READLINK, readlink) @@ -309,13 +312,12 @@ [ # Locate the directory of this script. SCRIPT="[$]0" -BASIC_REMOVE_SYMBOLIC_LINKS(SCRIPT) -AUTOCONF_DIR=`cd \`$DIRNAME $SCRIPT\`; $THEPWDCMD` +AUTOCONF_DIR=`cd \`$DIRNAME $SCRIPT\`; $THEPWDCMD -L` # Where is the source? It is located two levels above the configure script. CURDIR="$PWD" cd "$AUTOCONF_DIR/../.." -SRC_ROOT="`$THEPWDCMD`" +SRC_ROOT="`$THEPWDCMD -L`" if test "x$OPENJDK_TARGET_OS" = "xwindows"; then PATH_SEP=";" @@ -374,13 +376,9 @@ [ CONF_NAME=${with_conf_name} ]) # Test from where we are running configure, in or outside of src root. -# To enable comparison of directories, CURDIR needs to be symlink free -# just like SRC_ROOT already is -NOSYM_CURDIR="$CURDIR" -BASIC_REMOVE_SYMBOLIC_LINKS(NOSYM_CURDIR) -if test "x$NOSYM_CURDIR" = "x$SRC_ROOT" || test "x$NOSYM_CURDIR" = "x$SRC_ROOT/common" \ - || test "x$NOSYM_CURDIR" = "x$SRC_ROOT/common/autoconf" \ - || test "x$NOSYM_CURDIR" = "x$SRC_ROOT/common/makefiles" ; then +if test "x$CURDIR" = "x$SRC_ROOT" || test "x$CURDIR" = "x$SRC_ROOT/common" \ + || test "x$CURDIR" = "x$SRC_ROOT/common/autoconf" \ + || test "x$CURDIR" = "x$SRC_ROOT/common/makefiles" ; then # We are running configure from the src root. # Create a default ./build/target-variant-debuglevel output root. if test "x${CONF_NAME}" = x; then @@ -617,6 +615,20 @@ if test "x$OPENJDK_TARGET_OS" = "xmacosx"; then BASIC_REQUIRE_PROG(XATTR, xattr) + AC_PATH_PROG(CODESIGN, codesign) + if test "x$CODESIGN" != "x"; then + # Verify that the openjdk_codesign certificate is present + AC_MSG_CHECKING([if openjdk_codesign certificate is present]) + rm -f codesign-testfile + touch codesign-testfile + codesign -s openjdk_codesign codesign-testfile 2>&AS_MESSAGE_LOG_FD >&AS_MESSAGE_LOG_FD || CODESIGN= + rm -f codesign-testfile + if test "x$CODESIGN" = x; then + AC_MSG_RESULT([no]) + else + AC_MSG_RESULT([yes]) + fi + fi fi ]) diff -r a233c04832cf -r a08d0f5b08bc common/autoconf/basics_windows.m4 --- a/common/autoconf/basics_windows.m4 Thu May 30 10:58:13 2013 -0700 +++ b/common/autoconf/basics_windows.m4 Wed Jul 05 18:57:52 2017 +0200 @@ -300,7 +300,7 @@ # Setup basic configuration paths, and platform-specific stuff related to PATHs. AC_DEFUN([BASIC_CHECK_PATHS_WINDOWS], [ - SRC_ROOT_LENGTH=`$THEPWDCMD|$WC -m` + SRC_ROOT_LENGTH=`$THEPWDCMD -L|$WC -m` if test $SRC_ROOT_LENGTH -gt 100; then AC_MSG_ERROR([Your base path is too long. It is $SRC_ROOT_LENGTH characters long, but only 100 is supported]) fi diff -r a233c04832cf -r a08d0f5b08bc common/autoconf/build-performance.m4 --- a/common/autoconf/build-performance.m4 Thu May 30 10:58:13 2013 -0700 +++ b/common/autoconf/build-performance.m4 Wed Jul 05 18:57:52 2017 +0200 @@ -145,6 +145,9 @@ if test "$JOBS" -gt "16"; then JOBS=16 fi + if test "$JOBS" -eq "0"; then + JOBS=1 + fi AC_MSG_RESULT([$JOBS]) else JOBS=$with_jobs diff -r a233c04832cf -r a08d0f5b08bc common/autoconf/generated-configure.sh --- a/common/autoconf/generated-configure.sh Thu May 30 10:58:13 2013 -0700 +++ b/common/autoconf/generated-configure.sh Wed Jul 05 18:57:52 2017 +0200 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.67 for OpenJDK jdk8. +# Generated by GNU Autoconf 2.68 for OpenJDK jdk8. # # Report bugs to . # @@ -91,6 +91,7 @@ IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. +as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -216,11 +217,18 @@ # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. + # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL - exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} + case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; + esac + exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : @@ -681,8 +689,8 @@ SHARED_LIBRARY OBJ_SUFFIX COMPILER_NAME +JT_HOME JTREGEXE -JT_HOME LIPO ac_ct_OBJDUMP OBJDUMP @@ -797,6 +805,7 @@ OS_VERSION_MINOR OS_VERSION_MAJOR PKG_CONFIG +CODESIGN XATTR TIME STAT @@ -900,7 +909,6 @@ SORT SH RM -THEPWDCMD PRINTF MV MKTEMP @@ -988,6 +996,7 @@ with_cacerts_file enable_unlimited_crypto with_milestone +with_update_version with_build_number with_user_release_suffix with_boot_jdk @@ -1459,7 +1468,7 @@ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac @@ -1727,6 +1736,7 @@ group --with-cacerts-file specify alternative cacerts file --with-milestone Set milestone value for build [internal] + --with-update-version Set update version value for build [b00] --with-build-number Set build number value for build [b00] --with-user-release-suffix Add a custom string to the version string if build @@ -1894,7 +1904,7 @@ if $ac_init_version; then cat <<\_ACEOF OpenJDK configure jdk8 -generated by GNU Autoconf 2.67 +generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation @@ -1940,7 +1950,7 @@ ac_retval=1 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile @@ -1978,7 +1988,7 @@ ac_retval=1 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile @@ -2016,7 +2026,7 @@ ac_retval=1 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_objc_try_compile @@ -2053,7 +2063,7 @@ ac_retval=1 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp @@ -2090,7 +2100,7 @@ ac_retval=1 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_cpp @@ -2103,10 +2113,10 @@ ac_fn_cxx_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval "test \"\${$3+set}\"" = set; then : + if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 @@ -2173,7 +2183,7 @@ esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" @@ -2182,7 +2192,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_header_mongrel @@ -2223,7 +2233,7 @@ ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_run @@ -2237,7 +2247,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2255,7 +2265,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_header_compile @@ -2432,7 +2442,7 @@ rm -f conftest.val fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_compute_int @@ -2478,7 +2488,7 @@ # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_link @@ -2491,7 +2501,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2546,7 +2556,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_func @@ -2559,7 +2569,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2577,7 +2587,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile cat >config.log <<_ACEOF @@ -2585,7 +2595,7 @@ running configure, to aid debugging if configure makes a mistake. It was created by OpenJDK $as_me jdk8, which was -generated by GNU Autoconf 2.67. Invocation command line was +generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -2843,7 +2853,7 @@ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi done @@ -3780,7 +3790,7 @@ #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1369723814 +DATE_WHEN_GENERATED=1370470729 ############################################################################### # @@ -3818,7 +3828,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_BASENAME+set}" = set; then : +if ${ac_cv_path_BASENAME+:} false; then : $as_echo_n "(cached) " >&6 else case $BASENAME in @@ -3877,7 +3887,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_BASH+set}" = set; then : +if ${ac_cv_path_BASH+:} false; then : $as_echo_n "(cached) " >&6 else case $BASH in @@ -3936,7 +3946,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CAT+set}" = set; then : +if ${ac_cv_path_CAT+:} false; then : $as_echo_n "(cached) " >&6 else case $CAT in @@ -3995,7 +4005,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CHMOD+set}" = set; then : +if ${ac_cv_path_CHMOD+:} false; then : $as_echo_n "(cached) " >&6 else case $CHMOD in @@ -4054,7 +4064,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CMP+set}" = set; then : +if ${ac_cv_path_CMP+:} false; then : $as_echo_n "(cached) " >&6 else case $CMP in @@ -4113,7 +4123,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_COMM+set}" = set; then : +if ${ac_cv_path_COMM+:} false; then : $as_echo_n "(cached) " >&6 else case $COMM in @@ -4172,7 +4182,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CP+set}" = set; then : +if ${ac_cv_path_CP+:} false; then : $as_echo_n "(cached) " >&6 else case $CP in @@ -4231,7 +4241,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CPIO+set}" = set; then : +if ${ac_cv_path_CPIO+:} false; then : $as_echo_n "(cached) " >&6 else case $CPIO in @@ -4290,7 +4300,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CUT+set}" = set; then : +if ${ac_cv_path_CUT+:} false; then : $as_echo_n "(cached) " >&6 else case $CUT in @@ -4349,7 +4359,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_DATE+set}" = set; then : +if ${ac_cv_path_DATE+:} false; then : $as_echo_n "(cached) " >&6 else case $DATE in @@ -4408,7 +4418,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_DIFF+set}" = set; then : +if ${ac_cv_path_DIFF+:} false; then : $as_echo_n "(cached) " >&6 else case $DIFF in @@ -4467,7 +4477,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_DIRNAME+set}" = set; then : +if ${ac_cv_path_DIRNAME+:} false; then : $as_echo_n "(cached) " >&6 else case $DIRNAME in @@ -4526,7 +4536,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_ECHO+set}" = set; then : +if ${ac_cv_path_ECHO+:} false; then : $as_echo_n "(cached) " >&6 else case $ECHO in @@ -4585,7 +4595,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_EXPR+set}" = set; then : +if ${ac_cv_path_EXPR+:} false; then : $as_echo_n "(cached) " >&6 else case $EXPR in @@ -4644,7 +4654,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_FILE+set}" = set; then : +if ${ac_cv_path_FILE+:} false; then : $as_echo_n "(cached) " >&6 else case $FILE in @@ -4703,7 +4713,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_FIND+set}" = set; then : +if ${ac_cv_path_FIND+:} false; then : $as_echo_n "(cached) " >&6 else case $FIND in @@ -4762,7 +4772,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_HEAD+set}" = set; then : +if ${ac_cv_path_HEAD+:} false; then : $as_echo_n "(cached) " >&6 else case $HEAD in @@ -4821,7 +4831,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_LN+set}" = set; then : +if ${ac_cv_path_LN+:} false; then : $as_echo_n "(cached) " >&6 else case $LN in @@ -4880,7 +4890,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_LS+set}" = set; then : +if ${ac_cv_path_LS+:} false; then : $as_echo_n "(cached) " >&6 else case $LS in @@ -4939,7 +4949,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_MKDIR+set}" = set; then : +if ${ac_cv_path_MKDIR+:} false; then : $as_echo_n "(cached) " >&6 else case $MKDIR in @@ -4998,7 +5008,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_MKTEMP+set}" = set; then : +if ${ac_cv_path_MKTEMP+:} false; then : $as_echo_n "(cached) " >&6 else case $MKTEMP in @@ -5057,7 +5067,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_MV+set}" = set; then : +if ${ac_cv_path_MV+:} false; then : $as_echo_n "(cached) " >&6 else case $MV in @@ -5116,7 +5126,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_PRINTF+set}" = set; then : +if ${ac_cv_path_PRINTF+:} false; then : $as_echo_n "(cached) " >&6 else case $PRINTF in @@ -5169,72 +5179,13 @@ - for ac_prog in pwd -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_THEPWDCMD+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - case $THEPWDCMD in - [\\/]* | ?:[\\/]*) - ac_cv_path_THEPWDCMD="$THEPWDCMD" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_path_THEPWDCMD="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - ;; -esac -fi -THEPWDCMD=$ac_cv_path_THEPWDCMD -if test -n "$THEPWDCMD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $THEPWDCMD" >&5 -$as_echo "$THEPWDCMD" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$THEPWDCMD" && break -done - - - if test "x$THEPWDCMD" = x; then - if test "xpwd" = x; then - PROG_NAME=thepwdcmd - else - PROG_NAME=pwd - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $PROG_NAME!" >&5 -$as_echo "$as_me: Could not find $PROG_NAME!" >&6;} - as_fn_error $? "Cannot continue" "$LINENO" 5 - fi - - - for ac_prog in rm do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_RM+set}" = set; then : +if ${ac_cv_path_RM+:} false; then : $as_echo_n "(cached) " >&6 else case $RM in @@ -5293,7 +5244,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_SH+set}" = set; then : +if ${ac_cv_path_SH+:} false; then : $as_echo_n "(cached) " >&6 else case $SH in @@ -5352,7 +5303,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_SORT+set}" = set; then : +if ${ac_cv_path_SORT+:} false; then : $as_echo_n "(cached) " >&6 else case $SORT in @@ -5411,7 +5362,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_TAIL+set}" = set; then : +if ${ac_cv_path_TAIL+:} false; then : $as_echo_n "(cached) " >&6 else case $TAIL in @@ -5470,7 +5421,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_TAR+set}" = set; then : +if ${ac_cv_path_TAR+:} false; then : $as_echo_n "(cached) " >&6 else case $TAR in @@ -5529,7 +5480,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_TEE+set}" = set; then : +if ${ac_cv_path_TEE+:} false; then : $as_echo_n "(cached) " >&6 else case $TEE in @@ -5588,7 +5539,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_TOUCH+set}" = set; then : +if ${ac_cv_path_TOUCH+:} false; then : $as_echo_n "(cached) " >&6 else case $TOUCH in @@ -5647,7 +5598,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_TR+set}" = set; then : +if ${ac_cv_path_TR+:} false; then : $as_echo_n "(cached) " >&6 else case $TR in @@ -5706,7 +5657,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_UNAME+set}" = set; then : +if ${ac_cv_path_UNAME+:} false; then : $as_echo_n "(cached) " >&6 else case $UNAME in @@ -5765,7 +5716,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_UNIQ+set}" = set; then : +if ${ac_cv_path_UNIQ+:} false; then : $as_echo_n "(cached) " >&6 else case $UNIQ in @@ -5824,7 +5775,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_WC+set}" = set; then : +if ${ac_cv_path_WC+:} false; then : $as_echo_n "(cached) " >&6 else case $WC in @@ -5883,7 +5834,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_WHICH+set}" = set; then : +if ${ac_cv_path_WHICH+:} false; then : $as_echo_n "(cached) " >&6 else case $WHICH in @@ -5942,7 +5893,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_XARGS+set}" = set; then : +if ${ac_cv_path_XARGS+:} false; then : $as_echo_n "(cached) " >&6 else case $XARGS in @@ -6002,7 +5953,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_AWK+set}" = set; then : +if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then @@ -6052,7 +6003,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if test "${ac_cv_path_GREP+set}" = set; then : +if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then @@ -6127,7 +6078,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } -if test "${ac_cv_path_EGREP+set}" = set; then : +if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 @@ -6206,7 +6157,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } -if test "${ac_cv_path_FGREP+set}" = set; then : +if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 @@ -6285,7 +6236,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } -if test "${ac_cv_path_SED+set}" = set; then : +if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ @@ -6371,7 +6322,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_NAWK+set}" = set; then : +if ${ac_cv_path_NAWK+:} false; then : $as_echo_n "(cached) " >&6 else case $NAWK in @@ -6426,12 +6377,16 @@ # Always force rm. RM="$RM -f" +# pwd behaves differently on various platforms and some don't support the -L flag. +# Always use the bash builtin pwd to get uniform behavior. +THEPWDCMD=pwd + # These are not required on all platforms # Extract the first word of "cygpath", so it can be a program name with args. set dummy cygpath; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CYGPATH+set}" = set; then : +if ${ac_cv_path_CYGPATH+:} false; then : $as_echo_n "(cached) " >&6 else case $CYGPATH in @@ -6471,7 +6426,7 @@ set dummy readlink; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_READLINK+set}" = set; then : +if ${ac_cv_path_READLINK+:} false; then : $as_echo_n "(cached) " >&6 else case $READLINK in @@ -6511,7 +6466,7 @@ set dummy df; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_DF+set}" = set; then : +if ${ac_cv_path_DF+:} false; then : $as_echo_n "(cached) " >&6 else case $DF in @@ -6551,7 +6506,7 @@ set dummy SetFile; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_SETFILE+set}" = set; then : +if ${ac_cv_path_SETFILE+:} false; then : $as_echo_n "(cached) " >&6 else case $SETFILE in @@ -6597,7 +6552,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } -if test "${ac_cv_build+set}" = set; then : +if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias @@ -6613,7 +6568,7 @@ $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; -*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5 ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' @@ -6631,7 +6586,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } -if test "${ac_cv_host+set}" = set; then : +if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then @@ -6646,7 +6601,7 @@ $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; -*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5 ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' @@ -6664,7 +6619,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 $as_echo_n "checking target system type... " >&6; } -if test "${ac_cv_target+set}" = set; then : +if ${ac_cv_target+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$target_alias" = x; then @@ -6679,7 +6634,7 @@ $as_echo "$ac_cv_target" >&6; } case $ac_cv_target in *-*-*) ;; -*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5 ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; esac target=$ac_cv_target ac_save_IFS=$IFS; IFS='-' @@ -7133,65 +7088,17 @@ # Locate the directory of this script. SCRIPT="$0" - - if test "x$OPENJDK_BUILD_OS" != xwindows; then - # Follow a chain of symbolic links. Use readlink - # where it exists, else fall back to horribly - # complicated shell code. - if test "x$READLINK_TESTED" != yes; then - # On MacOSX there is a readlink tool with a different - # purpose than the GNU readlink tool. Check the found readlink. - ISGNU=`$READLINK --version 2>&1 | $GREP GNU` - if test "x$ISGNU" = x; then - # A readlink that we do not know how to use. - # Are there other non-GNU readlinks out there? - READLINK_TESTED=yes - READLINK= - fi - fi - - if test "x$READLINK" != x; then - SCRIPT=`$READLINK -f $SCRIPT` - else - # Save the current directory for restoring afterwards - STARTDIR=$PWD - COUNTER=0 - sym_link_dir=`$DIRNAME $SCRIPT` - sym_link_file=`$BASENAME $SCRIPT` - # Use the system pwd and not the shell builtin to resolve directory symlinks - cd $sym_link_dir - cd `$THEPWDCMD` - sym_link_dir=`$THEPWDCMD` - # Resolve file symlinks - while test $COUNTER -lt 20; do - ISLINK=`$LS -l $sym_link_dir/$sym_link_file | $GREP '\->' | $SED -e 's/.*-> \(.*\)/\1/'` - if test "x$ISLINK" == x; then - # This is not a symbolic link! We are done! - break - fi - # Again resolve directory symlinks since the target of the just found - # link could be in a different directory - cd `$DIRNAME $ISLINK` - sym_link_dir=`$THEPWDCMD` - sym_link_file=`$BASENAME $ISLINK` - let COUNTER=COUNTER+1 - done - cd $STARTDIR - SCRIPT=$sym_link_dir/$sym_link_file - fi - fi - -AUTOCONF_DIR=`cd \`$DIRNAME $SCRIPT\`; $THEPWDCMD` +AUTOCONF_DIR=`cd \`$DIRNAME $SCRIPT\`; $THEPWDCMD -L` # Where is the source? It is located two levels above the configure script. CURDIR="$PWD" cd "$AUTOCONF_DIR/../.." -SRC_ROOT="`$THEPWDCMD`" +SRC_ROOT="`$THEPWDCMD -L`" if test "x$OPENJDK_TARGET_OS" = "xwindows"; then PATH_SEP=";" - SRC_ROOT_LENGTH=`$THEPWDCMD|$WC -m` + SRC_ROOT_LENGTH=`$THEPWDCMD -L|$WC -m` if test $SRC_ROOT_LENGTH -gt 100; then as_fn_error $? "Your base path is too long. It is $SRC_ROOT_LENGTH characters long, but only 100 is supported" "$LINENO" 5 fi @@ -7407,7 +7314,7 @@ as_fn_error $? "The path of SRC_ROOT, which resolves as \"$path\", is not found." "$LINENO" 5 fi - SRC_ROOT="`cd "$path"; $THEPWDCMD`" + SRC_ROOT="`cd "$path"; $THEPWDCMD -L`" fi @@ -7529,7 +7436,7 @@ as_fn_error $? "The path of CURDIR, which resolves as \"$path\", is not found." "$LINENO" 5 fi - CURDIR="`cd "$path"; $THEPWDCMD`" + CURDIR="`cd "$path"; $THEPWDCMD -L`" fi @@ -7900,60 +7807,9 @@ # Test from where we are running configure, in or outside of src root. -# To enable comparison of directories, CURDIR needs to be symlink free -# just like SRC_ROOT already is -NOSYM_CURDIR="$CURDIR" - - if test "x$OPENJDK_BUILD_OS" != xwindows; then - # Follow a chain of symbolic links. Use readlink - # where it exists, else fall back to horribly - # complicated shell code. - if test "x$READLINK_TESTED" != yes; then - # On MacOSX there is a readlink tool with a different - # purpose than the GNU readlink tool. Check the found readlink. - ISGNU=`$READLINK --version 2>&1 | $GREP GNU` - if test "x$ISGNU" = x; then - # A readlink that we do not know how to use. - # Are there other non-GNU readlinks out there? - READLINK_TESTED=yes - READLINK= - fi - fi - - if test "x$READLINK" != x; then - NOSYM_CURDIR=`$READLINK -f $NOSYM_CURDIR` - else - # Save the current directory for restoring afterwards - STARTDIR=$PWD - COUNTER=0 - sym_link_dir=`$DIRNAME $NOSYM_CURDIR` - sym_link_file=`$BASENAME $NOSYM_CURDIR` - # Use the system pwd and not the shell builtin to resolve directory symlinks - cd $sym_link_dir - cd `$THEPWDCMD` - sym_link_dir=`$THEPWDCMD` - # Resolve file symlinks - while test $COUNTER -lt 20; do - ISLINK=`$LS -l $sym_link_dir/$sym_link_file | $GREP '\->' | $SED -e 's/.*-> \(.*\)/\1/'` - if test "x$ISLINK" == x; then - # This is not a symbolic link! We are done! - break - fi - # Again resolve directory symlinks since the target of the just found - # link could be in a different directory - cd `$DIRNAME $ISLINK` - sym_link_dir=`$THEPWDCMD` - sym_link_file=`$BASENAME $ISLINK` - let COUNTER=COUNTER+1 - done - cd $STARTDIR - NOSYM_CURDIR=$sym_link_dir/$sym_link_file - fi - fi - -if test "x$NOSYM_CURDIR" = "x$SRC_ROOT" || test "x$NOSYM_CURDIR" = "x$SRC_ROOT/common" \ - || test "x$NOSYM_CURDIR" = "x$SRC_ROOT/common/autoconf" \ - || test "x$NOSYM_CURDIR" = "x$SRC_ROOT/common/makefiles" ; then +if test "x$CURDIR" = "x$SRC_ROOT" || test "x$CURDIR" = "x$SRC_ROOT/common" \ + || test "x$CURDIR" = "x$SRC_ROOT/common/autoconf" \ + || test "x$CURDIR" = "x$SRC_ROOT/common/makefiles" ; then # We are running configure from the src root. # Create a default ./build/target-variant-debuglevel output root. if test "x${CONF_NAME}" = x; then @@ -8128,7 +7984,7 @@ as_fn_error $? "The path of OUTPUT_ROOT, which resolves as \"$path\", is not found." "$LINENO" 5 fi - OUTPUT_ROOT="`cd "$path"; $THEPWDCMD`" + OUTPUT_ROOT="`cd "$path"; $THEPWDCMD -L`" fi @@ -8175,7 +8031,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_PKGHANDLER+set}" = set; then : +if ${ac_cv_prog_PKGHANDLER+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$PKGHANDLER"; then @@ -8540,7 +8396,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CHECK_GMAKE+set}" = set; then : +if ${ac_cv_path_CHECK_GMAKE+:} false; then : $as_echo_n "(cached) " >&6 else case $CHECK_GMAKE in @@ -8894,7 +8750,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CHECK_MAKE+set}" = set; then : +if ${ac_cv_path_CHECK_MAKE+:} false; then : $as_echo_n "(cached) " >&6 else case $CHECK_MAKE in @@ -9253,7 +9109,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CHECK_TOOLSDIR_GMAKE+set}" = set; then : +if ${ac_cv_path_CHECK_TOOLSDIR_GMAKE+:} false; then : $as_echo_n "(cached) " >&6 else case $CHECK_TOOLSDIR_GMAKE in @@ -9606,7 +9462,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CHECK_TOOLSDIR_MAKE+set}" = set; then : +if ${ac_cv_path_CHECK_TOOLSDIR_MAKE+:} false; then : $as_echo_n "(cached) " >&6 else case $CHECK_TOOLSDIR_MAKE in @@ -10002,7 +9858,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_UNZIP+set}" = set; then : +if ${ac_cv_path_UNZIP+:} false; then : $as_echo_n "(cached) " >&6 else case $UNZIP in @@ -10061,7 +9917,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_ZIP+set}" = set; then : +if ${ac_cv_path_ZIP+:} false; then : $as_echo_n "(cached) " >&6 else case $ZIP in @@ -10120,7 +9976,7 @@ set dummy ldd; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_LDD+set}" = set; then : +if ${ac_cv_path_LDD+:} false; then : $as_echo_n "(cached) " >&6 else case $LDD in @@ -10166,7 +10022,7 @@ set dummy otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_OTOOL+set}" = set; then : +if ${ac_cv_path_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else case $OTOOL in @@ -10211,7 +10067,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_READELF+set}" = set; then : +if ${ac_cv_path_READELF+:} false; then : $as_echo_n "(cached) " >&6 else case $READELF in @@ -10254,7 +10110,7 @@ set dummy hg; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_HG+set}" = set; then : +if ${ac_cv_path_HG+:} false; then : $as_echo_n "(cached) " >&6 else case $HG in @@ -10294,7 +10150,7 @@ set dummy stat; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_STAT+set}" = set; then : +if ${ac_cv_path_STAT+:} false; then : $as_echo_n "(cached) " >&6 else case $STAT in @@ -10334,7 +10190,7 @@ set dummy time; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_TIME+set}" = set; then : +if ${ac_cv_path_TIME+:} false; then : $as_echo_n "(cached) " >&6 else case $TIME in @@ -10379,7 +10235,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_COMM+set}" = set; then : +if ${ac_cv_path_COMM+:} false; then : $as_echo_n "(cached) " >&6 else case $COMM in @@ -10441,7 +10297,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_XATTR+set}" = set; then : +if ${ac_cv_path_XATTR+:} false; then : $as_echo_n "(cached) " >&6 else case $XATTR in @@ -10493,6 +10349,62 @@ fi + # Extract the first word of "codesign", so it can be a program name with args. +set dummy codesign; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_CODESIGN+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $CODESIGN in + [\\/]* | ?:[\\/]*) + ac_cv_path_CODESIGN="$CODESIGN" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_CODESIGN="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +CODESIGN=$ac_cv_path_CODESIGN +if test -n "$CODESIGN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CODESIGN" >&5 +$as_echo "$CODESIGN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$CODESIGN" != "x"; then + # Verify that the openjdk_codesign certificate is present + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if openjdk_codesign certificate is present" >&5 +$as_echo_n "checking if openjdk_codesign certificate is present... " >&6; } + rm -f codesign-testfile + touch codesign-testfile + codesign -s openjdk_codesign codesign-testfile 2>&5 >&5 || CODESIGN= + rm -f codesign-testfile + if test "x$CODESIGN" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + fi + fi fi @@ -10505,7 +10417,7 @@ set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_PKG_CONFIG+set}" = set; then : +if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in @@ -10548,7 +10460,7 @@ set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then : +if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in @@ -10721,7 +10633,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_BDEPS_UNZIP+set}" = set; then : +if ${ac_cv_prog_BDEPS_UNZIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$BDEPS_UNZIP"; then @@ -10767,7 +10679,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_BDEPS_FTP+set}" = set; then : +if ${ac_cv_prog_BDEPS_FTP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$BDEPS_FTP"; then @@ -10939,6 +10851,18 @@ fi +# Check whether --with-update-version was given. +if test "${with_update_version+set}" = set; then : + withval=$with_update_version; +fi + +if test "x$with_update_version" = xyes; then + as_fn_error $? "Update version must have a value" "$LINENO" 5 +elif test "x$with_update_version" != x; then + JDK_UPDATE_VERSION="$with_update_version" +fi + + # Check whether --with-build-number was given. if test "${with_build_number+set}" = set; then : withval=$with_build_number; @@ -11188,7 +11112,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -11520,7 +11444,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -11666,7 +11590,7 @@ as_fn_error $? "The path of JAVA_HOME_PROCESSED, which resolves as \"$path\", is not found." "$LINENO" 5 fi - JAVA_HOME_PROCESSED="`cd "$path"; $THEPWDCMD`" + JAVA_HOME_PROCESSED="`cd "$path"; $THEPWDCMD -L`" fi if test ! -d "$JAVA_HOME_PROCESSED"; then @@ -11838,7 +11762,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -12026,7 +11950,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -12055,7 +11979,7 @@ set dummy javac; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_JAVAC_CHECK+set}" = set; then : +if ${ac_cv_path_JAVAC_CHECK+:} false; then : $as_echo_n "(cached) " >&6 else case $JAVAC_CHECK in @@ -12095,7 +12019,7 @@ set dummy java; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_JAVA_CHECK+set}" = set; then : +if ${ac_cv_path_JAVA_CHECK+:} false; then : $as_echo_n "(cached) " >&6 else case $JAVA_CHECK in @@ -12165,10 +12089,10 @@ COUNTER=0 sym_link_dir=`$DIRNAME $BINARY` sym_link_file=`$BASENAME $BINARY` - # Use the system pwd and not the shell builtin to resolve directory symlinks cd $sym_link_dir - cd `$THEPWDCMD` - sym_link_dir=`$THEPWDCMD` + # Use -P flag to resolve symlinks in directories. + cd `$THEPWDCMD -P` + sym_link_dir=`$THEPWDCMD -P` # Resolve file symlinks while test $COUNTER -lt 20; do ISLINK=`$LS -l $sym_link_dir/$sym_link_file | $GREP '\->' | $SED -e 's/.*-> \(.*\)/\1/'` @@ -12179,7 +12103,7 @@ # Again resolve directory symlinks since the target of the just found # link could be in a different directory cd `$DIRNAME $ISLINK` - sym_link_dir=`$THEPWDCMD` + sym_link_dir=`$THEPWDCMD -P` sym_link_file=`$BASENAME $ISLINK` let COUNTER=COUNTER+1 done @@ -12354,7 +12278,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -12569,7 +12493,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -12749,7 +12673,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -12957,7 +12881,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -13137,7 +13061,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -13345,7 +13269,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -13525,7 +13449,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -13733,7 +13657,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -13913,7 +13837,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -14108,7 +14032,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -14286,7 +14210,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -14482,7 +14406,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -14660,7 +14584,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -14855,7 +14779,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -15033,7 +14957,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -15229,7 +15153,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -15407,7 +15331,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -15584,7 +15508,7 @@ as_fn_error $? "The path of BOOT_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 fi - BOOT_JDK="`cd "$path"; $THEPWDCMD`" + BOOT_JDK="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boot JDK" >&5 @@ -16261,14 +16185,28 @@ # Check whether --with-jtreg was given. if test "${with_jtreg+set}" = set; then : withval=$with_jtreg; -fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for JTReg Regression Test Harness" >&5 -$as_echo_n "checking for JTReg Regression Test Harness... " >&6; } - - if test "x$with_jtreg" != x; then - JT_HOME="$with_jtreg" +else + with_jtreg=no +fi + + + if test "x$with_jtreg" = xno; then + # jtreg disabled + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jtreg" >&5 +$as_echo_n "checking for jtreg... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + else + if test "x$with_jtreg" != xyes; then + # with path specified. + JT_HOME="$with_jtreg" + fi + + if test "x$JT_HOME" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jtreg" >&5 +$as_echo_n "checking for jtreg... " >&6; } + + # use JT_HOME enviroment var. if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then @@ -16388,20 +16326,82 @@ as_fn_error $? "The path of JT_HOME, which resolves as \"$path\", is not found." "$LINENO" 5 fi - JT_HOME="`cd "$path"; $THEPWDCMD`" - fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JT_HOME" >&5 -$as_echo "$JT_HOME" >&6; } - - # jtreg win32 script works for everybody - JTREGEXE="$JT_HOME/win32/bin/jtreg" - if test ! -f "$JTREGEXE"; then - as_fn_error $? "JTReg executable does not exist: $JTREGEXE" "$LINENO" 5 - fi - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + JT_HOME="`cd "$path"; $THEPWDCMD -L`" + fi + + + # jtreg win32 script works for everybody + JTREGEXE="$JT_HOME/win32/bin/jtreg" + + if test ! -f "$JTREGEXE"; then + as_fn_error $? "JTReg executable does not exist: $JTREGEXE" "$LINENO" 5 + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JTREGEXE" >&5 +$as_echo "$JTREGEXE" >&6; } + else + # try to find jtreg on path + + for ac_prog in jtreg +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_JTREGEXE+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $JTREGEXE in + [\\/]* | ?:[\\/]*) + ac_cv_path_JTREGEXE="$JTREGEXE" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_JTREGEXE="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +JTREGEXE=$ac_cv_path_JTREGEXE +if test -n "$JTREGEXE"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JTREGEXE" >&5 +$as_echo "$JTREGEXE" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$JTREGEXE" && break +done + + + if test "x$JTREGEXE" = x; then + if test "xjtreg" = x; then + PROG_NAME=jtregexe + else + PROG_NAME=jtreg + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $PROG_NAME!" >&5 +$as_echo "$as_me: Could not find $PROG_NAME!" >&6;} + as_fn_error $? "Cannot continue" "$LINENO" 5 + fi + + + JT_HOME="`$DIRNAME $JTREGEXE`" + fi fi @@ -16416,7 +16416,7 @@ set dummy link; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CYGWIN_LINK+set}" = set; then : +if ${ac_cv_path_CYGWIN_LINK+:} false; then : $as_echo_n "(cached) " >&6 else case $CYGWIN_LINK in @@ -17377,7 +17377,7 @@ as_fn_error $? "The path of MSVCR_DLL, which resolves as \"$path\", is not found." "$LINENO" 5 fi - MSVCR_DLL="`cd "$path"; $THEPWDCMD`" + MSVCR_DLL="`cd "$path"; $THEPWDCMD -L`" fi @@ -17534,7 +17534,7 @@ as_fn_error $? "The path of dxsdk_path, which resolves as \"$path\", is not found." "$LINENO" 5 fi - dxsdk_path="`cd "$path"; $THEPWDCMD`" + dxsdk_path="`cd "$path"; $THEPWDCMD -L`" fi @@ -17672,7 +17672,7 @@ 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`" + DXSDK_LIB_PATH="`cd "$path"; $THEPWDCMD -L`" fi @@ -17808,7 +17808,7 @@ 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`" + DXSDK_INCLUDE_PATH="`cd "$path"; $THEPWDCMD -L`" fi @@ -17843,7 +17843,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_BUILD_CC+set}" = set; then : +if ${ac_cv_path_BUILD_CC+:} false; then : $as_echo_n "(cached) " >&6 else case $BUILD_CC in @@ -18154,7 +18154,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_BUILD_CXX+set}" = set; then : +if ${ac_cv_path_BUILD_CXX+:} false; then : $as_echo_n "(cached) " >&6 else case $BUILD_CXX in @@ -18463,7 +18463,7 @@ set dummy ld; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_BUILD_LD+set}" = set; then : +if ${ac_cv_path_BUILD_LD+:} false; then : $as_echo_n "(cached) " >&6 else case $BUILD_LD in @@ -18979,7 +18979,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_TOOLS_DIR_CC+set}" = set; then : +if ${ac_cv_path_TOOLS_DIR_CC+:} false; then : $as_echo_n "(cached) " >&6 else case $TOOLS_DIR_CC in @@ -19031,7 +19031,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_POTENTIAL_CC+set}" = set; then : +if ${ac_cv_path_POTENTIAL_CC+:} false; then : $as_echo_n "(cached) " >&6 else case $POTENTIAL_CC in @@ -19395,10 +19395,10 @@ COUNTER=0 sym_link_dir=`$DIRNAME $TEST_COMPILER` sym_link_file=`$BASENAME $TEST_COMPILER` - # Use the system pwd and not the shell builtin to resolve directory symlinks cd $sym_link_dir - cd `$THEPWDCMD` - sym_link_dir=`$THEPWDCMD` + # Use -P flag to resolve symlinks in directories. + cd `$THEPWDCMD -P` + sym_link_dir=`$THEPWDCMD -P` # Resolve file symlinks while test $COUNTER -lt 20; do ISLINK=`$LS -l $sym_link_dir/$sym_link_file | $GREP '\->' | $SED -e 's/.*-> \(.*\)/\1/'` @@ -19409,7 +19409,7 @@ # Again resolve directory symlinks since the target of the just found # link could be in a different directory cd `$DIRNAME $ISLINK` - sym_link_dir=`$THEPWDCMD` + sym_link_dir=`$THEPWDCMD -P` sym_link_file=`$BASENAME $ISLINK` let COUNTER=COUNTER+1 done @@ -19444,7 +19444,7 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_PROPER_COMPILER_CC+set}" = set; then : +if ${ac_cv_prog_PROPER_COMPILER_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$PROPER_COMPILER_CC"; then @@ -19488,7 +19488,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_PROPER_COMPILER_CC+set}" = set; then : +if ${ac_cv_prog_ac_ct_PROPER_COMPILER_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_PROPER_COMPILER_CC"; then @@ -19832,10 +19832,10 @@ COUNTER=0 sym_link_dir=`$DIRNAME $PROPER_COMPILER_CC` sym_link_file=`$BASENAME $PROPER_COMPILER_CC` - # Use the system pwd and not the shell builtin to resolve directory symlinks cd $sym_link_dir - cd `$THEPWDCMD` - sym_link_dir=`$THEPWDCMD` + # Use -P flag to resolve symlinks in directories. + cd `$THEPWDCMD -P` + sym_link_dir=`$THEPWDCMD -P` # Resolve file symlinks while test $COUNTER -lt 20; do ISLINK=`$LS -l $sym_link_dir/$sym_link_file | $GREP '\->' | $SED -e 's/.*-> \(.*\)/\1/'` @@ -19846,7 +19846,7 @@ # Again resolve directory symlinks since the target of the just found # link could be in a different directory cd `$DIRNAME $ISLINK` - sym_link_dir=`$THEPWDCMD` + sym_link_dir=`$THEPWDCMD -P` sym_link_file=`$BASENAME $ISLINK` let COUNTER=COUNTER+1 done @@ -19938,7 +19938,7 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -19982,7 +19982,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : +if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -20035,7 +20035,7 @@ test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 @@ -20150,7 +20150,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } @@ -20193,7 +20193,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 @@ -20252,7 +20252,7 @@ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi fi fi @@ -20263,7 +20263,7 @@ ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } -if test "${ac_cv_objext+set}" = set; then : +if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -20304,7 +20304,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi @@ -20314,7 +20314,7 @@ ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if test "${ac_cv_c_compiler_gnu+set}" = set; then : +if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -20351,7 +20351,7 @@ ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } -if test "${ac_cv_prog_cc_g+set}" = set; then : +if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag @@ -20429,7 +20429,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if test "${ac_cv_prog_cc_c89+set}" = set; then : +if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no @@ -20552,7 +20552,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_TOOLS_DIR_CXX+set}" = set; then : +if ${ac_cv_path_TOOLS_DIR_CXX+:} false; then : $as_echo_n "(cached) " >&6 else case $TOOLS_DIR_CXX in @@ -20604,7 +20604,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_POTENTIAL_CXX+set}" = set; then : +if ${ac_cv_path_POTENTIAL_CXX+:} false; then : $as_echo_n "(cached) " >&6 else case $POTENTIAL_CXX in @@ -20968,10 +20968,10 @@ COUNTER=0 sym_link_dir=`$DIRNAME $TEST_COMPILER` sym_link_file=`$BASENAME $TEST_COMPILER` - # Use the system pwd and not the shell builtin to resolve directory symlinks cd $sym_link_dir - cd `$THEPWDCMD` - sym_link_dir=`$THEPWDCMD` + # Use -P flag to resolve symlinks in directories. + cd `$THEPWDCMD -P` + sym_link_dir=`$THEPWDCMD -P` # Resolve file symlinks while test $COUNTER -lt 20; do ISLINK=`$LS -l $sym_link_dir/$sym_link_file | $GREP '\->' | $SED -e 's/.*-> \(.*\)/\1/'` @@ -20982,7 +20982,7 @@ # Again resolve directory symlinks since the target of the just found # link could be in a different directory cd `$DIRNAME $ISLINK` - sym_link_dir=`$THEPWDCMD` + sym_link_dir=`$THEPWDCMD -P` sym_link_file=`$BASENAME $ISLINK` let COUNTER=COUNTER+1 done @@ -21017,7 +21017,7 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_PROPER_COMPILER_CXX+set}" = set; then : +if ${ac_cv_prog_PROPER_COMPILER_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$PROPER_COMPILER_CXX"; then @@ -21061,7 +21061,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_PROPER_COMPILER_CXX+set}" = set; then : +if ${ac_cv_prog_ac_ct_PROPER_COMPILER_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_PROPER_COMPILER_CXX"; then @@ -21405,10 +21405,10 @@ COUNTER=0 sym_link_dir=`$DIRNAME $PROPER_COMPILER_CXX` sym_link_file=`$BASENAME $PROPER_COMPILER_CXX` - # Use the system pwd and not the shell builtin to resolve directory symlinks cd $sym_link_dir - cd `$THEPWDCMD` - sym_link_dir=`$THEPWDCMD` + # Use -P flag to resolve symlinks in directories. + cd `$THEPWDCMD -P` + sym_link_dir=`$THEPWDCMD -P` # Resolve file symlinks while test $COUNTER -lt 20; do ISLINK=`$LS -l $sym_link_dir/$sym_link_file | $GREP '\->' | $SED -e 's/.*-> \(.*\)/\1/'` @@ -21419,7 +21419,7 @@ # Again resolve directory symlinks since the target of the just found # link could be in a different directory cd `$DIRNAME $ISLINK` - sym_link_dir=`$THEPWDCMD` + sym_link_dir=`$THEPWDCMD -P` sym_link_file=`$BASENAME $ISLINK` let COUNTER=COUNTER+1 done @@ -21515,7 +21515,7 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CXX+set}" = set; then : +if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then @@ -21559,7 +21559,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : +if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then @@ -21637,7 +21637,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } -if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : +if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -21674,7 +21674,7 @@ ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } -if test "${ac_cv_prog_cxx_g+set}" = set; then : +if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag @@ -21772,7 +21772,7 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_OBJC+set}" = set; then : +if ${ac_cv_prog_OBJC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJC"; then @@ -21816,7 +21816,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_OBJC+set}" = set; then : +if ${ac_cv_prog_ac_ct_OBJC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJC"; then @@ -21892,7 +21892,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU Objective C compiler" >&5 $as_echo_n "checking whether we are using the GNU Objective C compiler... " >&6; } -if test "${ac_cv_objc_compiler_gnu+set}" = set; then : +if ${ac_cv_objc_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -21929,7 +21929,7 @@ ac_save_OBJCFLAGS=$OBJCFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $OBJC accepts -g" >&5 $as_echo_n "checking whether $OBJC accepts -g... " >&6; } -if test "${ac_cv_prog_objc_g+set}" = set; then : +if ${ac_cv_prog_objc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_objc_werror_flag=$ac_objc_werror_flag @@ -22305,7 +22305,7 @@ set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_AR+set}" = set; then : +if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then @@ -22345,7 +22345,7 @@ set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_AR+set}" = set; then : +if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then @@ -22687,7 +22687,7 @@ set dummy link; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_WINLD+set}" = set; then : +if ${ac_cv_prog_WINLD+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$WINLD"; then @@ -23026,7 +23026,7 @@ set dummy mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_MT+set}" = set; then : +if ${ac_cv_prog_MT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MT"; then @@ -23347,7 +23347,7 @@ set dummy rc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_RC+set}" = set; then : +if ${ac_cv_prog_RC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RC"; then @@ -23738,7 +23738,7 @@ set dummy lib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_WINAR+set}" = set; then : +if ${ac_cv_prog_WINAR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$WINAR"; then @@ -24044,7 +24044,7 @@ set dummy dumpbin; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_DUMPBIN+set}" = set; then : +if ${ac_cv_prog_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then @@ -24363,7 +24363,7 @@ CPP= fi if test -z "$CPP"; then - if test "${ac_cv_prog_CPP+set}" = set; then : + if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded @@ -24479,7 +24479,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=cpp @@ -24763,7 +24763,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 $as_echo_n "checking how to run the C++ preprocessor... " >&6; } if test -z "$CXXCPP"; then - if test "${ac_cv_prog_CXXCPP+set}" = set; then : + if ${ac_cv_prog_CXXCPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CXXCPP needs to be expanded @@ -24879,7 +24879,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=cpp @@ -25181,7 +25181,7 @@ set dummy as; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_AS+set}" = set; then : +if ${ac_cv_path_AS+:} false; then : $as_echo_n "(cached) " >&6 else case $AS in @@ -25493,7 +25493,7 @@ set dummy nm; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_NM+set}" = set; then : +if ${ac_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else case $NM in @@ -25799,7 +25799,7 @@ set dummy gnm; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_GNM+set}" = set; then : +if ${ac_cv_path_GNM+:} false; then : $as_echo_n "(cached) " >&6 else case $GNM in @@ -26105,7 +26105,7 @@ set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_STRIP+set}" = set; then : +if ${ac_cv_path_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else case $STRIP in @@ -26411,7 +26411,7 @@ set dummy mcs; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_MCS+set}" = set; then : +if ${ac_cv_path_MCS+:} false; then : $as_echo_n "(cached) " >&6 else case $MCS in @@ -26719,7 +26719,7 @@ set dummy ${ac_tool_prefix}nm; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_NM+set}" = set; then : +if ${ac_cv_prog_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then @@ -26759,7 +26759,7 @@ set dummy nm; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_NM+set}" = set; then : +if ${ac_cv_prog_ac_ct_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NM"; then @@ -27079,7 +27079,7 @@ set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_STRIP+set}" = set; then : +if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then @@ -27119,7 +27119,7 @@ set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then @@ -27444,7 +27444,7 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_OBJCOPY+set}" = set; then : +if ${ac_cv_prog_OBJCOPY+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJCOPY"; then @@ -27488,7 +27488,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_OBJCOPY+set}" = set; then : +if ${ac_cv_prog_ac_ct_OBJCOPY+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJCOPY"; then @@ -27815,7 +27815,7 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_OBJDUMP+set}" = set; then : +if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then @@ -27859,7 +27859,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then : +if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then @@ -28183,7 +28183,7 @@ set dummy lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_LIPO+set}" = set; then : +if ${ac_cv_path_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else case $LIPO in @@ -28500,7 +28500,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } -if test "${ac_cv_header_stdc+set}" = set; then : +if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -28677,7 +28677,7 @@ for ac_header in stdio.h do : ac_fn_cxx_check_header_mongrel "$LINENO" "stdio.h" "ac_cv_header_stdio_h" "$ac_includes_default" -if test "x$ac_cv_header_stdio_h" = x""yes; then : +if test "x$ac_cv_header_stdio_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STDIO_H 1 _ACEOF @@ -28706,7 +28706,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int *" >&5 $as_echo_n "checking size of int *... " >&6; } -if test "${ac_cv_sizeof_int_p+set}" = set; then : +if ${ac_cv_sizeof_int_p+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_cxx_compute_int "$LINENO" "(long int) (sizeof (int *))" "ac_cv_sizeof_int_p" "$ac_includes_default"; then : @@ -28716,7 +28716,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (int *) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int_p=0 fi @@ -28763,7 +28763,7 @@ # { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } -if test "${ac_cv_c_bigendian+set}" = set; then : +if ${ac_cv_c_bigendian+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown @@ -29930,8 +29930,8 @@ have_x=disabled else case $x_includes,$x_libraries in #( - *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5 ;; #( - *,NONE | NONE,*) if test "${ac_cv_have_x+set}" = set; then : + *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( + *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then : $as_echo_n "(cached) " >&6 else # One or both of the vars are not set, and there is no cached value. @@ -30208,7 +30208,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; } -if test "${ac_cv_lib_dnet_dnet_ntoa+set}" = set; then : +if ${ac_cv_lib_dnet_dnet_ntoa+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -30242,14 +30242,14 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; } -if test "x$ac_cv_lib_dnet_dnet_ntoa" = x""yes; then : +if test "x$ac_cv_lib_dnet_dnet_ntoa" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" fi if test $ac_cv_lib_dnet_dnet_ntoa = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; } -if test "${ac_cv_lib_dnet_stub_dnet_ntoa+set}" = set; then : +if ${ac_cv_lib_dnet_stub_dnet_ntoa+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -30283,7 +30283,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; } -if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = x""yes; then : +if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" fi @@ -30302,14 +30302,14 @@ # The functions gethostbyname, getservbyname, and inet_addr are # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. ac_fn_cxx_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" -if test "x$ac_cv_func_gethostbyname" = x""yes; then : +if test "x$ac_cv_func_gethostbyname" = xyes; then : fi if test $ac_cv_func_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; } -if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then : +if ${ac_cv_lib_nsl_gethostbyname+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -30343,14 +30343,14 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 $as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } -if test "x$ac_cv_lib_nsl_gethostbyname" = x""yes; then : +if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" fi if test $ac_cv_lib_nsl_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5 $as_echo_n "checking for gethostbyname in -lbsd... " >&6; } -if test "${ac_cv_lib_bsd_gethostbyname+set}" = set; then : +if ${ac_cv_lib_bsd_gethostbyname+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -30384,7 +30384,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5 $as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; } -if test "x$ac_cv_lib_bsd_gethostbyname" = x""yes; then : +if test "x$ac_cv_lib_bsd_gethostbyname" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" fi @@ -30399,14 +30399,14 @@ # must be given before -lnsl if both are needed. We assume that # if connect needs -lnsl, so does gethostbyname. ac_fn_cxx_check_func "$LINENO" "connect" "ac_cv_func_connect" -if test "x$ac_cv_func_connect" = x""yes; then : +if test "x$ac_cv_func_connect" = xyes; then : fi if test $ac_cv_func_connect = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 $as_echo_n "checking for connect in -lsocket... " >&6; } -if test "${ac_cv_lib_socket_connect+set}" = set; then : +if ${ac_cv_lib_socket_connect+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -30440,7 +30440,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5 $as_echo "$ac_cv_lib_socket_connect" >&6; } -if test "x$ac_cv_lib_socket_connect" = x""yes; then : +if test "x$ac_cv_lib_socket_connect" = xyes; then : X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" fi @@ -30448,14 +30448,14 @@ # Guillermo Gomez says -lposix is necessary on A/UX. ac_fn_cxx_check_func "$LINENO" "remove" "ac_cv_func_remove" -if test "x$ac_cv_func_remove" = x""yes; then : +if test "x$ac_cv_func_remove" = xyes; then : fi if test $ac_cv_func_remove = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5 $as_echo_n "checking for remove in -lposix... " >&6; } -if test "${ac_cv_lib_posix_remove+set}" = set; then : +if ${ac_cv_lib_posix_remove+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -30489,7 +30489,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5 $as_echo "$ac_cv_lib_posix_remove" >&6; } -if test "x$ac_cv_lib_posix_remove" = x""yes; then : +if test "x$ac_cv_lib_posix_remove" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" fi @@ -30497,14 +30497,14 @@ # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. ac_fn_cxx_check_func "$LINENO" "shmat" "ac_cv_func_shmat" -if test "x$ac_cv_func_shmat" = x""yes; then : +if test "x$ac_cv_func_shmat" = xyes; then : fi if test $ac_cv_func_shmat = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5 $as_echo_n "checking for shmat in -lipc... " >&6; } -if test "${ac_cv_lib_ipc_shmat+set}" = set; then : +if ${ac_cv_lib_ipc_shmat+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -30538,7 +30538,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5 $as_echo "$ac_cv_lib_ipc_shmat" >&6; } -if test "x$ac_cv_lib_ipc_shmat" = x""yes; then : +if test "x$ac_cv_lib_ipc_shmat" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" fi @@ -30556,7 +30556,7 @@ # John Interrante, Karl Berry { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5 $as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; } -if test "${ac_cv_lib_ICE_IceConnectionNumber+set}" = set; then : +if ${ac_cv_lib_ICE_IceConnectionNumber+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -30590,7 +30590,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 $as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; } -if test "x$ac_cv_lib_ICE_IceConnectionNumber" = x""yes; then : +if test "x$ac_cv_lib_ICE_IceConnectionNumber" = xyes; then : X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" fi @@ -31131,7 +31131,7 @@ as_fn_error $? "The path of with_freetype, which resolves as \"$path\", is not found." "$LINENO" 5 fi - with_freetype="`cd "$path"; $THEPWDCMD`" + with_freetype="`cd "$path"; $THEPWDCMD -L`" fi FREETYPE2_LIBS="-L$with_freetype/lib -lfreetype" @@ -31433,7 +31433,7 @@ as_fn_error $? "The path of FREETYPELOCATION, which resolves as \"$path\", is not found." "$LINENO" 5 fi - FREETYPELOCATION="`cd "$path"; $THEPWDCMD`" + FREETYPELOCATION="`cd "$path"; $THEPWDCMD -L`" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype in some standard windows locations" >&5 @@ -31609,7 +31609,7 @@ LDFLAGS="$FREETYPE2_LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for FT_Init_FreeType in -lfreetype" >&5 $as_echo_n "checking for FT_Init_FreeType in -lfreetype... " >&6; } -if test "${ac_cv_lib_freetype_FT_Init_FreeType+set}" = set; then : +if ${ac_cv_lib_freetype_FT_Init_FreeType+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -31643,7 +31643,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_freetype_FT_Init_FreeType" >&5 $as_echo "$ac_cv_lib_freetype_FT_Init_FreeType" >&6; } -if test "x$ac_cv_lib_freetype_FT_Init_FreeType" = x""yes; then : +if test "x$ac_cv_lib_freetype_FT_Init_FreeType" = xyes; then : FREETYPE2_FOUND=true else as_fn_error $? "Could not find freetype2! $HELP_MSG " "$LINENO" 5 @@ -31931,7 +31931,7 @@ for ac_header in alsa/asoundlib.h do : ac_fn_cxx_check_header_mongrel "$LINENO" "alsa/asoundlib.h" "ac_cv_header_alsa_asoundlib_h" "$ac_includes_default" -if test "x$ac_cv_header_alsa_asoundlib_h" = x""yes; then : +if test "x$ac_cv_header_alsa_asoundlib_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_ALSA_ASOUNDLIB_H 1 _ACEOF @@ -31990,7 +31990,7 @@ USE_EXTERNAL_LIBJPEG=true { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -ljpeg" >&5 $as_echo_n "checking for main in -ljpeg... " >&6; } -if test "${ac_cv_lib_jpeg_main+set}" = set; then : +if ${ac_cv_lib_jpeg_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -32018,7 +32018,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jpeg_main" >&5 $as_echo "$ac_cv_lib_jpeg_main" >&6; } -if test "x$ac_cv_lib_jpeg_main" = x""yes; then : +if test "x$ac_cv_lib_jpeg_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBJPEG 1 _ACEOF @@ -32067,7 +32067,7 @@ USE_EXTERNAL_LIBGIF=false elif test "x${with_giflib}" = "xsystem"; then ac_fn_cxx_check_header_mongrel "$LINENO" "gif_lib.h" "ac_cv_header_gif_lib_h" "$ac_includes_default" -if test "x$ac_cv_header_gif_lib_h" = x""yes; then : +if test "x$ac_cv_header_gif_lib_h" = xyes; then : else as_fn_error $? "--with-giflib=system specified, but gif_lib.h not found!" "$LINENO" 5 @@ -32076,7 +32076,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DGifGetCode in -lgif" >&5 $as_echo_n "checking for DGifGetCode in -lgif... " >&6; } -if test "${ac_cv_lib_gif_DGifGetCode+set}" = set; then : +if ${ac_cv_lib_gif_DGifGetCode+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -32110,7 +32110,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gif_DGifGetCode" >&5 $as_echo "$ac_cv_lib_gif_DGifGetCode" >&6; } -if test "x$ac_cv_lib_gif_DGifGetCode" = x""yes; then : +if test "x$ac_cv_lib_gif_DGifGetCode" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBGIF 1 _ACEOF @@ -32142,7 +32142,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for compress in -lz" >&5 $as_echo_n "checking for compress in -lz... " >&6; } -if test "${ac_cv_lib_z_compress+set}" = set; then : +if ${ac_cv_lib_z_compress+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -32176,7 +32176,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_compress" >&5 $as_echo "$ac_cv_lib_z_compress" >&6; } -if test "x$ac_cv_lib_z_compress" = x""yes; then : +if test "x$ac_cv_lib_z_compress" = xyes; then : ZLIB_FOUND=yes else ZLIB_FOUND=no @@ -32269,7 +32269,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cos in -lm" >&5 $as_echo_n "checking for cos in -lm... " >&6; } -if test "${ac_cv_lib_m_cos+set}" = set; then : +if ${ac_cv_lib_m_cos+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -32303,7 +32303,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_cos" >&5 $as_echo "$ac_cv_lib_m_cos" >&6; } -if test "x$ac_cv_lib_m_cos" = x""yes; then : +if test "x$ac_cv_lib_m_cos" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBM 1 _ACEOF @@ -32327,7 +32327,7 @@ LIBS="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } -if test "${ac_cv_lib_dl_dlopen+set}" = set; then : +if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -32361,7 +32361,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDL 1 _ACEOF @@ -32591,7 +32591,7 @@ See the pkg-config man page for more details. To get pkg-config, see . -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else LIBFFI_CFLAGS=$pkg_cv_LIBFFI_CFLAGS LIBFFI_LIBS=$pkg_cv_LIBFFI_LIBS @@ -32607,7 +32607,7 @@ set dummy llvm-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_LLVM_CONFIG+set}" = set; then : +if ${ac_cv_prog_LLVM_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LLVM_CONFIG"; then @@ -32933,6 +32933,9 @@ if test "$JOBS" -gt "16"; then JOBS=16 fi + if test "$JOBS" -eq "0"; then + JOBS=1 + fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JOBS" >&5 $as_echo "$JOBS" >&6; } else @@ -33216,7 +33219,7 @@ set dummy ccache; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CCACHE+set}" = set; then : +if ${ac_cv_path_CCACHE+:} false; then : $as_echo_n "(cached) " >&6 else case $CCACHE in @@ -33477,10 +33480,21 @@ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then - test "x$cache_file" != "x/dev/null" && + if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} - cat confcache >$cache_file + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} @@ -33512,7 +33526,7 @@ -: ${CONFIG_STATUS=./config.status} +: "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" @@ -33613,6 +33627,7 @@ IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. +as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -33920,7 +33935,7 @@ # values after options handling. ac_log=" This file was extended by OpenJDK $as_me jdk8, which was -generated by GNU Autoconf 2.67. Invocation command line was +generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -33983,7 +33998,7 @@ ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ OpenJDK config.status jdk8 -configured by $0, generated by GNU Autoconf 2.67, +configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. @@ -34112,7 +34127,7 @@ "$OUTPUT_ROOT/spec.sh") CONFIG_FILES="$CONFIG_FILES $OUTPUT_ROOT/spec.sh:$AUTOCONF_DIR/spec.sh.in" ;; "$OUTPUT_ROOT/Makefile") CONFIG_FILES="$CONFIG_FILES $OUTPUT_ROOT/Makefile:$AUTOCONF_DIR/Makefile.in" ;; - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done @@ -34134,9 +34149,10 @@ # after its creation but before its name has been assigned to `$tmp'. $debug || { - tmp= + tmp= ac_tmp= trap 'exit_status=$? - { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } @@ -34144,12 +34160,13 @@ { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -n "$tmp" && test -d "$tmp" + test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. @@ -34171,7 +34188,7 @@ ac_cs_awk_cr=$ac_cr fi -echo 'BEGIN {' >"$tmp/subs1.awk" && +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF @@ -34199,7 +34216,7 @@ rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h @@ -34247,7 +34264,7 @@ rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK -cat >>"\$tmp/subs1.awk" <<_ACAWK && +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" @@ -34279,7 +34296,7 @@ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat -fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF @@ -34313,7 +34330,7 @@ # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then -cat >"$tmp/defines.awk" <<\_ACAWK || +cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF @@ -34325,8 +34342,8 @@ # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do - ac_t=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_t"; then + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 @@ -34427,7 +34444,7 @@ esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac @@ -34446,7 +34463,7 @@ for ac_f do case $ac_f in - -) ac_f="$tmp/stdin";; + -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. @@ -34455,7 +34472,7 @@ [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" @@ -34481,8 +34498,8 @@ esac case $ac_tag in - *:-:* | *:-) cat >"$tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac @@ -34607,21 +34624,22 @@ s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} - rm -f "$tmp/stdin" + rm -f "$ac_tmp/stdin" case $ac_file in - -) cat "$tmp/out" && rm -f "$tmp/out";; - *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; @@ -34632,20 +34650,20 @@ if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" - } >"$tmp/config.h" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" - mv "$tmp/config.h" "$ac_file" \ + mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; diff -r a233c04832cf -r a08d0f5b08bc common/autoconf/jdk-options.m4 --- a/common/autoconf/jdk-options.m4 Thu May 30 10:58:13 2013 -0700 +++ b/common/autoconf/jdk-options.m4 Wed Jul 05 18:57:52 2017 +0200 @@ -422,6 +422,14 @@ MILESTONE=internal fi +AC_ARG_WITH(update-version, [AS_HELP_STRING([--with-update-version], + [Set update version value for build @<:@b00@:>@])]) +if test "x$with_update_version" = xyes; then + AC_MSG_ERROR([Update version must have a value]) +elif test "x$with_update_version" != x; then + JDK_UPDATE_VERSION="$with_update_version" +fi + AC_ARG_WITH(build-number, [AS_HELP_STRING([--with-build-number], [Set build number value for build @<:@b00@:>@])]) if test "x$with_build_number" = xyes; then diff -r a233c04832cf -r a08d0f5b08bc common/autoconf/spec.gmk.in --- a/common/autoconf/spec.gmk.in Thu May 30 10:58:13 2013 -0700 +++ b/common/autoconf/spec.gmk.in Wed Jul 05 18:57:52 2017 +0200 @@ -478,6 +478,7 @@ # CD is going away, but remains to cater for legacy makefiles. CD:=cd CHMOD:=@CHMOD@ +CODESIGN:=@CODESIGN@ COMM:=@COMM@ CP:=@CP@ CPIO:=@CPIO@ diff -r a233c04832cf -r a08d0f5b08bc common/autoconf/toolchain.m4 --- a/common/autoconf/toolchain.m4 Thu May 30 10:58:13 2013 -0700 +++ b/common/autoconf/toolchain.m4 Wed Jul 05 18:57:52 2017 +0200 @@ -36,7 +36,7 @@ $ECHO $COMPILER_VERSION_TEST | $GREP "^.*: Sun $COMPILER_NAME" > /dev/null if test $? -ne 0; then GCC_VERSION_TEST=`$COMPILER --version 2>&1 | $HEAD -n 1` - + AC_MSG_NOTICE([The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required Sun Studio compiler.]) AC_MSG_NOTICE([The result from running with -V was: "$COMPILER_VERSION_TEST" and with --version: "$GCC_VERSION_TEST"]) AC_MSG_ERROR([Sun Studio compiler is required. Try setting --with-tools-dir.]) @@ -69,7 +69,7 @@ AC_MSG_NOTICE([The result from running with --version was: "$COMPILER_VERSION_TEST"]) AC_MSG_ERROR([GCC compiler is required. Try setting --with-tools-dir.]) fi - + # First line typically looks something like: # gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2 COMPILER_VERSION=`$ECHO $COMPILER_VERSION_TEST | $SED -n "s/^.* \(@<:@1-9@:>@@<:@0-9.@:>@*\)/\1/p"` @@ -142,7 +142,7 @@ BASIC_REMOVE_SYMBOLIC_LINKS(TEST_COMPILER) AC_MSG_RESULT([$TEST_COMPILER]) AC_MSG_CHECKING([if $1 is disguised ccache]) - + COMPILER_BASENAME=`$BASENAME "$TEST_COMPILER"` if test "x$COMPILER_BASENAME" = "xccache"; then AC_MSG_RESULT([yes, trying to find proper $COMPILER_NAME compiler]) @@ -226,11 +226,11 @@ ], []) -if test "x$SYS_ROOT" != "x/" ; then +if test "x$SYS_ROOT" != "x/" ; then CFLAGS="--sysroot=$SYS_ROOT $CFLAGS" CXXFLAGS="--sysroot=$SYS_ROOT $CXXFLAGS" - OBJCFLAGS="--sysroot=$SYS_ROOT $OBJCFLAGS" - OBJCXXFLAGS="--sysroot=$SYS_ROOT $OBJCFLAGS" + OBJCFLAGS="--sysroot=$SYS_ROOT $OBJCFLAGS" + OBJCXXFLAGS="--sysroot=$SYS_ROOT $OBJCFLAGS" CPPFLAGS="--sysroot=$SYS_ROOT $CPPFLAGS" LDFLAGS="--sysroot=$SYS_ROOT $LDFLAGS" fi @@ -330,7 +330,7 @@ COMPILER_NAME=gcc COMPILER_TYPE=CC AS_IF([test "x$OPENJDK_TARGET_OS" = xwindows], [ - # For now, assume that we are always compiling using cl.exe. + # For now, assume that we are always compiling using cl.exe. CC_OUT_OPTION=-Fo EXE_OUT_OPTION=-out: LD_OUT_OPTION=-out: @@ -491,7 +491,7 @@ ############################################################################### # -# How to compile shared libraries. +# How to compile shared libraries. # if test "x$GCC" = xyes; then @@ -525,7 +525,7 @@ SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0 $PICFLAG" SHARED_LIBRARY_SUFFIX='.dylib' EXE_SUFFIX='' - SET_SHARED_LIBRARY_NAME='-Xlinker -install_name -Xlinker @rpath/[$]1' + SET_SHARED_LIBRARY_NAME='-Xlinker -install_name -Xlinker @rpath/[$]1' SET_SHARED_LIBRARY_MAPFILE='' SET_SHARED_LIBRARY_ORIGIN='-Xlinker -rpath -Xlinker @loader_path/.' SET_EXECUTABLE_ORIGIN="$SET_SHARED_LIBRARY_ORIGIN" @@ -676,7 +676,7 @@ # Use single precision floating point with 'float' CC_HIGHEST="$CC_HIGHEST -fsingle" # Assume memory references via basic pointer types do not alias - # (Source with excessing pointer casting and data access with mixed + # (Source with excessing pointer casting and data access with mixed # pointer types are not recommended) CC_HIGHEST="$CC_HIGHEST -xalias_level=basic" # Use intrinsic or inline versions for math/std functions @@ -892,7 +892,7 @@ fi if test "x$OPENJDK_TARGET_OS" = xmacosx; then CCXXFLAGS_JDK="$CCXXFLAGS_JDK -DMACOSX -D_ALLBSD_SOURCE" - # Setting these parameters makes it an error to link to macosx APIs that are + # Setting these parameters makes it an error to link to macosx APIs that are # newer than the given OS version and makes the linked binaries compatible even # if built on a newer version of the OS. # The expected format is X.Y.Z @@ -940,12 +940,12 @@ # Which should we link to? Are we lucky enough that the binary api to the libjvm.so library # is identical for client and server? Yes. Which is picked at runtime (client or server)? # Neither, since the chosen libjvm.so has already been loaded by the launcher, all the following -# libraries will link to whatever is in memory. Yuck. +# libraries will link to whatever is in memory. Yuck. # # Thus we offer the compiler to find libjvm.so first in server then in client. It works. Ugh. if test "x$COMPILER_NAME" = xcl; then LDFLAGS_JDK="$LDFLAGS_JDK -nologo -opt:ref -incremental:no" - if test "x$OPENJDK_TARGET_CPU" = xx86; then + if test "x$OPENJDK_TARGET_CPU" = xx86; then LDFLAGS_JDK="$LDFLAGS_JDK -safeseh" fi # TODO: make -debug optional "--disable-full-debug-symbols" @@ -965,7 +965,7 @@ if test -n "$HAS_GNU_HASH"; then LDFLAGS_JDK="${LDFLAGS_JDK} -Xlinker --hash-style=both " fi - if test "x$OPENJDK_TARGET_OS" = xlinux; then + if test "x$OPENJDK_TARGET_OS" = xlinux; then # And since we now know that the linker is gnu, then add -z defs, to forbid # undefined symbols in object files. LDFLAGS_JDK="${LDFLAGS_JDK} -Xlinker -z -Xlinker defs" @@ -1006,7 +1006,7 @@ # Adjust flags according to debug level. case $DEBUG_LEVEL in - fastdebug ) + fastdebug ) CFLAGS="$CFLAGS $D_FLAG" JAVAC_FLAGS="$JAVAC_FLAGS -g" ;; @@ -1018,9 +1018,9 @@ CXX_O_FLAG_NORM="$CXX_O_FLAG_NONE" JAVAC_FLAGS="$JAVAC_FLAGS -g" ;; -esac +esac - + AC_SUBST(CFLAGS_JDKLIB) AC_SUBST(CFLAGS_JDKEXE) @@ -1092,28 +1092,45 @@ AC_SUBST(COMPILER_SUPPORTS_TARGET_BITS_FLAG) ]) -# Setup the JTREG paths -AC_DEFUN_ONCE([TOOLCHAIN_SETUP_JTREG], -[ - AC_ARG_WITH(jtreg, [AS_HELP_STRING([--with-jtreg], - [Regression Test Harness @<:@probed@:>@])]) - - AC_MSG_CHECKING([for JTReg Regression Test Harness]) - - if test "x$with_jtreg" != x; then - JT_HOME="$with_jtreg" - BASIC_FIXUP_PATH([JT_HOME]) - AC_MSG_RESULT($JT_HOME) - - # jtreg win32 script works for everybody - JTREGEXE="$JT_HOME/win32/bin/jtreg" - if test ! -f "$JTREGEXE"; then - AC_MSG_ERROR([JTReg executable does not exist: $JTREGEXE]) +# Setup the JTREG paths +AC_DEFUN_ONCE([TOOLCHAIN_SETUP_JTREG], +[ + AC_ARG_WITH(jtreg, [AS_HELP_STRING([--with-jtreg], + [Regression Test Harness @<:@probed@:>@])], + [], + [with_jtreg=no]) + + if test "x$with_jtreg" = xno; then + # jtreg disabled + AC_MSG_CHECKING([for jtreg]) + AC_MSG_RESULT(no) + else + if test "x$with_jtreg" != xyes; then + # with path specified. + JT_HOME="$with_jtreg" fi - else - AC_MSG_RESULT(no) - fi - - AC_SUBST(JT_HOME) - AC_SUBST(JTREGEXE) + + if test "x$JT_HOME" != x; then + AC_MSG_CHECKING([for jtreg]) + + # use JT_HOME enviroment var. + BASIC_FIXUP_PATH([JT_HOME]) + + # jtreg win32 script works for everybody + JTREGEXE="$JT_HOME/win32/bin/jtreg" + + if test ! -f "$JTREGEXE"; then + AC_MSG_ERROR([JTReg executable does not exist: $JTREGEXE]) + fi + + AC_MSG_RESULT($JTREGEXE) + else + # try to find jtreg on path + BASIC_REQUIRE_PROG(JTREGEXE, jtreg) + JT_HOME="`$DIRNAME $JTREGEXE`" + fi + fi + + AC_SUBST(JT_HOME) + AC_SUBST(JTREGEXE) ]) diff -r a233c04832cf -r a08d0f5b08bc common/makefiles/Jprt.gmk --- a/common/makefiles/Jprt.gmk Thu May 30 10:58:13 2013 -0700 +++ b/common/makefiles/Jprt.gmk Wed Jul 05 18:57:52 2017 +0200 @@ -127,9 +127,21 @@ ifdef ALT_JAVAFX_ZIP_DIR @$(ECHO) " --with-javafx-zip-dir=$(call UnixPath,$(ALT_JAVAFX_ZIP_DIR)) " >> $@.tmp endif + ifdef ALT_JMC_ZIP_DIR + @$(ECHO) " --with-jmc-zip-dir=$(call UnixPath,$(ALT_JMC_ZIP_DIR)) " >> $@.tmp + endif ifdef ALT_WIXDIR @$(ECHO) " --with-wix=$(call UnixPath,$(ALT_WIXDIR)) " >> $@.tmp endif + ifdef ALT_INSTALL_LZMA_PATH + @$(ECHO) " --with-lzma-path=$(call UnixPath,$(ALT_INSTALL_LZMA_PATH)) " >> $@.tmp + endif + ifdef ALT_INSTALL_UPX_PATH + @$(ECHO) " --with-upx-path=$(call UnixPath,$(ALT_INSTALL_UPX_PATH)) " >> $@.tmp + endif + ifdef ALT_INSTALL_UPX_FILENAME + @$(ECHO) " --with-upx-filename=$(call UnixPath,$(ALT_INSTALL_UPX_FILENAME)) " >> $@.tmp + endif ifdef ALT_CCSS_SIGNING_DIR @$(ECHO) " --with-ccss-signing=$(call UnixPath,$(ALT_CCSS_SIGNING_DIR)) " >> $@.tmp endif diff -r a233c04832cf -r a08d0f5b08bc common/makefiles/Main.gmk --- a/common/makefiles/Main.gmk Thu May 30 10:58:13 2013 -0700 +++ b/common/makefiles/Main.gmk Wed Jul 05 18:57:52 2017 +0200 @@ -183,7 +183,7 @@ test: images test-only test-only: start-make @$(call TargetEnter) - @($(CD) $(SRC_ROOT)/test && $(BUILD_LOG_WRAPPER) $(MAKE) -j1 -k MAKEFLAGS= PRODUCT_HOME=$(JDK_IMAGE_DIR) JPRT_JAVA_HOME=$(JDK_IMAGE_DIR) ALT_OUTPUTDIR=$(OUTPUT_ROOT) $(TEST)) || true + @($(CD) $(SRC_ROOT)/test && $(BUILD_LOG_WRAPPER) $(MAKE) -j1 -k JT_HOME=$(JT_HOME) MAKEFLAGS= PRODUCT_HOME=$(JDK_IMAGE_DIR) JPRT_JAVA_HOME=$(JDK_IMAGE_DIR) ALT_OUTPUTDIR=$(OUTPUT_ROOT) $(TEST)) || true @$(call TargetExit) # Stores the tips for each repository. This file is be used when constructing the jdk image and can be diff -r a233c04832cf -r a08d0f5b08bc common/makefiles/MakeBase.gmk --- a/common/makefiles/MakeBase.gmk Thu May 30 10:58:13 2013 -0700 +++ b/common/makefiles/MakeBase.gmk Wed Jul 05 18:57:52 2017 +0200 @@ -361,8 +361,8 @@ # This is to be called by all SetupFoo macros define LogSetupMacroEntry - $(if $(26),$(error Internal makefile error: Too many arguments to LogSetupMacroEntry, please update MakeBase.gmk)) - $(if $(findstring $(LOG_LEVEL),debug trace), $(info $1 $(foreach i,2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25,$(if $($i),$(NEWLINE) $(strip [$i] $($i)))))) + $(if $(27),$(error Internal makefile error: Too many arguments to LogSetupMacroEntry, please update MakeBase.gmk)) + $(if $(findstring $(LOG_LEVEL),debug trace), $(info $1 $(foreach i,2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26,$(if $($i),$(NEWLINE) $(strip [$i] $($i)))))) endef # Make directory without forking mkdir if not needed diff -r a233c04832cf -r a08d0f5b08bc common/makefiles/NativeCompilation.gmk --- a/common/makefiles/NativeCompilation.gmk Thu May 30 10:58:13 2013 -0700 +++ b/common/makefiles/NativeCompilation.gmk Wed Jul 05 18:57:52 2017 +0200 @@ -147,9 +147,9 @@ # CC the compiler to use, default is $(CC) # LDEXE the linker to use for linking executables, default is $(LDEXE) # OPTIMIZATION sets optimization level to NONE, LOW, HIGH, HIGHEST - $(foreach i,2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25, $(if $($i),$1_$(strip $($i)))$(NEWLINE)) - $(call LogSetupMacroEntry,SetupNativeCompilation($1),$2,$3,$4,$5,$6,$7,$8,$9,$(10),$(11),$(12),$(13),$(14),$(15),$(16),$(17),$(18),$(19),$(20),$(21),$(22),$(23),$(24),$(25)) - $(if $(26),$(error Internal makefile error: Too many arguments to SetupNativeCompilation, please update NativeCompilation.gmk)) + $(foreach i,2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26, $(if $($i),$1_$(strip $($i)))$(NEWLINE)) + $(call LogSetupMacroEntry,SetupNativeCompilation($1),$2,$3,$4,$5,$6,$7,$8,$9,$(10),$(11),$(12),$(13),$(14),$(15),$(16),$(17),$(18),$(19),$(20),$(21),$(22),$(23),$(24),$(25),$(26)) + $(if $(27),$(error Internal makefile error: Too many arguments to SetupNativeCompilation, please update NativeCompilation.gmk)) ifneq (,$$($1_BIN)) $$(error BIN has been replaced with OBJECT_DIR) @@ -567,6 +567,12 @@ ifneq (,$$($1_GEN_MANIFEST)) $(MT) -nologo -manifest $$($1_GEN_MANIFEST) -outputresource:$$@;#1 endif - + # This only works if the openjdk_codesign identity is present on the system. Let + # silently fail otherwise. + ifneq (,$(CODESIGN)) + ifneq (,$$($1_CODESIGN)) + $(CODESIGN) -s openjdk_codesign $$@ + endif + endif endif endef diff -r a233c04832cf -r a08d0f5b08bc corba/.hgtags --- a/corba/.hgtags Thu May 30 10:58:13 2013 -0700 +++ b/corba/.hgtags Wed Jul 05 18:57:52 2017 +0200 @@ -213,3 +213,4 @@ fe4150590ee597f4e125fea950aa3b352622cc2d jdk8-b89 c8286839d0df04aba819ec4bef12b86babccf30e jdk8-b90 8f7ffb296385f85a4a6d53f9f2d4a7b13a8fa1ff jdk8-b91 +717aa26f8e0a1c0e768aebb3a763aca56db0c83e jdk8-b92 diff -r a233c04832cf -r a08d0f5b08bc hotspot/.hgtags --- a/hotspot/.hgtags Thu May 30 10:58:13 2013 -0700 +++ b/hotspot/.hgtags Wed Jul 05 18:57:52 2017 +0200 @@ -345,3 +345,4 @@ b19517cecc2e91636d7c16ba2f35e3d3dc628099 hs25-b33 7cbdf0e3725c0c56a2ff7540fc70b6d4b5890d04 jdk8-b91 38da9f4f67096745f851318d792d6468aa1f6cf8 hs25-b34 +092018493d3bbeb1c24278fd8c40ff3d76e1fed7 jdk8-b92 diff -r a233c04832cf -r a08d0f5b08bc jaxp/.hgtags --- a/jaxp/.hgtags Thu May 30 10:58:13 2013 -0700 +++ b/jaxp/.hgtags Wed Jul 05 18:57:52 2017 +0200 @@ -213,3 +213,4 @@ 893d2ba8bbea3a8d090e51d8eaea285b390789ea jdk8-b89 668acc0e1034bc1bec6d02be92e0dd4a63d0667e jdk8-b90 e3065fb07877c7e96e8b93416fe2ab9a4c9eb2a5 jdk8-b91 +1ab5d8d6eab81e65c6c3cf21739474cd67a0e7cf jdk8-b92 diff -r a233c04832cf -r a08d0f5b08bc jaxp/src/com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderImpl.java --- a/jaxp/src/com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderImpl.java Thu May 30 10:58:13 2013 -0700 +++ b/jaxp/src/com/sun/org/apache/xerces/internal/jaxp/DocumentBuilderImpl.java Wed Jul 05 18:57:52 2017 +0200 @@ -236,10 +236,6 @@ String feature = (String) entry.getKey(); boolean value = ((Boolean) entry.getValue()).booleanValue(); domParser.setFeature(feature, value); - if (feature.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) { - domParser.setProperty(ACCESS_EXTERNAL_DTD, ""); - domParser.setProperty(ACCESS_EXTERNAL_SCHEMA, ""); - } } } } diff -r a233c04832cf -r a08d0f5b08bc jaxp/src/com/sun/org/apache/xerces/internal/jaxp/SAXParserImpl.java --- a/jaxp/src/com/sun/org/apache/xerces/internal/jaxp/SAXParserImpl.java Thu May 30 10:58:13 2013 -0700 +++ b/jaxp/src/com/sun/org/apache/xerces/internal/jaxp/SAXParserImpl.java Wed Jul 05 18:57:52 2017 +0200 @@ -242,10 +242,6 @@ String feature = (String) entry.getKey(); boolean value = ((Boolean) entry.getValue()).booleanValue(); xmlReader.setFeature0(feature, value); - if (feature.equals(XMLConstants.FEATURE_SECURE_PROCESSING) && value) { - xmlReader.setProperty0(ACCESS_EXTERNAL_DTD, ""); - xmlReader.setProperty0(ACCESS_EXTERNAL_SCHEMA, ""); - } } } } diff -r a233c04832cf -r a08d0f5b08bc jaxp/src/com/sun/org/apache/xerces/internal/xinclude/ObjectFactory.java --- a/jaxp/src/com/sun/org/apache/xerces/internal/xinclude/ObjectFactory.java Thu May 30 10:58:13 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,553 +0,0 @@ -/* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 2001-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.sun.org.apache.xerces.internal.xinclude; - -import java.io.InputStream; -import java.io.IOException; -import java.io.File; -import java.io.FileInputStream; - -import java.util.Properties; -import java.io.BufferedReader; -import java.io.InputStreamReader; - -/** - * This class is duplicated for each JAXP subpackage so keep it in sync. - * It is package private and therefore is not exposed as part of the JAXP - * API. - *

- * This code is designed to implement the JAXP 1.1 spec pluggability - * feature and is designed to run on JDK version 1.1 and - * later, and to compile on JDK 1.2 and onward. - * The code also runs both as part of an unbundled jar file and - * when bundled as part of the JDK. - *

- * - */ -final class ObjectFactory { - - // - // Constants - // - - // name of default properties file to look for in JDK's jre/lib directory - private static final String DEFAULT_PROPERTIES_FILENAME = "xerces.properties"; - - /** Set to true for debugging */ - private static final boolean DEBUG = false; - - /** - * Default columns per line. - */ - private static final int DEFAULT_LINE_LENGTH = 80; - - /** cache the contents of the xerces.properties file. - * Until an attempt has been made to read this file, this will - * be null; if the file does not exist or we encounter some other error - * during the read, this will be empty. - */ - private static Properties fXercesProperties = null; - - /*** - * Cache the time stamp of the xerces.properties file so - * that we know if it's been modified and can invalidate - * the cache when necessary. - */ - private static long fLastModified = -1; - - // - // static methods - // - - /** - * Finds the implementation Class object in the specified order. The - * specified order is the following: - *

    - *
  1. query the system property using System.getProperty - *
  2. read META-INF/services/factoryId file - *
  3. use fallback classname - *
- * - * @return Class object of factory, never null - * - * @param factoryId Name of the factory to find, same as - * a property name - * @param fallbackClassName Implementation class name, if nothing else - * is found. Use null to mean no fallback. - * - * @exception ObjectFactory.ConfigurationError - */ - static Object createObject(String factoryId, String fallbackClassName) - throws ConfigurationError { - return createObject(factoryId, null, fallbackClassName); - } // createObject(String,String):Object - - /** - * Finds the implementation Class object in the specified order. The - * specified order is the following: - *
    - *
  1. query the system property using System.getProperty - *
  2. read $java.home/lib/propertiesFilename file - *
  3. read META-INF/services/factoryId file - *
  4. use fallback classname - *
- * - * @return Class object of factory, never null - * - * @param factoryId Name of the factory to find, same as - * a property name - * @param propertiesFilename The filename in the $java.home/lib directory - * of the properties file. If none specified, - * ${java.home}/lib/xerces.properties will be used. - * @param fallbackClassName Implementation class name, if nothing else - * is found. Use null to mean no fallback. - * - * @exception ObjectFactory.ConfigurationError - */ - static Object createObject(String factoryId, - String propertiesFilename, - String fallbackClassName) - throws ConfigurationError - { - if (DEBUG) debugPrintln("debug is on"); - - SecuritySupport ss = SecuritySupport.getInstance(); - ClassLoader cl = findClassLoader(); - - // Use the system property first - try { - String systemProp = ss.getSystemProperty(factoryId); - if (systemProp != null) { - if (DEBUG) debugPrintln("found system property, value=" + systemProp); - return newInstance(systemProp, cl, true); - } - } catch (SecurityException se) { - // Ignore and continue w/ next location - } - - // JAXP specific change - // always use fallback class to avoid the expense of constantly - // "stat"ing a non-existent "xerces.properties" and jar SPI entry - // see CR 6400863: Expensive creating of SAX parser in Mustang - if (true) { - if (fallbackClassName == null) { - throw new ConfigurationError( - "Provider for " + factoryId + " cannot be found", null); - } - - if (DEBUG) debugPrintln("using fallback, value=" + fallbackClassName); - return newInstance(fallbackClassName, cl, true); - } - - // Try to read from propertiesFilename, or $java.home/lib/xerces.properties - String factoryClassName = null; - // no properties file name specified; use $JAVA_HOME/lib/xerces.properties: - if (propertiesFilename == null) { - File propertiesFile = null; - boolean propertiesFileExists = false; - try { - String javah = ss.getSystemProperty("java.home"); - propertiesFilename = javah + File.separator + - "lib" + File.separator + DEFAULT_PROPERTIES_FILENAME; - propertiesFile = new File(propertiesFilename); - propertiesFileExists = ss.getFileExists(propertiesFile); - } catch (SecurityException e) { - // try again... - fLastModified = -1; - fXercesProperties = null; - } - - synchronized (ObjectFactory.class) { - boolean loadProperties = false; - FileInputStream fis = null; - try { - // file existed last time - if(fLastModified >= 0) { - if(propertiesFileExists && - (fLastModified < (fLastModified = ss.getLastModified(propertiesFile)))) { - loadProperties = true; - } else { - // file has stopped existing... - if(!propertiesFileExists) { - fLastModified = -1; - fXercesProperties = null; - } // else, file wasn't modified! - } - } else { - // file has started to exist: - if(propertiesFileExists) { - loadProperties = true; - fLastModified = ss.getLastModified(propertiesFile); - } // else, nothing's changed - } - if(loadProperties) { - // must never have attempted to read xerces.properties before (or it's outdeated) - fXercesProperties = new Properties(); - fis = ss.getFileInputStream(propertiesFile); - fXercesProperties.load(fis); - } - } catch (Exception x) { - fXercesProperties = null; - fLastModified = -1; - // assert(x instanceof FileNotFoundException - // || x instanceof SecurityException) - // In both cases, ignore and continue w/ next location - } - finally { - // try to close the input stream if one was opened. - if (fis != null) { - try { - fis.close(); - } - // Ignore the exception. - catch (IOException exc) {} - } - } - } - if(fXercesProperties != null) { - factoryClassName = fXercesProperties.getProperty(factoryId); - } - } else { - FileInputStream fis = null; - try { - fis = ss.getFileInputStream(new File(propertiesFilename)); - Properties props = new Properties(); - props.load(fis); - factoryClassName = props.getProperty(factoryId); - } catch (Exception x) { - // assert(x instanceof FileNotFoundException - // || x instanceof SecurityException) - // In both cases, ignore and continue w/ next location - } - finally { - // try to close the input stream if one was opened. - if (fis != null) { - try { - fis.close(); - } - // Ignore the exception. - catch (IOException exc) {} - } - } - } - if (factoryClassName != null) { - if (DEBUG) debugPrintln("found in " + propertiesFilename + ", value=" + factoryClassName); - return newInstance(factoryClassName, cl, true); - } - - // Try Jar Service Provider Mechanism - Object provider = findJarServiceProvider(factoryId); - if (provider != null) { - return provider; - } - - if (fallbackClassName == null) { - throw new ConfigurationError( - "Provider for " + factoryId + " cannot be found", null); - } - - if (DEBUG) debugPrintln("using fallback, value=" + fallbackClassName); - return newInstance(fallbackClassName, cl, true); - } // createObject(String,String,String):Object - - // - // Private static methods - // - - /** Prints a message to standard error if debugging is enabled. */ - private static void debugPrintln(String msg) { - if (DEBUG) { - System.err.println("JAXP: " + msg); - } - } // debugPrintln(String) - - /** - * Figure out which ClassLoader to use. For JDK 1.2 and later use - * the context ClassLoader. - */ - static ClassLoader findClassLoader() - throws ConfigurationError - { - SecuritySupport ss = SecuritySupport.getInstance(); - - // Figure out which ClassLoader to use for loading the provider - // class. If there is a Context ClassLoader then use it. - ClassLoader context = ss.getContextClassLoader(); - ClassLoader system = ss.getSystemClassLoader(); - - ClassLoader chain = system; - while (true) { - if (context == chain) { - // Assert: we are on JDK 1.1 or we have no Context ClassLoader - // or any Context ClassLoader in chain of system classloader - // (including extension ClassLoader) so extend to widest - // ClassLoader (always look in system ClassLoader if Xerces - // is in boot/extension/system classpath and in current - // ClassLoader otherwise); normal classloaders delegate - // back to system ClassLoader first so this widening doesn't - // change the fact that context ClassLoader will be consulted - ClassLoader current = ObjectFactory.class.getClassLoader(); - - chain = system; - while (true) { - if (current == chain) { - // Assert: Current ClassLoader in chain of - // boot/extension/system ClassLoaders - return system; - } - if (chain == null) { - break; - } - chain = ss.getParentClassLoader(chain); - } - - // Assert: Current ClassLoader not in chain of - // boot/extension/system ClassLoaders - return current; - } - - if (chain == null) { - // boot ClassLoader reached - break; - } - - // Check for any extension ClassLoaders in chain up to - // boot ClassLoader - chain = ss.getParentClassLoader(chain); - }; - - // Assert: Context ClassLoader not in chain of - // boot/extension/system ClassLoaders - return context; - } // findClassLoader():ClassLoader - - /** - * Create an instance of a class using the specified ClassLoader - */ - static Object newInstance(String className, ClassLoader cl, - boolean doFallback) - throws ConfigurationError - { - // assert(className != null); - try{ - Class providerClass = findProviderClass(className, cl, doFallback); - Object instance = providerClass.newInstance(); - if (DEBUG) debugPrintln("created new instance of " + providerClass + - " using ClassLoader: " + cl); - return instance; - } catch (ClassNotFoundException x) { - throw new ConfigurationError( - "Provider " + className + " not found", x); - } catch (Exception x) { - throw new ConfigurationError( - "Provider " + className + " could not be instantiated: " + x, - x); - } - } - - /** - * Find a Class using the specified ClassLoader - */ - static Class findProviderClass(String className, ClassLoader cl, - boolean doFallback) - throws ClassNotFoundException, ConfigurationError - { - //throw security exception if the calling thread is not allowed to access the package - //restrict the access to package as speicified in java.security policy - SecurityManager security = System.getSecurityManager(); - if (security != null) { - final int lastDot = className.lastIndexOf("."); - String packageName = className; - if (lastDot != -1) packageName = className.substring(0, lastDot); - security.checkPackageAccess(packageName); - } - Class providerClass; - if (cl == null) { - // XXX Use the bootstrap ClassLoader. There is no way to - // load a class using the bootstrap ClassLoader that works - // in both JDK 1.1 and Java 2. However, this should still - // work b/c the following should be true: - // - // (cl == null) iff current ClassLoader == null - // - // Thus Class.forName(String) will use the current - // ClassLoader which will be the bootstrap ClassLoader. - providerClass = Class.forName(className); - } else { - try { - providerClass = cl.loadClass(className); - } catch (ClassNotFoundException x) { - if (doFallback) { - // Fall back to current classloader - ClassLoader current = ObjectFactory.class.getClassLoader(); - if (current == null) { - providerClass = Class.forName(className); - } else if (cl != current) { - cl = current; - providerClass = cl.loadClass(className); - } else { - throw x; - } - } else { - throw x; - } - } - } - - return providerClass; - } - - /* - * Try to find provider using Jar Service Provider Mechanism - * - * @return instance of provider class if found or null - */ - private static Object findJarServiceProvider(String factoryId) - throws ConfigurationError - { - SecuritySupport ss = SecuritySupport.getInstance(); - String serviceId = "META-INF/services/" + factoryId; - InputStream is = null; - - // First try the Context ClassLoader - ClassLoader cl = findClassLoader(); - - is = ss.getResourceAsStream(cl, serviceId); - - // If no provider found then try the current ClassLoader - if (is == null) { - ClassLoader current = ObjectFactory.class.getClassLoader(); - if (cl != current) { - cl = current; - is = ss.getResourceAsStream(cl, serviceId); - } - } - - if (is == null) { - // No provider found - return null; - } - - if (DEBUG) debugPrintln("found jar resource=" + serviceId + - " using ClassLoader: " + cl); - - // Read the service provider name in UTF-8 as specified in - // the jar spec. Unfortunately this fails in Microsoft - // VJ++, which does not implement the UTF-8 - // encoding. Theoretically, we should simply let it fail in - // that case, since the JVM is obviously broken if it - // doesn't support such a basic standard. But since there - // are still some users attempting to use VJ++ for - // development, we have dropped in a fallback which makes a - // second attempt using the platform's default encoding. In - // VJ++ this is apparently ASCII, which is a subset of - // UTF-8... and since the strings we'll be reading here are - // also primarily limited to the 7-bit ASCII range (at - // least, in English versions), this should work well - // enough to keep us on the air until we're ready to - // officially decommit from VJ++. [Edited comment from - // jkesselm] - BufferedReader rd; - try { - rd = new BufferedReader(new InputStreamReader(is, "UTF-8"), DEFAULT_LINE_LENGTH); - } catch (java.io.UnsupportedEncodingException e) { - rd = new BufferedReader(new InputStreamReader(is), DEFAULT_LINE_LENGTH); - } - - String factoryClassName = null; - try { - // XXX Does not handle all possible input as specified by the - // Jar Service Provider specification - factoryClassName = rd.readLine(); - } catch (IOException x) { - // No provider found - return null; - } - finally { - try { - // try to close the reader. - rd.close(); - } - // Ignore the exception. - catch (IOException exc) {} - } - - if (factoryClassName != null && - ! "".equals(factoryClassName)) { - if (DEBUG) debugPrintln("found in resource, value=" - + factoryClassName); - - // Note: here we do not want to fall back to the current - // ClassLoader because we want to avoid the case where the - // resource file was found using one ClassLoader and the - // provider class was instantiated using a different one. - return newInstance(factoryClassName, cl, false); - } - - // No provider found - return null; - } - - // - // Classes - // - - /** - * A configuration error. - */ - static final class ConfigurationError - extends Error { - - /** Serialization version. */ - static final long serialVersionUID = 5061904944269807898L; - - // - // Data - // - - /** Exception. */ - private Exception exception; - - // - // Constructors - // - - /** - * Construct a new instance with the specified detail string and - * exception. - */ - ConfigurationError(String msg, Exception x) { - super(msg); - this.exception = x; - } // (String,Exception) - - // - // methods - // - - /** Returns the exception associated to this error. */ - Exception getException() { - return exception; - } // getException():Exception - - } // class ConfigurationError - -} // class ObjectFactory diff -r a233c04832cf -r a08d0f5b08bc jaxp/src/com/sun/org/apache/xml/internal/serialize/ObjectFactory.java --- a/jaxp/src/com/sun/org/apache/xml/internal/serialize/ObjectFactory.java Thu May 30 10:58:13 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,553 +0,0 @@ -/* - * reserved comment block - * DO NOT REMOVE OR ALTER! - */ -/* - * Copyright 2001-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.sun.org.apache.xml.internal.serialize; - -import java.io.InputStream; -import java.io.IOException; -import java.io.File; -import java.io.FileInputStream; - -import java.util.Properties; -import java.io.BufferedReader; -import java.io.InputStreamReader; - -/** - * This class is duplicated for each JAXP subpackage so keep it in sync. - * It is package private and therefore is not exposed as part of the JAXP - * API. - *

- * This code is designed to implement the JAXP 1.1 spec pluggability - * feature and is designed to run on JDK version 1.1 and - * later, and to compile on JDK 1.2 and onward. - * The code also runs both as part of an unbundled jar file and - * when bundled as part of the JDK. - *

- * - */ -final class ObjectFactory { - - // - // Constants - // - - // name of default properties file to look for in JDK's jre/lib directory - private static final String DEFAULT_PROPERTIES_FILENAME = "xerces.properties"; - - /** Set to true for debugging */ - private static final boolean DEBUG = false; - - /** - * Default columns per line. - */ - private static final int DEFAULT_LINE_LENGTH = 80; - - /** cache the contents of the xerces.properties file. - * Until an attempt has been made to read this file, this will - * be null; if the file does not exist or we encounter some other error - * during the read, this will be empty. - */ - private static Properties fXercesProperties = null; - - /*** - * Cache the time stamp of the xerces.properties file so - * that we know if it's been modified and can invalidate - * the cache when necessary. - */ - private static long fLastModified = -1; - - // - // static methods - // - - /** - * Finds the implementation Class object in the specified order. The - * specified order is the following: - *

    - *
  1. query the system property using System.getProperty - *
  2. read META-INF/services/factoryId file - *
  3. use fallback classname - *
- * - * @return Class object of factory, never null - * - * @param factoryId Name of the factory to find, same as - * a property name - * @param fallbackClassName Implementation class name, if nothing else - * is found. Use null to mean no fallback. - * - * @exception ObjectFactory.ConfigurationError - */ - static Object createObject(String factoryId, String fallbackClassName) - throws ConfigurationError { - return createObject(factoryId, null, fallbackClassName); - } // createObject(String,String):Object - - /** - * Finds the implementation Class object in the specified order. The - * specified order is the following: - *
    - *
  1. query the system property using System.getProperty - *
  2. read $java.home/lib/propertiesFilename file - *
  3. read META-INF/services/factoryId file - *
  4. use fallback classname - *
- * - * @return Class object of factory, never null - * - * @param factoryId Name of the factory to find, same as - * a property name - * @param propertiesFilename The filename in the $java.home/lib directory - * of the properties file. If none specified, - * ${java.home}/lib/xerces.properties will be used. - * @param fallbackClassName Implementation class name, if nothing else - * is found. Use null to mean no fallback. - * - * @exception ObjectFactory.ConfigurationError - */ - static Object createObject(String factoryId, - String propertiesFilename, - String fallbackClassName) - throws ConfigurationError - { - if (DEBUG) debugPrintln("debug is on"); - - SecuritySupport ss = SecuritySupport.getInstance(); - ClassLoader cl = findClassLoader(); - - // Use the system property first - try { - String systemProp = ss.getSystemProperty(factoryId); - if (systemProp != null) { - if (DEBUG) debugPrintln("found system property, value=" + systemProp); - return newInstance(systemProp, cl, true); - } - } catch (SecurityException se) { - // Ignore and continue w/ next location - } - - // JAXP specific change - // always use fallback class to avoid the expense of constantly - // "stat"ing a non-existent "xerces.properties" and jar SPI entry - // see CR 6400863: Expensive creating of SAX parser in Mustang - if (true) { - if (fallbackClassName == null) { - throw new ConfigurationError( - "Provider for " + factoryId + " cannot be found", null); - } - - if (DEBUG) debugPrintln("using fallback, value=" + fallbackClassName); - return newInstance(fallbackClassName, cl, true); - } - - // Try to read from propertiesFilename, or $java.home/lib/xerces.properties - String factoryClassName = null; - // no properties file name specified; use $JAVA_HOME/lib/xerces.properties: - if (propertiesFilename == null) { - File propertiesFile = null; - boolean propertiesFileExists = false; - try { - String javah = ss.getSystemProperty("java.home"); - propertiesFilename = javah + File.separator + - "lib" + File.separator + DEFAULT_PROPERTIES_FILENAME; - propertiesFile = new File(propertiesFilename); - propertiesFileExists = ss.getFileExists(propertiesFile); - } catch (SecurityException e) { - // try again... - fLastModified = -1; - fXercesProperties = null; - } - - synchronized (ObjectFactory.class) { - boolean loadProperties = false; - FileInputStream fis = null; - try { - // file existed last time - if(fLastModified >= 0) { - if(propertiesFileExists && - (fLastModified < (fLastModified = ss.getLastModified(propertiesFile)))) { - loadProperties = true; - } else { - // file has stopped existing... - if(!propertiesFileExists) { - fLastModified = -1; - fXercesProperties = null; - } // else, file wasn't modified! - } - } else { - // file has started to exist: - if(propertiesFileExists) { - loadProperties = true; - fLastModified = ss.getLastModified(propertiesFile); - } // else, nothing's changed - } - if(loadProperties) { - // must never have attempted to read xerces.properties before (or it's outdeated) - fXercesProperties = new Properties(); - fis = ss.getFileInputStream(propertiesFile); - fXercesProperties.load(fis); - } - } catch (Exception x) { - fXercesProperties = null; - fLastModified = -1; - // assert(x instanceof FileNotFoundException - // || x instanceof SecurityException) - // In both cases, ignore and continue w/ next location - } - finally { - // try to close the input stream if one was opened. - if (fis != null) { - try { - fis.close(); - } - // Ignore the exception. - catch (IOException exc) {} - } - } - } - if(fXercesProperties != null) { - factoryClassName = fXercesProperties.getProperty(factoryId); - } - } else { - FileInputStream fis = null; - try { - fis = ss.getFileInputStream(new File(propertiesFilename)); - Properties props = new Properties(); - props.load(fis); - factoryClassName = props.getProperty(factoryId); - } catch (Exception x) { - // assert(x instanceof FileNotFoundException - // || x instanceof SecurityException) - // In both cases, ignore and continue w/ next location - } - finally { - // try to close the input stream if one was opened. - if (fis != null) { - try { - fis.close(); - } - // Ignore the exception. - catch (IOException exc) {} - } - } - } - if (factoryClassName != null) { - if (DEBUG) debugPrintln("found in " + propertiesFilename + ", value=" + factoryClassName); - return newInstance(factoryClassName, cl, true); - } - - // Try Jar Service Provider Mechanism - Object provider = findJarServiceProvider(factoryId); - if (provider != null) { - return provider; - } - - if (fallbackClassName == null) { - throw new ConfigurationError( - "Provider for " + factoryId + " cannot be found", null); - } - - if (DEBUG) debugPrintln("using fallback, value=" + fallbackClassName); - return newInstance(fallbackClassName, cl, true); - } // createObject(String,String,String):Object - - // - // Private static methods - // - - /** Prints a message to standard error if debugging is enabled. */ - private static void debugPrintln(String msg) { - if (DEBUG) { - System.err.println("JAXP: " + msg); - } - } // debugPrintln(String) - - /** - * Figure out which ClassLoader to use. For JDK 1.2 and later use - * the context ClassLoader. - */ - static ClassLoader findClassLoader() - throws ConfigurationError - { - SecuritySupport ss = SecuritySupport.getInstance(); - - // Figure out which ClassLoader to use for loading the provider - // class. If there is a Context ClassLoader then use it. - ClassLoader context = ss.getContextClassLoader(); - ClassLoader system = ss.getSystemClassLoader(); - - ClassLoader chain = system; - while (true) { - if (context == chain) { - // Assert: we are on JDK 1.1 or we have no Context ClassLoader - // or any Context ClassLoader in chain of system classloader - // (including extension ClassLoader) so extend to widest - // ClassLoader (always look in system ClassLoader if Xerces - // is in boot/extension/system classpath and in current - // ClassLoader otherwise); normal classloaders delegate - // back to system ClassLoader first so this widening doesn't - // change the fact that context ClassLoader will be consulted - ClassLoader current = ObjectFactory.class.getClassLoader(); - - chain = system; - while (true) { - if (current == chain) { - // Assert: Current ClassLoader in chain of - // boot/extension/system ClassLoaders - return system; - } - if (chain == null) { - break; - } - chain = ss.getParentClassLoader(chain); - } - - // Assert: Current ClassLoader not in chain of - // boot/extension/system ClassLoaders - return current; - } - - if (chain == null) { - // boot ClassLoader reached - break; - } - - // Check for any extension ClassLoaders in chain up to - // boot ClassLoader - chain = ss.getParentClassLoader(chain); - }; - - // Assert: Context ClassLoader not in chain of - // boot/extension/system ClassLoaders - return context; - } // findClassLoader():ClassLoader - - /** - * Create an instance of a class using the specified ClassLoader - */ - static Object newInstance(String className, ClassLoader cl, - boolean doFallback) - throws ConfigurationError - { - // assert(className != null); - try{ - Class providerClass = findProviderClass(className, cl, doFallback); - Object instance = providerClass.newInstance(); - if (DEBUG) debugPrintln("created new instance of " + providerClass + - " using ClassLoader: " + cl); - return instance; - } catch (ClassNotFoundException x) { - throw new ConfigurationError( - "Provider " + className + " not found", x); - } catch (Exception x) { - throw new ConfigurationError( - "Provider " + className + " could not be instantiated: " + x, - x); - } - } - - /** - * Find a Class using the specified ClassLoader - */ - static Class findProviderClass(String className, ClassLoader cl, - boolean doFallback) - throws ClassNotFoundException, ConfigurationError - { - //throw security exception if the calling thread is not allowed to access the package - //restrict the access to package as speicified in java.security policy - SecurityManager security = System.getSecurityManager(); - if (security != null) { - final int lastDot = className.lastIndexOf("."); - String packageName = className; - if (lastDot != -1) packageName = className.substring(0, lastDot); - security.checkPackageAccess(packageName); - } - Class providerClass; - if (cl == null) { - // XXX Use the bootstrap ClassLoader. There is no way to - // load a class using the bootstrap ClassLoader that works - // in both JDK 1.1 and Java 2. However, this should still - // work b/c the following should be true: - // - // (cl == null) iff current ClassLoader == null - // - // Thus Class.forName(String) will use the current - // ClassLoader which will be the bootstrap ClassLoader. - providerClass = Class.forName(className); - } else { - try { - providerClass = cl.loadClass(className); - } catch (ClassNotFoundException x) { - if (doFallback) { - // Fall back to current classloader - ClassLoader current = ObjectFactory.class.getClassLoader(); - if (current == null) { - providerClass = Class.forName(className); - } else if (cl != current) { - cl = current; - providerClass = cl.loadClass(className); - } else { - throw x; - } - } else { - throw x; - } - } - } - - return providerClass; - } - - /* - * Try to find provider using Jar Service Provider Mechanism - * - * @return instance of provider class if found or null - */ - private static Object findJarServiceProvider(String factoryId) - throws ConfigurationError - { - SecuritySupport ss = SecuritySupport.getInstance(); - String serviceId = "META-INF/services/" + factoryId; - InputStream is = null; - - // First try the Context ClassLoader - ClassLoader cl = findClassLoader(); - - is = ss.getResourceAsStream(cl, serviceId); - - // If no provider found then try the current ClassLoader - if (is == null) { - ClassLoader current = ObjectFactory.class.getClassLoader(); - if (cl != current) { - cl = current; - is = ss.getResourceAsStream(cl, serviceId); - } - } - - if (is == null) { - // No provider found - return null; - } - - if (DEBUG) debugPrintln("found jar resource=" + serviceId + - " using ClassLoader: " + cl); - - // Read the service provider name in UTF-8 as specified in - // the jar spec. Unfortunately this fails in Microsoft - // VJ++, which does not implement the UTF-8 - // encoding. Theoretically, we should simply let it fail in - // that case, since the JVM is obviously broken if it - // doesn't support such a basic standard. But since there - // are still some users attempting to use VJ++ for - // development, we have dropped in a fallback which makes a - // second attempt using the platform's default encoding. In - // VJ++ this is apparently ASCII, which is a subset of - // UTF-8... and since the strings we'll be reading here are - // also primarily limited to the 7-bit ASCII range (at - // least, in English versions), this should work well - // enough to keep us on the air until we're ready to - // officially decommit from VJ++. [Edited comment from - // jkesselm] - BufferedReader rd; - try { - rd = new BufferedReader(new InputStreamReader(is, "UTF-8"), DEFAULT_LINE_LENGTH); - } catch (java.io.UnsupportedEncodingException e) { - rd = new BufferedReader(new InputStreamReader(is), DEFAULT_LINE_LENGTH); - } - - String factoryClassName = null; - try { - // XXX Does not handle all possible input as specified by the - // Jar Service Provider specification - factoryClassName = rd.readLine(); - } catch (IOException x) { - // No provider found - return null; - } - finally { - try { - // try to close the reader. - rd.close(); - } - // Ignore the exception. - catch (IOException exc) {} - } - - if (factoryClassName != null && - ! "".equals(factoryClassName)) { - if (DEBUG) debugPrintln("found in resource, value=" - + factoryClassName); - - // Note: here we do not want to fall back to the current - // ClassLoader because we want to avoid the case where the - // resource file was found using one ClassLoader and the - // provider class was instantiated using a different one. - return newInstance(factoryClassName, cl, false); - } - - // No provider found - return null; - } - - // - // Classes - // - - /** - * A configuration error. - */ - static final class ConfigurationError - extends Error { - - /** Serialization version. */ - static final long serialVersionUID = 937647395548533254L; - - // - // Data - // - - /** Exception. */ - private Exception exception; - - // - // Constructors - // - - /** - * Construct a new instance with the specified detail string and - * exception. - */ - ConfigurationError(String msg, Exception x) { - super(msg); - this.exception = x; - } // (String,Exception) - - // - // methods - // - - /** Returns the exception associated to this error. */ - Exception getException() { - return exception; - } // getException():Exception - - } // class ConfigurationError - -} // class ObjectFactory diff -r a233c04832cf -r a08d0f5b08bc jdk/.hgtags --- a/jdk/.hgtags Thu May 30 10:58:13 2013 -0700 +++ b/jdk/.hgtags Wed Jul 05 18:57:52 2017 +0200 @@ -213,3 +213,4 @@ 845025546e35519fbb8970e79fc2a834063a5e19 jdk8-b89 c63eda8f63008a4398d2c22ac8d72f7fef6f9238 jdk8-b90 169451cf0cc53bde5af24f9820ea3f35ec4b4df4 jdk8-b91 +a2a2a91075ad85becbe10a39d7fd04ef9bea8df5 jdk8-b92 diff -r a233c04832cf -r a08d0f5b08bc jdk/make/common/Defs-windows.gmk --- a/jdk/make/common/Defs-windows.gmk Thu May 30 10:58:13 2013 -0700 +++ b/jdk/make/common/Defs-windows.gmk Wed Jul 05 18:57:52 2017 +0200 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 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 @@ -432,40 +432,3 @@ -d "JDK_COPYRIGHT=$(JDK_RC_COPYRIGHT)" \ -d "JDK_NAME=$(JDK_RC_NAME)" \ -d "JDK_FVER=$(JDK_RC_FVER)" - -# Enable 7-Zip LZMA file (de)compression for Java Kernel if it is available -ifeq ($(ARCH_DATA_MODEL), 32) - ifneq ($(KERNEL), off) - # This is a hack to use until 7-Zip (and UPX) bundles can be put - # under /java/devtools. - ifndef DEPLOY_TOPDIR - DEPLOY_TOPDIR=$(JDK_TOPDIR)/../deploy - endif - # Uncomment this block to cause build failure if above assumption false - #DCHK = $(shell if [ ! -d $(DEPLOY_TOPDIR) ] ; then \ - # $(ECHO) deploy_not_a_peer_of_j2se ; \ - #fi ) - #ifeq ($(DCHK), deploy_not_a_peer_of_j2se) - # If a build failure points to control coming here it means - # it means deploy is not in the same directory - # as j2se. Java Kernel can't tolerate that for the time being. - #endif - EC_TMP = $(shell if [ -d $(DEPLOY_TOPDIR)/make/lzma ] ; then \ - $(ECHO) true ; \ - else \ - $(ECHO) false ; \ - fi ) - ifeq ($(EC_TMP), true) - EXTRA_COMP_INSTALL_PATH = lib\\\\deploy\\\\lzma.dll - # Crazy but true: deploy/make/plugin/jinstall/Makefile.jkernel does - # not include deploy/make/common/Defs-windows.gmk, either directly - # or indirectly. But it does include this file, so redundantly declare - # these variables that are in deploy/make/common/Defs-windows.gmk for - # the sake of the Java Kernel part of the deploy build. Whew! - EXTRA_COMP_LIB_NAME = lzma.dll - EXTRA_COMP_PATH = $(OUTPUTDIR)/tmp/deploy/lzma/win32/obj - EXTRA_COMP_CMD_PATH = $(EXTRA_COMP_PATH)/lzma.exe - EXTRA_COMP_LIB_PATH = $(EXTRA_COMP_PATH)/$(EXTRA_COMP_LIB_NAME) - endif - endif -endif diff -r a233c04832cf -r a08d0f5b08bc jdk/make/jpda/back/Makefile --- a/jdk/make/jpda/back/Makefile Thu May 30 10:58:13 2013 -0700 +++ b/jdk/make/jpda/back/Makefile Wed Jul 05 18:57:52 2017 +0200 @@ -31,6 +31,8 @@ LIBRARY = jdwp PRODUCT = jpda +LIBRARY_SUPPORTS_FULL_DEBUG_SYMBOLS=1 + FILES_m = mapfile-vers include $(BUILDDIR)/common/Defs.gmk diff -r a233c04832cf -r a08d0f5b08bc jdk/make/sun/awt/FILES_c_unix.gmk --- a/jdk/make/sun/awt/FILES_c_unix.gmk Thu May 30 10:58:13 2013 -0700 +++ b/jdk/make/sun/awt/FILES_c_unix.gmk Wed Jul 05 18:57:52 2017 +0200 @@ -171,3 +171,13 @@ GLXSurfaceData.c \ AccelGlyphCache.c \ CUPSfuncs.c + +ifeq ($(PLATFORM), macosx) +FILES_NO_MOTIF_objc = \ + AWTFont.m \ + AWTStrike.m \ + CCharToGlyphMapper.m \ + CGGlyphImages.m \ + CGGlyphOutlines.m \ + CoreTextSupport.m +endif # PLATFORM diff -r a233c04832cf -r a08d0f5b08bc jdk/make/sun/awt/FILES_export_unix.gmk --- a/jdk/make/sun/awt/FILES_export_unix.gmk Thu May 30 10:58:13 2013 -0700 +++ b/jdk/make/sun/awt/FILES_export_unix.gmk Wed Jul 05 18:57:52 2017 +0200 @@ -187,3 +187,14 @@ java/awt/dnd/DnDConstants.java \ sun/awt/CausedFocusEvent.java +ifeq ($(PLATFORM), macosx) +ifeq ($(HEADLESS), true) +FILES_export += \ + sun/awt/SunHints.java \ + sun/font/CCharToGlyphMapper.java \ + sun/font/CFont.java \ + sun/font/CFontManager.java \ + sun/font/CStrike.java \ + sun/font/CStrikeDisposer.java +endif # HEADLESS +endif # PLATFORM diff -r a233c04832cf -r a08d0f5b08bc jdk/make/sun/awt/mawt.gmk --- a/jdk/make/sun/awt/mawt.gmk Thu May 30 10:58:13 2013 -0700 +++ b/jdk/make/sun/awt/mawt.gmk Wed Jul 05 18:57:52 2017 +0200 @@ -43,6 +43,10 @@ # compiled based on the motif version. FILES_c = $(FILES_NO_MOTIF_c) +ifeq ($(PLATFORM), macosx) +FILES_objc = $(FILES_NO_MOTIF_objc) +endif # PLATFORM + ifeq ($(PLATFORM), solaris) ifneq ($(ARCH), amd64) FILES_reorder += reorder-$(ARCH) @@ -97,6 +101,10 @@ vpath %.cpp $(SHARE_SRC)/native/$(PKGDIR)/image vpath %.c $(PLATFORM_SRC)/native/$(PKGDIR)/robot_child +ifeq ($(PLATFORM), macosx) +vpath %.m $(call NativeSrcDirList,,native/sun/font) +endif # PLATFORM + # # Libraries to link in. # @@ -192,13 +200,21 @@ $(EVENT_MODEL) ifeq ($(PLATFORM), macosx) -CPPFLAGS += -I$(CUPS_HEADERS_PATH) +CPPFLAGS += -I$(CUPS_HEADERS_PATH) \ + $(call NativeSrcDirList,-I,native/sun/awt) \ + $(call NativeSrcDirList,-I,native/sun/font) ifndef HEADLESS CPPFLAGS += -I$(MOTIF_DIR)/include \ -I$(OPENWIN_HOME)/include LDFLAGS += -L$(MOTIF_LIB) -L$(OPENWIN_LIB) - +else +LDFLAGS += -framework Accelerate \ + -framework ApplicationServices \ + -framework Cocoa \ + -F/System/Library/Frameworks/JavaVM.framework/Frameworks \ + -framework JavaNativeFoundation \ + -framework JavaRuntimeSupport endif # !HEADLESS endif # PLATFORM diff -r a233c04832cf -r a08d0f5b08bc jdk/makefiles/CompileLaunchers.gmk --- a/jdk/makefiles/CompileLaunchers.gmk Thu May 30 10:58:13 2013 -0700 +++ b/jdk/makefiles/CompileLaunchers.gmk Wed Jul 05 18:57:52 2017 +0200 @@ -95,6 +95,9 @@ $1_PLIST_FILE:=Info-cmdline.plist ifneq ($(11),) $1_PLIST_FILE:=$(11) + ifneq ($$(findstring privileged,$$($1_PLIST_FILE)),) + $1_CODESIGN:=true + endif endif $1_LDFLAGS += -Wl,-all_load $(JDK_OUTPUTDIR)/objs/libjli_static.a \ @@ -174,7 +177,8 @@ -D "JDK_INTERNAL_NAME=$1" \ -D "JDK_FTYPE=0x1L" \ $7,\ - MANIFEST:=$(JDK_TOPDIR)/src/windows/resource/java.manifest) + MANIFEST:=$(JDK_TOPDIR)/src/windows/resource/java.manifest,\ + CODESIGN:=$$($1_CODESIGN)) BUILD_LAUNCHERS += $$(BUILD_LAUNCHER_$1) diff -r a233c04832cf -r a08d0f5b08bc jdk/makefiles/CompileNativeLibraries.gmk --- a/jdk/makefiles/CompileNativeLibraries.gmk Thu May 30 10:58:13 2013 -0700 +++ b/jdk/makefiles/CompileNativeLibraries.gmk Wed Jul 05 18:57:52 2017 +0200 @@ -1143,7 +1143,7 @@ -D "JDK_INTERNAL_NAME=jdwp" \ -D "JDK_FTYPE=0x2L",\ OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjdwp,\ - DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES))) + DEBUG_SYMBOLS:=true)) $(BUILD_LIBJDWP) : $(BUILD_LIBJAVA) @@ -2314,6 +2314,10 @@ $(JDK_TOPDIR)/src/solaris/native/sun/java2d/opengl \ $(JDK_TOPDIR)/src/solaris/native/sun/java2d/x11 +ifeq ($(OPENJDK_TARGET_OS),macosx) + LIBAWT_HEADLESS_DIRS+=$(JDK_TOPDIR)/src/macosx/native/sun/font +endif + LIBAWT_HEADLESS_CFLAGS:=-DHEADLESS=true \ -DX11_PATH=\"$(X11_PATH)\" -DPACKAGE_PATH=\"$(PACKAGE_PATH)\" \ $(CUPS_CFLAGS) \ @@ -2328,6 +2332,12 @@ -I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/jdga \ $(foreach dir,$(LIBAWT_HEADLESS_DIRS),-I$(dir)) +ifeq ($(OPENJDK_TARGET_OS),macosx) + LIBAWT_HEADLESS_CFLAGS+=\ + -F/System/Library/Frameworks/JavaVM.framework/Frameworks \ + -F/System/Library/Frameworks/ApplicationServices.framework/Frameworks +endif + LIBAWT_HEADLESS_FILES:=\ awt_Font.c \ HeadlessToolkit.c \ @@ -2356,6 +2366,16 @@ AccelGlyphCache.c \ CUPSfuncs.c +ifeq ($(OPENJDK_TARGET_OS),macosx) + LIBAWT_HEADLESS_FILES+=\ + AWTFont.m \ + AWTStrike.m \ + CCharToGlyphMapper.m \ + CGGlyphImages.m \ + CGGlyphOutlines.m \ + CoreTextSupport.m +endif + LIBAWT_HEADLESS_REORDER:= ifeq ($(OPENJDK_TARGET_OS), solaris) ifneq ($(OPENJDK_TARGET_CPU), x86_64) @@ -2382,7 +2402,13 @@ REORDER:=$(LIBAWT_HEADLESS_REORDER), \ LDFLAGS_SUFFIX_linux:=-ljvm -lawt -lm $(LIBDL) -ljava,\ LDFLAGS_SUFFIX_solaris:=$(LIBDL) -ljvm -lawt -lm -ljava $(LIBCXX) -lc,\ - LDFLAGS_SUFFIX_macosx:=-ljvm $(LIBCXX) -lawt $(LIBDL) -ljava,\ + LDFLAGS_SUFFIX_macosx:=-ljvm $(LIBCXX) -lawt $(LIBDL) -ljava \ + -framework Accelerate \ + -framework ApplicationServices \ + -framework Cocoa \ + -F/System/Library/Frameworks/JavaVM.framework/Frameworks \ + -framework JavaNativeFoundation \ + -framework JavaRuntimeSupport,\ OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libawt_headless,\ DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES))) diff -r a233c04832cf -r a08d0f5b08bc jdk/makefiles/Images.gmk --- a/jdk/makefiles/Images.gmk Thu May 30 10:58:13 2013 -0700 +++ b/jdk/makefiles/Images.gmk Wed Jul 05 18:57:52 2017 +0200 @@ -50,8 +50,6 @@ overlay-images: jre-overlay-image jdk-overlay-image --include $(CUSTOM_MAKE_DIR)/Images.gmk - # Processing license files from source area to image area # These will be modified to have the platform specific EOL chars. @@ -774,3 +772,5 @@ ################################################################################ .PHONY: default images jre-image jdk-image + +-include $(CUSTOM_MAKE_DIR)/Images.gmk diff -r a233c04832cf -r a08d0f5b08bc jdk/src/macosx/bin/java_md_macosx.c --- a/jdk/src/macosx/bin/java_md_macosx.c Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/macosx/bin/java_md_macosx.c Wed Jul 05 18:57:52 2017 +0200 @@ -44,7 +44,6 @@ #include #include #include -#include #include #include @@ -1001,6 +1000,32 @@ setenv(envVar, "1", 1); } +/* This class is made for performSelectorOnMainThread when java main + * should be launched on main thread. + * We cannot use dispatch_sync here, because it blocks the main dispatch queue + * which is used inside Cocoa + */ +@interface JavaLaunchHelper : NSObject { + int _returnValue; +} +- (void) launchJava:(NSValue*)argsValue; +- (int) getReturnValue; +@end + +@implementation JavaLaunchHelper + +- (void) launchJava:(NSValue*)argsValue +{ + _returnValue = JavaMain([argsValue pointerValue]); +} + +- (int) getReturnValue +{ + return _returnValue; +} + +@end + // MacOSX we may continue in the same thread int JVMInit(InvocationFunctions* ifn, jlong threadStackSize, @@ -1010,16 +1035,22 @@ JLI_TraceLauncher("In same thread\n"); // need to block this thread against the main thread // so signals get caught correctly - __block int rslt; - dispatch_sync(dispatch_get_main_queue(), ^(void) { - JavaMainArgs args; - args.argc = argc; - args.argv = argv; - args.mode = mode; - args.what = what; - args.ifn = *ifn; - rslt = JavaMain((void*)&args); - }); + JavaMainArgs args; + args.argc = argc; + args.argv = argv; + args.mode = mode; + args.what = what; + args.ifn = *ifn; + int rslt; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + { + JavaLaunchHelper* launcher = [[[JavaLaunchHelper alloc] init] autorelease]; + [launcher performSelectorOnMainThread:@selector(launchJava:) + withObject:[NSValue valueWithPointer:(void*)&args] + waitUntilDone:YES]; + rslt = [launcher getReturnValue]; + } + [pool drain]; return rslt; } else { return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret); diff -r a233c04832cf -r a08d0f5b08bc jdk/src/macosx/classes/sun/lwawt/macosx/CDropTargetContextPeer.java --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CDropTargetContextPeer.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CDropTargetContextPeer.java Wed Jul 05 18:57:52 2017 +0200 @@ -38,7 +38,7 @@ private long fNativeDropTransfer = 0; private long fNativeDataAvailable = 0; private Object fNativeData = null; - private boolean insideTarget = false; + private boolean insideTarget = true; Object awtLockAccess = new Object(); diff -r a233c04832cf -r a08d0f5b08bc jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java Wed Jul 05 18:57:52 2017 +0200 @@ -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 @@ -115,6 +115,8 @@ static final int RESIZABLE = 1 << 9; // both a style bit and prop bit static final int NONACTIVATING = 1 << 24; + static final int IS_DIALOG = 1 << 25; + static final int IS_MODAL = 1 << 26; static final int _STYLE_PROP_BITMASK = DECORATED | TEXTURED | UNIFIED | UTILITY | HUD | SHEET | CLOSEABLE | MINIMIZABLE | RESIZABLE; @@ -374,6 +376,13 @@ } } + if (isDialog) { + styleBits = SET(styleBits, IS_DIALOG, true); + if (((Dialog) target).isModal()) { + styleBits = SET(styleBits, IS_MODAL, true); + } + } + peer.setTextured(IS(TEXTURED, styleBits)); return styleBits; diff -r a233c04832cf -r a08d0f5b08bc jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterJob.java --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterJob.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterJob.java Wed Jul 05 18:57:52 2017 +0200 @@ -36,6 +36,7 @@ import javax.print.*; import javax.print.attribute.PrintRequestAttributeSet; import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.standard.PageRanges; import sun.java2d.*; import sun.print.*; @@ -173,6 +174,19 @@ if (nsPrintInfo != null) { fNSPrintInfo = nsPrintInfo.getValue(); } + + PageRanges pageRangesAttr = (PageRanges)attributes.get(PageRanges.class); + if (isSupportedValue(pageRangesAttr, attributes)) { + SunPageSelection rangeSelect = (SunPageSelection)attributes.get(SunPageSelection.class); + // If rangeSelect is not null, we are using AWT's print dialog that has + // All, Selection, and Range radio buttons + if (rangeSelect == null || rangeSelect == SunPageSelection.RANGE) { + int[][] range = pageRangesAttr.getMembers(); + // setPageRange will set firstPage and lastPage as called in getFirstPage + // and getLastPage + setPageRange(range[0][0] - 1, range[0][1] - 1); + } + } } volatile boolean onEventThread; @@ -225,7 +239,6 @@ * the end of the document. Note that firstPage * and lastPage are 0 based page indices. */ - int numPages = mDocument.getNumberOfPages(); int firstPage = getFirstPage(); int lastPage = getLastPage(); @@ -242,42 +255,53 @@ userCancelled = false; } - if (EventQueue.isDispatchThread()) { - // This is an AWT EventQueue, and this print rendering loop needs to block it. - - onEventThread = true; + //Add support for PageRange + PageRanges pr = (attributes == null) ? null + : (PageRanges)attributes.get(PageRanges.class); + int[][] prMembers = (pr == null) ? new int[0][0] : pr.getMembers(); + int loopi = 0; + do { + if (EventQueue.isDispatchThread()) { + // This is an AWT EventQueue, and this print rendering loop needs to block it. - printingLoop = AccessController.doPrivileged(new PrivilegedAction() { - @Override - public SecondaryLoop run() { - return Toolkit.getDefaultToolkit() - .getSystemEventQueue() - .createSecondaryLoop(); - } - }); + onEventThread = true; + + printingLoop = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public SecondaryLoop run() { + return Toolkit.getDefaultToolkit() + .getSystemEventQueue() + .createSecondaryLoop(); + } + }); - try { - // Fire off the print rendering loop on the AppKit thread, and don't have - // it wait and block this thread. - if (printLoop(false, firstPage, lastPage)) { - // Start a secondary loop on EDT until printing operation is finished or cancelled - printingLoop.enter(); + try { + // Fire off the print rendering loop on the AppKit thread, and don't have + // it wait and block this thread. + if (printLoop(false, firstPage, lastPage)) { + // Start a secondary loop on EDT until printing operation is finished or cancelled + printingLoop.enter(); + } + } catch (Exception e) { + e.printStackTrace(); } - } catch (Exception e) { - e.printStackTrace(); + } else { + // Fire off the print rendering loop on the AppKit, and block this thread + // until it is done. + // But don't actually block... we need to come back here! + onEventThread = false; + + try { + printLoop(true, firstPage, lastPage); + } catch (Exception e) { + e.printStackTrace(); + } } - } else { - // Fire off the print rendering loop on the AppKit, and block this thread - // until it is done. - // But don't actually block... we need to come back here! - onEventThread = false; - - try { - printLoop(true, firstPage, lastPage); - } catch (Exception e) { - e.printStackTrace(); + if (++loopi < prMembers.length) { + firstPage = prMembers[loopi][0]-1; + lastPage = prMembers[loopi][1] -1; } - } + } while (loopi < prMembers.length); } finally { synchronized (this) { // NOTE: Native code shouldn't allow exceptions out while diff -r a233c04832cf -r a08d0f5b08bc jdk/src/macosx/native/sun/awt/AWTWindow.m --- a/jdk/src/macosx/native/sun/awt/AWTWindow.m Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/macosx/native/sun/awt/AWTWindow.m Wed Jul 05 18:57:52 2017 +0200 @@ -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 @@ -536,8 +536,12 @@ - (void) windowDidBecomeKey: (NSNotification *) notification { AWT_ASSERT_APPKIT_THREAD; [AWTToolkit eventCountPlusPlus]; - [CMenuBar activate:self.javaMenuBar modallyDisabled:NO]; AWTWindow *opposite = [AWTWindow lastKeyWindow]; + if (!IS(self.styleBits, IS_DIALOG)) { + [CMenuBar activate:self.javaMenuBar modallyDisabled:NO]; + } else if (IS(self.styleBits, IS_MODAL)) { + [CMenuBar activate:opposite->javaMenuBar modallyDisabled:YES]; + } [AWTWindow setLastKeyWindow:nil]; [self _deliverWindowFocusEvent:YES oppositeWindow: opposite]; diff -r a233c04832cf -r a08d0f5b08bc jdk/src/macosx/native/sun/font/AWTFont.m --- a/jdk/src/macosx/native/sun/font/AWTFont.m Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/macosx/native/sun/font/AWTFont.m Wed Jul 05 18:57:52 2017 +0200 @@ -395,6 +395,7 @@ #pragma mark --- Miscellaneous JNI --- +#ifndef HEADLESS /* * Class: sun_awt_PlatformFont * Method: initIDs @@ -416,3 +417,4 @@ (JNIEnv *env, jclass cls) { } +#endif diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/com/sun/beans/finder/AbstractFinder.java --- a/jdk/src/share/classes/com/sun/beans/finder/AbstractFinder.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/com/sun/beans/finder/AbstractFinder.java Wed Jul 05 18:57:52 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2011, 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 @@ -24,6 +24,9 @@ */ package com.sun.beans.finder; +import java.lang.reflect.Executable; +import java.lang.reflect.Modifier; + import java.util.HashMap; import java.util.Map; @@ -37,7 +40,7 @@ * * @author Sergey A. Malenkov */ -abstract class AbstractFinder { +abstract class AbstractFinder { private final Class[] args; /** @@ -53,27 +56,6 @@ } /** - * Returns an array of {@code Class} objects - * that represent the formal parameter types of the method. - * Returns an empty array if the method takes no parameters. - * - * @param method the object that represents method - * @return the parameter types of the method - */ - protected abstract Class[] getParameters(T method); - - /** - * Returns {@code true} if and only if the method - * was declared to take a variable number of arguments. - * - * @param method the object that represents method - * @return {@code true} if the method was declared - * to take a variable number of arguments; - * {@code false} otherwise - */ - protected abstract boolean isVarArgs(T method); - - /** * Checks validness of the method. * At least the valid method should be public. * @@ -81,7 +63,9 @@ * @return {@code true} if the method is valid, * {@code false} otherwise */ - protected abstract boolean isValid(T method); + protected boolean isValid(T method) { + return Modifier.isPublic(method.getModifiers()); + } /** * Performs a search in the {@code methods} array. @@ -109,7 +93,7 @@ for (T newMethod : methods) { if (isValid(newMethod)) { - Class[] newParams = getParameters(newMethod); + Class[] newParams = newMethod.getParameterTypes(); if (newParams.length == this.args.length) { PrimitiveWrapperMap.replacePrimitivesWithWrappers(newParams); if (isAssignable(newParams, this.args)) { @@ -120,6 +104,11 @@ boolean useNew = isAssignable(oldParams, newParams); boolean useOld = isAssignable(newParams, oldParams); + if (useOld && useNew) { + // only if parameters are equal + useNew = !newMethod.isSynthetic(); + useOld = !oldMethod.isSynthetic(); + } if (useOld == useNew) { ambiguous = true; } else if (useNew) { @@ -130,7 +119,7 @@ } } } - if (isVarArgs(newMethod)) { + if (newMethod.isVarArgs()) { int length = newParams.length - 1; if (length <= this.args.length) { Class[] array = new Class[this.args.length]; @@ -160,6 +149,11 @@ boolean useNew = isAssignable(oldParams, newParams); boolean useOld = isAssignable(newParams, oldParams); + if (useOld && useNew) { + // only if parameters are equal + useNew = !newMethod.isSynthetic(); + useOld = !oldMethod.isSynthetic(); + } if (useOld == useNew) { if (oldParams == map.get(oldMethod)) { ambiguous = true; diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/com/sun/beans/finder/ConstructorFinder.java --- a/jdk/src/share/classes/com/sun/beans/finder/ConstructorFinder.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/com/sun/beans/finder/ConstructorFinder.java Wed Jul 05 18:57:52 2017 +0200 @@ -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 @@ -86,44 +86,4 @@ private ConstructorFinder(Class[] args) { super(args); } - - /** - * Returns an array of {@code Class} objects - * that represent the formal parameter types of the constructor. - * Returns an empty array if the constructor takes no parameters. - * - * @param constructor the object that represents constructor - * @return the parameter types of the constructor - */ - @Override - protected Class[] getParameters(Constructor constructor) { - return constructor.getParameterTypes(); - } - - /** - * Returns {@code true} if and only if the constructor - * was declared to take a variable number of arguments. - * - * @param constructor the object that represents constructor - * @return {@code true} if the constructor was declared - * to take a variable number of arguments; - * {@code false} otherwise - */ - @Override - protected boolean isVarArgs(Constructor constructor) { - return constructor.isVarArgs(); - } - - /** - * Checks validness of the constructor. - * The valid constructor should be public. - * - * @param constructor the object that represents constructor - * @return {@code true} if the constructor is valid, - * {@code false} otherwise - */ - @Override - protected boolean isValid(Constructor constructor) { - return Modifier.isPublic(constructor.getModifiers()); - } } diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/com/sun/beans/finder/MethodFinder.java --- a/jdk/src/share/classes/com/sun/beans/finder/MethodFinder.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/com/sun/beans/finder/MethodFinder.java Wed Jul 05 18:57:52 2017 +0200 @@ -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 @@ -196,33 +196,6 @@ } /** - * Returns an array of {@code Class} objects - * that represent the formal parameter types of the method. - * Returns an empty array if the method takes no parameters. - * - * @param method the object that represents method - * @return the parameter types of the method - */ - @Override - protected Class[] getParameters(Method method) { - return method.getParameterTypes(); - } - - /** - * Returns {@code true} if and only if the method - * was declared to take a variable number of arguments. - * - * @param method the object that represents method - * @return {@code true} if the method was declared - * to take a variable number of arguments; - * {@code false} otherwise - */ - @Override - protected boolean isVarArgs(Method method) { - return method.isVarArgs(); - } - - /** * Checks validness of the method. * The valid method should be public and * should have the specified name. @@ -233,6 +206,6 @@ */ @Override protected boolean isValid(Method method) { - return !method.isBridge() && Modifier.isPublic(method.getModifiers()) && method.getName().equals(this.name); + return super.isValid(method) && method.getName().equals(this.name); } } diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/com/sun/jndi/toolkit/ctx/Continuation.java --- a/jdk/src/share/classes/com/sun/jndi/toolkit/ctx/Continuation.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/com/sun/jndi/toolkit/ctx/Continuation.java Wed Jul 05 18:57:52 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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,14 +90,16 @@ * Constructs a new instance of Continuation. * @param top The name of the object that is to be resolved/operated upon. * This becomes the Continuation's 'starter' and is used to - * calculate the "resolved name" when filling in a NamingException. + * calculate the "resolved name" when filling in a NamingException. * @param environment The environment used by the caller. It is used - * when setting the "environment" of a CannotProceedException. + * when setting the "environment" of a CannotProceedException. */ + @SuppressWarnings("unchecked") // For Hashtable clone: environment.clone() public Continuation(Name top, Hashtable environment) { super(); starter = top; - this.environment = environment; + this.environment = (Hashtable) + ((environment == null) ? null : environment.clone()); } /** diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/com/sun/jndi/toolkit/dir/LazySearchEnumerationImpl.java --- a/jdk/src/share/classes/com/sun/jndi/toolkit/dir/LazySearchEnumerationImpl.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/com/sun/jndi/toolkit/dir/LazySearchEnumerationImpl.java Wed Jul 05 18:57:52 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -69,6 +69,7 @@ } } + @SuppressWarnings("unchecked") // For Hashtable clone: env.clone() public LazySearchEnumerationImpl(NamingEnumeration candidates, AttrFilter filter, SearchControls cons, Context ctx, Hashtable env, boolean useFactory) @@ -76,7 +77,8 @@ this.candidates = candidates; this.filter = filter; - this.env = env; + this.env = (Hashtable) + ((env == null) ? null : env.clone()); this.context = ctx; this.useFactory = useFactory; diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/com/sun/jndi/toolkit/url/GenericURLContext.java --- a/jdk/src/share/classes/com/sun/jndi/toolkit/url/GenericURLContext.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/com/sun/jndi/toolkit/url/GenericURLContext.java Wed Jul 05 18:57:52 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -53,7 +53,8 @@ @SuppressWarnings("unchecked") // Expect Hashtable public GenericURLContext(Hashtable env) { // context that is not tied to any specific URL - myEnv = (Hashtable)env; // copied on write + myEnv = + (Hashtable)(env == null ? null : env.clone()); } public void close() throws NamingException { @@ -488,22 +489,19 @@ return result; } - @SuppressWarnings("unchecked") // clone() public Object removeFromEnvironment(String propName) throws NamingException { if (myEnv == null) { return null; } - myEnv = (Hashtable)myEnv.clone(); return myEnv.remove(propName); } - @SuppressWarnings("unchecked") // clone() public Object addToEnvironment(String propName, Object propVal) throws NamingException { - myEnv = (myEnv == null) - ? new Hashtable(11, 0.75f) - : (Hashtable)myEnv.clone(); + if (myEnv == null) { + myEnv = new Hashtable(11, 0.75f); + } return myEnv.put(propName, propVal); } diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/io/FileInputStream.java --- a/jdk/src/share/classes/java/io/FileInputStream.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/io/FileInputStream.java Wed Jul 05 18:57:52 2017 +0200 @@ -240,13 +240,15 @@ * *

The skip method may, for a variety of * reasons, end up skipping over some smaller number of bytes, - * possibly 0. If n is negative, an - * IOException is thrown, even though the skip - * method of the {@link InputStream} superclass does nothing in this case. - * The actual number of bytes skipped is returned. + * possibly 0. If n is negative, the method + * will try to skip backwards. In case the backing file does not support + * backward skip at its current position, an IOException is + * thrown. The actual number of bytes skipped is returned. If it skips + * forwards, it returns a positive value. If it skips backwards, it + * returns a negative value. * - *

This method may skip more bytes than are remaining in the backing - * file. This produces no exception and the number of bytes skipped + *

This method may skip more bytes than what are remaining in the + * backing file. This produces no exception and the number of bytes skipped * may include some number of bytes that were beyond the EOF of the * backing file. Attempting to read from the stream after skipping past * the end will result in -1 indicating the end of the file. @@ -261,9 +263,10 @@ /** * Returns an estimate of the number of remaining bytes that can be read (or * skipped over) from this input stream without blocking by the next - * invocation of a method for this input stream. The next invocation might be - * the same thread or another thread. A single read or skip of this - * many bytes will not block, but may read or skip fewer bytes. + * invocation of a method for this input stream. Returns 0 when the file + * position is beyond EOF. The next invocation might be the same thread + * or another thread. A single read or skip of this many bytes will not + * block, but may read or skip fewer bytes. * *

In some cases, a non-blocking read (or skip) may appear to be * blocked when it is merely slow, for example when reading large diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/io/InputStream.java --- a/jdk/src/share/classes/java/io/InputStream.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/io/InputStream.java Wed Jul 05 18:57:52 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2011, 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 @@ -193,8 +193,10 @@ * up skipping over some smaller number of bytes, possibly 0. * This may result from any of a number of conditions; reaching end of file * before n bytes have been skipped is only one possibility. - * The actual number of bytes skipped is returned. If n is - * negative, no bytes are skipped. + * The actual number of bytes skipped is returned. If {@code n} is + * negative, the {@code skip} method for class {@code InputStream} always + * returns 0, and no bytes are skipped. Subclasses may handle the negative + * value differently. * *

The skip method of this class creates a * byte array and then repeatedly reads into it until n bytes diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/lang/Class.java --- a/jdk/src/share/classes/java/lang/Class.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/lang/Class.java Wed Jul 05 18:57:52 2017 +0200 @@ -28,6 +28,7 @@ import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; +import java.lang.reflect.GenericDeclaration; import java.lang.reflect.Member; import java.lang.reflect.Field; import java.lang.reflect.Executable; @@ -115,9 +116,9 @@ * @since JDK1.0 */ public final class Class implements java.io.Serializable, - java.lang.reflect.GenericDeclaration, - java.lang.reflect.Type, - java.lang.reflect.AnnotatedElement { + GenericDeclaration, + Type, + AnnotatedElement { private static final int ANNOTATION= 0x00002000; private static final int ENUM = 0x00004000; private static final int SYNTHETIC = 0x00001000; @@ -3182,7 +3183,7 @@ */ @Override public boolean isAnnotationPresent(Class annotationClass) { - return AnnotatedElement.super.isAnnotationPresent(annotationClass); + return GenericDeclaration.super.isAnnotationPresent(annotationClass); } /** diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/lang/String.java --- a/jdk/src/share/classes/java/lang/String.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/lang/String.java Wed Jul 05 18:57:52 2017 +0200 @@ -1010,13 +1010,14 @@ private boolean nonSyncContentEquals(AbstractStringBuilder sb) { char v1[] = value; char v2[] = sb.getValue(); - int i = 0; - int n = value.length; - while (n-- != 0) { + int n = v1.length; + if (n != sb.length()) { + return false; + } + for (int i = 0; i < n; i++) { if (v1[i] != v2[i]) { return false; } - i++; } return true; } @@ -1038,8 +1039,6 @@ * @since 1.5 */ public boolean contentEquals(CharSequence cs) { - if (value.length != cs.length()) - return false; // Argument is a StringBuffer, StringBuilder if (cs instanceof AbstractStringBuilder) { if (cs instanceof StringBuffer) { @@ -1055,12 +1054,14 @@ return true; // Argument is a generic CharSequence char v1[] = value; - int i = 0; - int n = value.length; - while (n-- != 0) { - if (v1[i] != cs.charAt(i)) + int n = v1.length; + if (n != cs.length()) { + return false; + } + for (int i = 0; i < n; i++) { + if (v1[i] != cs.charAt(i)) { return false; - i++; + } } return true; } diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/lang/StringBuffer.java --- a/jdk/src/share/classes/java/lang/StringBuffer.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/lang/StringBuffer.java Wed Jul 05 18:57:52 2017 +0200 @@ -335,10 +335,8 @@ * @since 1.5 */ @Override - public StringBuffer append(CharSequence s) { - // Note, synchronization achieved via invocations of other StringBuffer methods after - // narrowing of s to specific type - // Ditto for toStringCache clearing + public synchronized StringBuffer append(CharSequence s) { + toStringCache = null; super.append(s); return this; } diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/lang/Thread.java --- a/jdk/src/share/classes/java/lang/Thread.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/lang/Thread.java Wed Jul 05 18:57:52 2017 +0200 @@ -145,10 +145,10 @@ registerNatives(); } - private char name[]; - private int priority; - private Thread threadQ; - private long eetop; + private volatile char name[]; + private int priority; + private Thread threadQ; + private long eetop; /* Whether or not to single_step this thread. */ private boolean single_step; @@ -1135,7 +1135,7 @@ * @see #getName * @see #checkAccess() */ - public final void setName(String name) { + public final synchronized void setName(String name) { checkAccess(); this.name = name.toCharArray(); if (threadStatus != 0) { @@ -1150,7 +1150,7 @@ * @see #setName(String) */ public final String getName() { - return String.valueOf(name); + return new String(name, true); } /** diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/lang/ref/Reference.java --- a/jdk/src/share/classes/java/lang/ref/Reference.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/lang/ref/Reference.java Wed Jul 05 18:57:52 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, 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 @@ -138,8 +138,23 @@ pending = r.discovered; r.discovered = null; } else { + // The waiting on the lock may cause an OOME because it may try to allocate + // exception objects, so also catch OOME here to avoid silent exit of the + // reference handler thread. + // + // Explicitly define the order of the two exceptions we catch here + // when waiting for the lock. + // + // We do not want to try to potentially load the InterruptedException class + // (which would be done if this was its first use, and InterruptedException + // were checked first) in this situation. + // + // This may lead to the VM not ever trying to load the InterruptedException + // class again. try { - lock.wait(); + try { + lock.wait(); + } catch (OutOfMemoryError x) { } } catch (InterruptedException x) { } continue; } diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/lang/reflect/GenericDeclaration.java --- a/jdk/src/share/classes/java/lang/reflect/GenericDeclaration.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/lang/reflect/GenericDeclaration.java Wed Jul 05 18:57:52 2017 +0200 @@ -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 @@ -30,7 +30,7 @@ * * @since 1.5 */ -public interface GenericDeclaration { +public interface GenericDeclaration extends AnnotatedElement { /** * Returns an array of {@code TypeVariable} objects that * represent the type variables declared by the generic diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/nio/charset/Charset-X-Coder.java.template --- a/jdk/src/share/classes/java/nio/charset/Charset-X-Coder.java.template Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/nio/charset/Charset-X-Coder.java.template Wed Jul 05 18:57:52 2017 +0200 @@ -34,6 +34,7 @@ import java.nio.BufferUnderflowException; import java.lang.ref.WeakReference; import java.nio.charset.CoderMalfunctionError; // javadoc +import java.util.Arrays; /** @@ -244,7 +245,12 @@ * which is never null and is never empty */ public final $replType$ replacement() { +#if[decoder] return replacement; +#end[decoder] +#if[encoder] + return Arrays.copyOf(replacement, replacement.$replLength$); +#end[encoder] } /** @@ -280,12 +286,15 @@ throw new IllegalArgumentException("Empty replacement"); if (len > max$ItypesPerOtype$) throw new IllegalArgumentException("Replacement too long"); +#if[decoder] + this.replacement = newReplacement; +#end[decoder] #if[encoder] if (!isLegalReplacement(newReplacement)) throw new IllegalArgumentException("Illegal replacement"); + this.replacement = Arrays.copyOf(newReplacement, newReplacement.$replLength$); #end[encoder] - this.replacement = newReplacement; - implReplaceWith(newReplacement); + implReplaceWith(this.replacement); return this; } diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/nio/file/FileTreeIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/nio/file/FileTreeIterator.java Wed Jul 05 18:57:52 2017 +0200 @@ -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. + */ + +package java.nio.file; + +import java.io.Closeable; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Arrays; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.nio.file.FileTreeWalker.Event; + +/** + * An {@code Iterator to iterate over the nodes of a file tree. + * + *

{@code
+ *     try (FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options)) {
+ *         while (iterator.hasNext()) {
+ *             Event ev = iterator.next();
+ *             Path path = ev.file();
+ *             BasicFileAttributes attrs = ev.attributes();
+ *         }
+ *     }
+ * }
+ */ + +class FileTreeIterator implements Iterator, Closeable { + private final FileTreeWalker walker; + private Event next; + + /** + * Creates a new iterator to walk the file tree starting at the given file. + * + * @throws IllegalArgumentException + * if {@code maxDepth} is negative + * @throws IOException + * if an I/O errors occurs opening the starting file + * @throws SecurityException + * if the security manager denies access to the starting file + * @throws NullPointerException + * if {@code start} or {@code options} is {@ocde null} or + * the options array contains a {@code null} element + */ + FileTreeIterator(Path start, int maxDepth, FileVisitOption... options) + throws IOException + { + this.walker = new FileTreeWalker(Arrays.asList(options), maxDepth); + this.next = walker.walk(start); + assert next.type() == FileTreeWalker.EventType.ENTRY || + next.type() == FileTreeWalker.EventType.START_DIRECTORY; + + // IOException if there a problem accessing the starting file + IOException ioe = next.ioeException(); + if (ioe != null) + throw ioe; + } + + private void fetchNextIfNeeded() { + if (next == null) { + FileTreeWalker.Event ev = walker.next(); + while (ev != null) { + IOException ioe = ev.ioeException(); + if (ioe != null) + throw new UncheckedIOException(ioe); + + // END_DIRECTORY events are ignored + if (ev.type() != FileTreeWalker.EventType.END_DIRECTORY) { + next = ev; + return; + } + ev = walker.next(); + } + } + } + + @Override + public boolean hasNext() { + if (!walker.isOpen()) + throw new IllegalStateException(); + fetchNextIfNeeded(); + return next != null; + } + + @Override + public Event next() { + if (!walker.isOpen()) + throw new IllegalStateException(); + fetchNextIfNeeded(); + if (next == null) + throw new NoSuchElementException(); + Event result = next; + next = null; + return result; + } + + @Override + public void close() { + walker.close(); + } +} diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/nio/file/FileTreeWalker.java --- a/jdk/src/share/classes/java/nio/file/FileTreeWalker.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/nio/file/FileTreeWalker.java Wed Jul 05 18:57:52 2017 +0200 @@ -29,8 +29,8 @@ import java.io.Closeable; import java.io.IOException; import java.util.ArrayDeque; +import java.util.Collection; import java.util.Iterator; -import java.util.Set; import sun.nio.fs.BasicFileAttributesHolder; /** @@ -164,8 +164,17 @@ /** * Creates a {@code FileTreeWalker}. + * + * @throws IllegalArgumentException + * if {@code maxDepth} is negative + * @throws ClassCastException + * if (@code options} contains an element that is not a + * {@code FileVisitOption} + * @throws NullPointerException + * if {@code options} is {@ocde null} or the options + * array contains a {@code null} element */ - FileTreeWalker(Set options, int maxDepth) { + FileTreeWalker(Collection options, int maxDepth) { boolean fl = false; for (FileVisitOption option: options) { // will throw NPE if options contains null @@ -175,6 +184,9 @@ throw new AssertionError("Should not get here"); } } + if (maxDepth < 0) + throw new IllegalArgumentException("'maxDepth' is negative"); + this.followLinks = fl; this.linkOptions = (fl) ? new LinkOption[0] : new LinkOption[] { LinkOption.NOFOLLOW_LINKS }; diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/nio/file/Files.java --- a/jdk/src/share/classes/java/nio/file/Files.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/nio/file/Files.java Wed Jul 05 18:57:52 2017 +0200 @@ -25,10 +25,13 @@ package java.nio.file; +import java.nio.ByteBuffer; import java.nio.file.attribute.*; import java.nio.file.spi.FileSystemProvider; import java.nio.file.spi.FileTypeDetector; +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; @@ -38,7 +41,13 @@ 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; @@ -2587,9 +2596,6 @@ FileVisitor visitor) throws IOException { - if (maxDepth < 0) - throw new IllegalArgumentException("'maxDepth' is negative"); - /** * Create a FileTreeWalker to walk the file tree, invoking the visitor * for each event. @@ -2941,40 +2947,6 @@ } /** - * Read all the bytes from an input stream. The {@code initialSize} - * parameter indicates the initial size of the byte[] to allocate. - */ - private static byte[] read(InputStream source, int initialSize) - throws IOException - { - int capacity = initialSize; - byte[] buf = new byte[capacity]; - int nread = 0; - int rem = buf.length; - int n; - // read to EOF which may read more or less than initialSize (eg: file - // is truncated while we are reading) - while ((n = source.read(buf, nread, rem)) > 0) { - nread += n; - rem -= n; - assert rem >= 0; - if (rem == 0) { - // need larger buffer - int newCapacity = capacity << 1; - if (newCapacity < 0) { - if (capacity == Integer.MAX_VALUE) - throw new OutOfMemoryError("Required array size too large"); - newCapacity = Integer.MAX_VALUE; - } - rem = newCapacity - capacity; - buf = Arrays.copyOf(buf, newCapacity); - capacity = newCapacity; - } - } - return (capacity == nread) ? buf : Arrays.copyOf(buf, nread); - } - - /** * Read all the bytes from a file. The method ensures that the file is * closed when all bytes have been read or an I/O error, or other runtime * exception, is thrown. @@ -2999,12 +2971,22 @@ * method is invoked to check read access to the file. */ public static byte[] readAllBytes(Path path) throws IOException { - long size = size(path); - if (size > (long)Integer.MAX_VALUE) - throw new OutOfMemoryError("Required array size too large"); + try (FileChannel fc = FileChannel.open(path)) { + long size = fc.size(); + if (size > (long)Integer.MAX_VALUE) + throw new OutOfMemoryError("Required array size too large"); - try (InputStream in = newInputStream(path)) { - return read(in, (int)size); + byte[] arr = new byte[(int)size]; + ByteBuffer bb = ByteBuffer.wrap(arr); + while (bb.hasRemaining()) { + if (fc.read(bb) < 0) { + // truncated + break; + } + } + + int nread = bb.position(); + return (nread == size) ? arr : Arrays.copyOf(arr, nread); } } @@ -3177,4 +3159,336 @@ } return path; } + + // -- Stream APIs -- + + /** + * Implementation of CloseableStream + */ + private static class DelegatingCloseableStream extends DelegatingStream + implements CloseableStream + { + private final Closeable closeable; + + DelegatingCloseableStream(Closeable c, Stream 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 + * which are the entries in the directory. The listing is not recursive. + * + *

The elements of the stream are {@link Path} objects that are + * obtained as if by {@link Path#resolve(Path) resolving} the name of the + * directory entry against {@code dir}. Some file systems maintain special + * links to the directory itself and the directory's parent directory. + * Entries representing these links are not included. + * + *

The stream is weakly consistent. It is thread safe but does + * not freeze the directory while iterating, so it may (or may not) + * reflect updates to the directory that occur after returning from this + * method. + * + *

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 + * has been reached. Due to read-ahead, one or more elements may be + * returned after the stream has been closed. + * + *

If an {@link IOException} is thrown when accessing the directory + * after this method has returned, it is wrapped in an {@link + * UncheckedIOException} which will be thrown from the method that caused + * the access to take place. + * + * @param dir The path to the directory + * + * @return The {@code CloseableStream} describing the content of the + * directory + * + * @throws NotDirectoryException + * if the file could not otherwise be opened because it is not + * a directory (optional specific exception) + * @throws IOException + * if an I/O error occurs when opening the directory + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the directory. + * + * @see #newDirectoryStream(Path) + * @since 1.8 + */ + public static CloseableStream list(Path dir) throws IOException { + DirectoryStream ds = Files.newDirectoryStream(dir); + final Iterator delegate = ds.iterator(); + + // Re-wrap DirectoryIteratorException to UncheckedIOException + Iterator it = new Iterator() { + public boolean hasNext() { + try { + return delegate.hasNext(); + } catch (DirectoryIteratorException e) { + throw new UncheckedIOException(e.getCause()); + } + } + public Path next() { + try { + return delegate.next(); + } catch (DirectoryIteratorException e) { + throw new UncheckedIOException(e.getCause()); + } + } + }; + + return new DelegatingCloseableStream<>(ds, + StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, + Spliterator.DISTINCT))); + } + + /** + * Return a {@code CloseableStream} that is lazily populated with {@code + * Path} by walking the file tree rooted at a given starting file. The + * file tree is traversed depth-first, 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}. + * + *

The {@code stream} walks the file tree as elements are consumed. + * The {@code CloseableStream} 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 + * their descendants will follow the directory in the stream as + * they are encountered. When all entries have been visited, then the + * directory is closed. The file tree walk then continues at the next + * sibling of the directory. + * + *

The stream is weakly consistent. It does not freeze the + * file tree while iterating, so it may (or may not) reflect updates to + * the file tree that occur after returned from this method. + * + *

By default, symbolic links are not automatically followed by this + * method. If the {@code options} parameter contains the {@link + * FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then symbolic links are + * followed. When following links, and the attributes of the target cannot + * be read, then this method attempts to get the {@code BasicFileAttributes} + * of the link. + * + *

If the {@code options} parameter contains the {@link + * FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then the stream keeps + * track of directories visited so that cycles can be detected. A cycle + * arises when there is an entry in a directory that is an ancestor of the + * directory. Cycle detection is done by recording the {@link + * java.nio.file.attribute.BasicFileAttributes#fileKey file-key} of directories, + * or if file keys are not available, by invoking the {@link #isSameFile + * isSameFile} method to test if a directory is the same file as an + * ancestor. When a cycle is detected it is treated as an I/O error with + * an instance of {@link FileSystemLoopException}. + * + *

The {@code maxDepth} parameter is the maximum number of levels of + * directories to visit. A value of {@code 0} means that only the starting + * file is visited, unless denied by the security manager. A value of + * {@link Integer#MAX_VALUE MAX_VALUE} may be used to indicate that all + * levels should be visited. + * + *

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

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 + * {@link java.lang.IllegalStateException}. + * + *

If an {@link IOException} is thrown when accessing the directory + * after this method has returned, it is wrapped in an {@link + * UncheckedIOException} which will be thrown from the method that caused + * the access to take place. + * + * @param start + * the starting file + * @param maxDepth + * the maximum number of directory levels to visit + * @param options + * options to configure the traversal + * + * @return the {@link CloseableStream} of {@link Path} + * + * @throws IllegalArgumentException + * if the {@code maxDepth} parameter is negative + * @throws SecurityException + * If the security manager denies access to the starting file. + * In the case of the default provider, the {@link + * SecurityManager#checkRead(String) checkRead} method is invoked + * to check read access to the directory. + * @throws IOException + * if an I/O error is thrown when accessing the starting file. + * @since 1.8 + */ + public static CloseableStream walk(Path start, int maxDepth, + FileVisitOption... options) + throws IOException + { + FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options); + return new DelegatingCloseableStream<>(iterator, + StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT)) + .map(entry -> entry.file())); + } + + /** + * Return a {@code CloseableStream} that is lazily populated with {@code + * Path} by walking the file tree rooted at a given starting file. The + * file tree is traversed depth-first, 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}. + * + *

This method works as if invoking it were equivalent to evaluating the + * expression: + *

+     * walk(start, Integer.MAX_VALUE, options)
+     * 
+ * In other words, it visits all levels of the file tree. + * + * @param start + * the starting file + * @param options + * options to configure the traversal + * + * @return the {@link CloseableStream} of {@link Path} + * + * @throws SecurityException + * If the security manager denies access to the starting file. + * In the case of the default provider, the {@link + * SecurityManager#checkRead(String) checkRead} method is invoked + * to check read access to the directory. + * @throws IOException + * if an I/O error is thrown when accessing the starting file. + * + * @see #walk(Path, int, FileVisitOption...) + * @since 1.8 + */ + public static CloseableStream walk(Path start, + FileVisitOption... options) + throws IOException + { + return walk(start, Integer.MAX_VALUE, options); + } + + /** + * Return a {@code CloseableStream} that is lazily populated with {@code + * Path} by searching for files in a file tree rooted at a given starting + * file. + * + *

This method walks the file tree in exactly the manner specified by + * the {@link #walk walk} method. For each file encountered, the given + * {@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 + * 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}. + * + *

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 + * the access to take place. + * + * @param start + * the starting file + * @param maxDepth + * the maximum number of directory levels to search + * @param matcher + * the function used to decide whether a file should be included + * in the returned stream + * @param options + * options to configure the traversal + * + * @return the {@link CloseableStream} of {@link Path} + * + * @throws IllegalArgumentException + * if the {@code maxDepth} parameter is negative + * @throws SecurityException + * If the security manager denies access to the starting file. + * In the case of the default provider, the {@link + * SecurityManager#checkRead(String) checkRead} method is invoked + * to check read access to the directory. + * @throws IOException + * if an I/O error is thrown when accessing the starting file. + * + * @see #walk(Path, int, FileVisitOption...) + * @since 1.8 + */ + public static CloseableStream find(Path start, + int maxDepth, + BiPredicate matcher, + FileVisitOption... options) + throws IOException + { + FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options); + return new DelegatingCloseableStream<>(iterator, + StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT)) + .filter(entry -> matcher.test(entry.file(), entry.attributes())) + .map(entry -> entry.file())); + } + + /** + * Read all lines from a file as a {@code CloseableStream}. 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. + * + *

Bytes from the file are decoded into characters using the specified + * charset and the same line terminators as specified by {@code + * readAllLines} are supported. + * + *

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 + * {@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}. + * + *

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. + * + * @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} + * + * @throws IOException + * if an I/O error occurs opening the file + * @throws SecurityException + * In the case of the default provider, and a security manager is + * installed, the {@link SecurityManager#checkRead(String) checkRead} + * method is invoked to check read access to the file. + * + * @see #readAllLines(Path, Charset) + * @see #newBufferedReader(Path, Charset) + * @see java.io.BufferedReader#lines() + * @since 1.8 + */ + public static CloseableStream lines(Path path, Charset cs) + throws IOException + { + BufferedReader br = Files.newBufferedReader(path, cs); + return new DelegatingCloseableStream<>(br, br.lines()); + } } diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/text/DateFormatSymbols.java --- a/jdk/src/share/classes/java/text/DateFormatSymbols.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/text/DateFormatSymbols.java Wed Jul 05 18:57:52 2017 +0200 @@ -59,7 +59,7 @@ * DateFormatSymbols is a public class for encapsulating * localizable date-time formatting data, such as the names of the * months, the names of the days of the week, and the time zone data. - * DateFormat and SimpleDateFormat both use + * SimpleDateFormat uses * DateFormatSymbols to encapsulate this information. * *

diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/util/Arrays.java --- a/jdk/src/share/classes/java/util/Arrays.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/util/Arrays.java Wed Jul 05 18:57:52 2017 +0200 @@ -40,7 +40,6 @@ import java.util.stream.LongStream; import java.util.stream.Stream; import java.util.stream.StreamSupport; -import static java.util.ArraysParallelSortHelpers.*; /** * This class contains various methods for manipulating arrays (such as @@ -70,17 +69,62 @@ public class Arrays { /** - * The minimum array length below which the sorting algorithm will not - * further partition the sorting task. + * The minimum array length below which a parallel sorting + * algorithm will not further partition the sorting task. Using + * smaller sizes typically results in memory contention across + * tasks that makes parallel speedups unlikely. */ - // reasonable default so that we don't overcreate tasks - private static final int MIN_ARRAY_SORT_GRAN = 256; + private static final int MIN_ARRAY_SORT_GRAN = 1 << 13; // Suppresses default constructor, ensuring non-instantiability. private Arrays() {} + /** + * A comparator that implements the natural ordering of a group of + * mutually comparable elements. May be used when a supplied + * comparator is null. To simplify code-sharing within underlying + * implementations, the compare method only declares type Object + * for its second argument. + * + * Arrays class implementor's note: It is an empirical matter + * whether ComparableTimSort offers any performance benefit over + * TimSort used with this comparator. If not, you are better off + * deleting or bypassing ComparableTimSort. There is currently no + * empirical case for separating them for parallel sorting, so all + * public Object parallelSort methods use the same comparator + * based implementation. + */ + static final class NaturalOrder implements Comparator { + @SuppressWarnings("unchecked") + public int compare(Object first, Object second) { + return ((Comparable)first).compareTo(second); + } + static final NaturalOrder INSTANCE = new NaturalOrder(); + } + + /** + * Checks that {@code fromIndex} and {@code toIndex} are in + * the range and throws an exception if they aren't. + */ + private static void rangeCheck(int arrayLength, int fromIndex, int toIndex) { + if (fromIndex > toIndex) { + throw new IllegalArgumentException( + "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); + } + if (fromIndex < 0) { + throw new ArrayIndexOutOfBoundsException(fromIndex); + } + if (toIndex > arrayLength) { + throw new ArrayIndexOutOfBoundsException(toIndex); + } + } + /* - * Sorting of primitive type arrays. + * Sorting methods. Note that all public "sort" methods take the + * same form: Performing argument checks if necessary, and then + * expanding arguments into those required for the internal + * implementation methods residing in other package-private + * classes (except for legacyMergeSort, included in this class). */ /** @@ -95,7 +139,7 @@ * @param a the array to be sorted */ public static void sort(int[] a) { - DualPivotQuicksort.sort(a); + DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0); } /** @@ -120,7 +164,7 @@ */ public static void sort(int[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); + DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); } /** @@ -135,7 +179,7 @@ * @param a the array to be sorted */ public static void sort(long[] a) { - DualPivotQuicksort.sort(a); + DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0); } /** @@ -160,7 +204,7 @@ */ public static void sort(long[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); + DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); } /** @@ -175,7 +219,7 @@ * @param a the array to be sorted */ public static void sort(short[] a) { - DualPivotQuicksort.sort(a); + DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0); } /** @@ -200,7 +244,7 @@ */ public static void sort(short[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); + DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); } /** @@ -215,7 +259,7 @@ * @param a the array to be sorted */ public static void sort(char[] a) { - DualPivotQuicksort.sort(a); + DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0); } /** @@ -240,7 +284,7 @@ */ public static void sort(char[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); + DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); } /** @@ -255,7 +299,7 @@ * @param a the array to be sorted */ public static void sort(byte[] a) { - DualPivotQuicksort.sort(a); + DualPivotQuicksort.sort(a, 0, a.length - 1); } /** @@ -303,7 +347,7 @@ * @param a the array to be sorted */ public static void sort(float[] a) { - DualPivotQuicksort.sort(a); + DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0); } /** @@ -336,7 +380,7 @@ */ public static void sort(float[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); + DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); } /** @@ -359,7 +403,7 @@ * @param a the array to be sorted */ public static void sort(double[] a) { - DualPivotQuicksort.sort(a); + DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0); } /** @@ -392,7 +436,742 @@ */ public static void sort(double[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); + DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(byte[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(byte[]) Arrays.sort} method. The algorithm requires a + * working space no greater than the size of the original array. The + * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to + * execute any parallel tasks. + * + * @param a the array to be sorted + * + * @since 1.8 + */ + public static void parallelSort(byte[] a) { + int n = a.length, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + DualPivotQuicksort.sort(a, 0, n - 1); + else + new ArraysParallelSortHelpers.FJByte.Sorter + (null, a, new byte[n], 0, n, 0, + ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g).invoke(); + } + + /** + * Sorts the specified range of the array into ascending numerical order. + * The range to be sorted extends from the index {@code fromIndex}, + * inclusive, to the index {@code toIndex}, exclusive. If + * {@code fromIndex == toIndex}, the range to be sorted is empty. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(byte[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(byte[]) Arrays.sort} method. The algorithm requires a working + * space no greater than the size of the specified range of the original + * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is + * used to execute any parallel tasks. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + * + * @since 1.8 + */ + public static void parallelSort(byte[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + int n = toIndex - fromIndex, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); + else + new ArraysParallelSortHelpers.FJByte.Sorter + (null, a, new byte[n], fromIndex, n, 0, + ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g).invoke(); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(char[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(char[]) Arrays.sort} method. The algorithm requires a + * working space no greater than the size of the original array. The + * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to + * execute any parallel tasks. + * + * @param a the array to be sorted + * + * @since 1.8 + */ + public static void parallelSort(char[] a) { + int n = a.length, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0); + else + new ArraysParallelSortHelpers.FJChar.Sorter + (null, a, new char[n], 0, n, 0, + ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g).invoke(); + } + + /** + * Sorts the specified range of the array into ascending numerical order. + * The range to be sorted extends from the index {@code fromIndex}, + * inclusive, to the index {@code toIndex}, exclusive. If + * {@code fromIndex == toIndex}, the range to be sorted is empty. + * + @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(char[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(char[]) Arrays.sort} method. The algorithm requires a working + * space no greater than the size of the specified range of the original + * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is + * used to execute any parallel tasks. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + * + * @since 1.8 + */ + public static void parallelSort(char[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + int n = toIndex - fromIndex, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); + else + new ArraysParallelSortHelpers.FJChar.Sorter + (null, a, new char[n], fromIndex, n, 0, + ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g).invoke(); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(short[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(short[]) Arrays.sort} method. The algorithm requires a + * working space no greater than the size of the original array. The + * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to + * execute any parallel tasks. + * + * @param a the array to be sorted + * + * @since 1.8 + */ + public static void parallelSort(short[] a) { + int n = a.length, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0); + else + new ArraysParallelSortHelpers.FJShort.Sorter + (null, a, new short[n], 0, n, 0, + ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g).invoke(); + } + + /** + * Sorts the specified range of the array into ascending numerical order. + * The range to be sorted extends from the index {@code fromIndex}, + * inclusive, to the index {@code toIndex}, exclusive. If + * {@code fromIndex == toIndex}, the range to be sorted is empty. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(short[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(short[]) Arrays.sort} method. The algorithm requires a working + * space no greater than the size of the specified range of the original + * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is + * used to execute any parallel tasks. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + * + * @since 1.8 + */ + public static void parallelSort(short[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + int n = toIndex - fromIndex, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); + else + new ArraysParallelSortHelpers.FJShort.Sorter + (null, a, new short[n], fromIndex, n, 0, + ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g).invoke(); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(int[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(int[]) Arrays.sort} method. The algorithm requires a + * working space no greater than the size of the original array. The + * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to + * execute any parallel tasks. + * + * @param a the array to be sorted + * + * @since 1.8 + */ + public static void parallelSort(int[] a) { + int n = a.length, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0); + else + new ArraysParallelSortHelpers.FJInt.Sorter + (null, a, new int[n], 0, n, 0, + ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g).invoke(); + } + + /** + * Sorts the specified range of the array into ascending numerical order. + * The range to be sorted extends from the index {@code fromIndex}, + * inclusive, to the index {@code toIndex}, exclusive. If + * {@code fromIndex == toIndex}, the range to be sorted is empty. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(int[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(int[]) Arrays.sort} method. The algorithm requires a working + * space no greater than the size of the specified range of the original + * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is + * used to execute any parallel tasks. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + * + * @since 1.8 + */ + public static void parallelSort(int[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + int n = toIndex - fromIndex, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); + else + new ArraysParallelSortHelpers.FJInt.Sorter + (null, a, new int[n], fromIndex, n, 0, + ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g).invoke(); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(long[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(long[]) Arrays.sort} method. The algorithm requires a + * working space no greater than the size of the original array. The + * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to + * execute any parallel tasks. + * + * @param a the array to be sorted + * + * @since 1.8 + */ + public static void parallelSort(long[] a) { + int n = a.length, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0); + else + new ArraysParallelSortHelpers.FJLong.Sorter + (null, a, new long[n], 0, n, 0, + ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g).invoke(); + } + + /** + * Sorts the specified range of the array into ascending numerical order. + * The range to be sorted extends from the index {@code fromIndex}, + * inclusive, to the index {@code toIndex}, exclusive. If + * {@code fromIndex == toIndex}, the range to be sorted is empty. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(long[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(long[]) Arrays.sort} method. The algorithm requires a working + * space no greater than the size of the specified range of the original + * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is + * used to execute any parallel tasks. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + * + * @since 1.8 + */ + public static void parallelSort(long[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + int n = toIndex - fromIndex, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); + else + new ArraysParallelSortHelpers.FJLong.Sorter + (null, a, new long[n], fromIndex, n, 0, + ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g).invoke(); + } + + /** + * Sorts the specified array into ascending numerical order. + * + *

The {@code <} relation does not provide a total order on all float + * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Float#compareTo}: {@code -0.0f} is treated as less than value + * {@code 0.0f} and {@code Float.NaN} is considered greater than any + * other value and all {@code Float.NaN} values are considered equal. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(float[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(float[]) Arrays.sort} method. The algorithm requires a + * working space no greater than the size of the original array. The + * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to + * execute any parallel tasks. + * + * @param a the array to be sorted + * + * @since 1.8 + */ + public static void parallelSort(float[] a) { + int n = a.length, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0); + else + new ArraysParallelSortHelpers.FJFloat.Sorter + (null, a, new float[n], 0, n, 0, + ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g).invoke(); + } + + /** + * Sorts the specified range of the array into ascending numerical order. + * The range to be sorted extends from the index {@code fromIndex}, + * inclusive, to the index {@code toIndex}, exclusive. If + * {@code fromIndex == toIndex}, the range to be sorted is empty. + * + *

The {@code <} relation does not provide a total order on all float + * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Float#compareTo}: {@code -0.0f} is treated as less than value + * {@code 0.0f} and {@code Float.NaN} is considered greater than any + * other value and all {@code Float.NaN} values are considered equal. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(float[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(float[]) Arrays.sort} method. The algorithm requires a working + * space no greater than the size of the specified range of the original + * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is + * used to execute any parallel tasks. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + * + * @since 1.8 + */ + public static void parallelSort(float[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + int n = toIndex - fromIndex, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); + else + new ArraysParallelSortHelpers.FJFloat.Sorter + (null, a, new float[n], fromIndex, n, 0, + ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g).invoke(); + } + + /** + * Sorts the specified array into ascending numerical order. + * + *

The {@code <} relation does not provide a total order on all double + * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Double#compareTo}: {@code -0.0d} is treated as less than value + * {@code 0.0d} and {@code Double.NaN} is considered greater than any + * other value and all {@code Double.NaN} values are considered equal. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(double[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(double[]) Arrays.sort} method. The algorithm requires a + * working space no greater than the size of the original array. The + * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to + * execute any parallel tasks. + * + * @param a the array to be sorted + * + * @since 1.8 + */ + public static void parallelSort(double[] a) { + int n = a.length, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0); + else + new ArraysParallelSortHelpers.FJDouble.Sorter + (null, a, new double[n], 0, n, 0, + ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g).invoke(); + } + + /** + * Sorts the specified range of the array into ascending numerical order. + * The range to be sorted extends from the index {@code fromIndex}, + * inclusive, to the index {@code toIndex}, exclusive. If + * {@code fromIndex == toIndex}, the range to be sorted is empty. + * + *

The {@code <} relation does not provide a total order on all double + * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Double#compareTo}: {@code -0.0d} is treated as less than value + * {@code 0.0d} and {@code Double.NaN} is considered greater than any + * other value and all {@code Double.NaN} values are considered equal. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(double[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(double[]) Arrays.sort} method. The algorithm requires a working + * space no greater than the size of the specified range of the original + * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is + * used to execute any parallel tasks. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + * + * @since 1.8 + */ + public static void parallelSort(double[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + int n = toIndex - fromIndex, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); + else + new ArraysParallelSortHelpers.FJDouble.Sorter + (null, a, new double[n], fromIndex, n, 0, + ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g).invoke(); + } + + /** + * Sorts the specified array of objects into ascending order, according + * to the {@linkplain Comparable natural ordering} of its elements. + * All elements in the array must implement the {@link Comparable} + * interface. Furthermore, all elements in the array must be + * mutually comparable (that is, {@code e1.compareTo(e2)} must + * not throw a {@code ClassCastException} for any elements {@code e1} + * and {@code e2} in the array). + * + *

This sort is guaranteed to be stable: equal elements will + * not be reordered as a result of the sort. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a + * working space no greater than the size of the original array. The + * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to + * execute any parallel tasks. + * + * @param a the array to be sorted + * + * @throws ClassCastException if the array contains elements that are not + * mutually comparable (for example, strings and integers) + * @throws IllegalArgumentException (optional) if the natural + * ordering of the array elements is found to violate the + * {@link Comparable} contract + * + * @since 1.8 + */ + @SuppressWarnings("unchecked") + public static > void parallelSort(T[] a) { + int n = a.length, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + TimSort.sort(a, 0, n, NaturalOrder.INSTANCE, null, 0, 0); + else + new ArraysParallelSortHelpers.FJObject.Sorter + (null, a, + (T[])Array.newInstance(a.getClass().getComponentType(), n), + 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g, NaturalOrder.INSTANCE).invoke(); + } + + /** + * Sorts the specified range of the specified array of objects into + * ascending order, according to the + * {@linkplain Comparable natural ordering} of its + * elements. The range to be sorted extends from index + * {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive. + * (If {@code fromIndex==toIndex}, the range to be sorted is empty.) All + * elements in this range must implement the {@link Comparable} + * interface. Furthermore, all elements in this range must be mutually + * comparable (that is, {@code e1.compareTo(e2)} must not throw a + * {@code ClassCastException} for any elements {@code e1} and + * {@code e2} in the array). + * + *

This sort is guaranteed to be stable: equal elements will + * not be reordered as a result of the sort. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a working + * space no greater than the size of the specified range of the original + * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is + * used to execute any parallel tasks. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element (inclusive) to be + * sorted + * @param toIndex the index of the last element (exclusive) to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} or + * (optional) if the natural ordering of the array elements is + * found to violate the {@link Comparable} contract + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} + * @throws ClassCastException if the array contains elements that are + * not mutually comparable (for example, strings and + * integers). + * + * @since 1.8 + */ + @SuppressWarnings("unchecked") + public static > + void parallelSort(T[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + int n = toIndex - fromIndex, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + TimSort.sort(a, fromIndex, toIndex, NaturalOrder.INSTANCE, null, 0, 0); + else + new ArraysParallelSortHelpers.FJObject.Sorter + (null, a, + (T[])Array.newInstance(a.getClass().getComponentType(), n), + fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g, NaturalOrder.INSTANCE).invoke(); + } + + /** + * Sorts the specified array of objects according to the order induced by + * the specified comparator. All elements in the array must be + * mutually comparable by the specified comparator (that is, + * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException} + * for any elements {@code e1} and {@code e2} in the array). + * + *

This sort is guaranteed to be stable: equal elements will + * not be reordered as a result of the sort. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a + * working space no greater than the size of the original array. The + * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to + * execute any parallel tasks. + * + * @param a the array to be sorted + * @param cmp the comparator to determine the order of the array. A + * {@code null} value indicates that the elements' + * {@linkplain Comparable natural ordering} should be used. + * @throws ClassCastException if the array contains elements that are + * not mutually comparable using the specified comparator + * @throws IllegalArgumentException (optional) if the comparator is + * found to violate the {@link java.util.Comparator} contract + * + * @since 1.8 + */ + @SuppressWarnings("unchecked") + public static void parallelSort(T[] a, Comparator cmp) { + if (cmp == null) + cmp = NaturalOrder.INSTANCE; + int n = a.length, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + TimSort.sort(a, 0, n, cmp, null, 0, 0); + else + new ArraysParallelSortHelpers.FJObject.Sorter + (null, a, + (T[])Array.newInstance(a.getClass().getComponentType(), n), + 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g, cmp).invoke(); + } + + /** + * Sorts the specified range of the specified array of objects according + * to the order induced by the specified comparator. The range to be + * sorted extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the + * range to be sorted is empty.) All elements in the range must be + * mutually comparable by the specified comparator (that is, + * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException} + * for any elements {@code e1} and {@code e2} in the range). + * + *

This sort is guaranteed to be stable: equal elements will + * not be reordered as a result of the sort. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a working + * space no greater than the size of the specified range of the original + * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is + * used to execute any parallel tasks. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element (inclusive) to be + * sorted + * @param toIndex the index of the last element (exclusive) to be sorted + * @param cmp the comparator to determine the order of the array. A + * {@code null} value indicates that the elements' + * {@linkplain Comparable natural ordering} should be used. + * @throws IllegalArgumentException if {@code fromIndex > toIndex} or + * (optional) if the natural ordering of the array elements is + * found to violate the {@link Comparable} contract + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} + * @throws ClassCastException if the array contains elements that are + * not mutually comparable (for example, strings and + * integers). + * + * @since 1.8 + */ + @SuppressWarnings("unchecked") + public static void parallelSort(T[] a, int fromIndex, int toIndex, + Comparator cmp) { + rangeCheck(a.length, fromIndex, toIndex); + if (cmp == null) + cmp = NaturalOrder.INSTANCE; + int n = toIndex - fromIndex, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + TimSort.sort(a, fromIndex, toIndex, cmp, null, 0, 0); + else + new ArraysParallelSortHelpers.FJObject.Sorter + (null, a, + (T[])Array.newInstance(a.getClass().getComponentType(), n), + fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g, cmp).invoke(); } /* @@ -412,39 +1191,6 @@ "java.util.Arrays.useLegacyMergeSort")).booleanValue(); } - /* - * If this platform has an optimizing VM, check whether ComparableTimSort - * offers any performance benefit over TimSort in conjunction with a - * comparator that returns: - * {@code ((Comparable)first).compareTo(Second)}. - * If not, you are better off deleting ComparableTimSort to - * eliminate the code duplication. In other words, the commented - * out code below is the preferable implementation for sorting - * arrays of Comparables if it offers sufficient performance. - */ - -// /** -// * A comparator that implements the natural ordering of a group of -// * mutually comparable elements. Using this comparator saves us -// * from duplicating most of the code in this file (one version for -// * Comparables, one for explicit Comparators). -// */ -// private static final Comparator NATURAL_ORDER = -// new Comparator() { -// @SuppressWarnings("unchecked") -// public int compare(Object first, Object second) { -// return ((Comparable)first).compareTo(second); -// } -// }; -// -// public static void sort(Object[] a) { -// sort(a, 0, a.length, NATURAL_ORDER); -// } -// -// public static void sort(Object[] a, int fromIndex, int toIndex) { -// sort(a, fromIndex, toIndex, NATURAL_ORDER); -// } - /** * Sorts the specified array of objects into ascending order, according * to the {@linkplain Comparable natural ordering} of its elements. @@ -491,7 +1237,7 @@ if (LegacyMergeSort.userRequested) legacyMergeSort(a); else - ComparableTimSort.sort(a); + ComparableTimSort.sort(a, 0, a.length, null, 0, 0); } /** To be removed in a future release. */ @@ -553,16 +1299,16 @@ * integers). */ public static void sort(Object[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); if (LegacyMergeSort.userRequested) legacyMergeSort(a, fromIndex, toIndex); else - ComparableTimSort.sort(a, fromIndex, toIndex); + ComparableTimSort.sort(a, fromIndex, toIndex, null, 0, 0); } /** To be removed in a future release. */ private static void legacyMergeSort(Object[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); Object[] aux = copyOfRange(a, fromIndex, toIndex); mergeSort(aux, a, fromIndex, toIndex, -fromIndex); } @@ -676,10 +1422,12 @@ * found to violate the {@link Comparator} contract */ public static void sort(T[] a, Comparator c) { + if (c == null) + c = NaturalOrder.INSTANCE; if (LegacyMergeSort.userRequested) legacyMergeSort(a, c); else - TimSort.sort(a, c); + TimSort.sort(a, 0, a.length, c, null, 0, 0); } /** To be removed in a future release. */ @@ -744,16 +1492,18 @@ */ public static void sort(T[] a, int fromIndex, int toIndex, Comparator c) { + if (c == null) + c = NaturalOrder.INSTANCE; + rangeCheck(a.length, fromIndex, toIndex); if (LegacyMergeSort.userRequested) legacyMergeSort(a, fromIndex, toIndex, c); else - TimSort.sort(a, fromIndex, toIndex, c); + TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0); } /** To be removed in a future release. */ private static void legacyMergeSort(T[] a, int fromIndex, int toIndex, Comparator c) { - rangeCheck(a.length, fromIndex, toIndex); T[] aux = copyOfRange(a, fromIndex, toIndex); if (c==null) mergeSort(aux, a, fromIndex, toIndex, -fromIndex); @@ -809,630 +1559,6 @@ } } - /* - * Parallel sorting of primitive type arrays. - */ - - /** - * Sorts the specified array into ascending numerical order. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(byte[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * - * @since 1.8 - */ - public static void parallelSort(byte[] a) { - parallelSort(a, 0, a.length); - } - - /** - * Sorts the specified range of the array into ascending order. The range - * to be sorted extends from the index {@code fromIndex}, inclusive, to - * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(byte[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - * - * @since 1.8 - */ - public static void parallelSort(byte[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - int nelements = toIndex - fromIndex; - int gran = getSplitThreshold(nelements); - FJByte.Sorter task = new FJByte.Sorter(a, new byte[a.length], fromIndex, - nelements, gran); - task.invoke(); - } - - /** - * Sorts the specified array into ascending numerical order. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(char[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * - * @since 1.8 - */ - public static void parallelSort(char[] a) { - parallelSort(a, 0, a.length); - } - - /** - * Sorts the specified range of the array into ascending order. The range - * to be sorted extends from the index {@code fromIndex}, inclusive, to - * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(char[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - * - * @since 1.8 - */ - public static void parallelSort(char[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - int nelements = toIndex - fromIndex; - int gran = getSplitThreshold(nelements); - FJChar.Sorter task = new FJChar.Sorter(a, new char[a.length], fromIndex, - nelements, gran); - task.invoke(); - } - - /** - * Sorts the specified array into ascending numerical order. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(short[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * - * @since 1.8 - */ - public static void parallelSort(short[] a) { - parallelSort(a, 0, a.length); - } - - /** - * Sorts the specified range of the array into ascending order. The range - * to be sorted extends from the index {@code fromIndex}, inclusive, to - * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(short[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - * - * @since 1.8 - */ - public static void parallelSort(short[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - int nelements = toIndex - fromIndex; - int gran = getSplitThreshold(nelements); - FJShort.Sorter task = new FJShort.Sorter(a, new short[a.length], fromIndex, - nelements, gran); - task.invoke(); - } - - /** - * Sorts the specified array into ascending numerical order. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(int[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * - * @since 1.8 - */ - public static void parallelSort(int[] a) { - parallelSort(a, 0, a.length); - } - - /** - * Sorts the specified range of the array into ascending order. The range - * to be sorted extends from the index {@code fromIndex}, inclusive, to - * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(int[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - * - * @since 1.8 - */ - public static void parallelSort(int[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - int nelements = toIndex - fromIndex; - int gran = getSplitThreshold(nelements); - FJInt.Sorter task = new FJInt.Sorter(a, new int[a.length], fromIndex, - nelements, gran); - task.invoke(); - } - - /** - * Sorts the specified array into ascending numerical order. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(long[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * - * @since 1.8 - */ - public static void parallelSort(long[] a) { - parallelSort(a, 0, a.length); - } - - /** - * Sorts the specified range of the array into ascending order. The range - * to be sorted extends from the index {@code fromIndex}, inclusive, to - * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(long[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - * - * @since 1.8 - */ - public static void parallelSort(long[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - int nelements = toIndex - fromIndex; - int gran = getSplitThreshold(nelements); - FJLong.Sorter task = new FJLong.Sorter(a, new long[a.length], fromIndex, - nelements, gran); - task.invoke(); - } - - /** - * Sorts the specified array into ascending numerical order. - * - *

The {@code <} relation does not provide a total order on all float - * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} - * value compares neither less than, greater than, nor equal to any value, - * even itself. This method uses the total order imposed by the method - * {@link Float#compareTo}: {@code -0.0f} is treated as less than value - * {@code 0.0f} and {@code Float.NaN} is considered greater than any - * other value and all {@code Float.NaN} values are considered equal. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(float[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * - * @since 1.8 - */ - public static void parallelSort(float[] a) { - parallelSort(a, 0, a.length); - } - - /** - * Sorts the specified range of the array into ascending order. The range - * to be sorted extends from the index {@code fromIndex}, inclusive, to - * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty. - * - *

The {@code <} relation does not provide a total order on all float - * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} - * value compares neither less than, greater than, nor equal to any value, - * even itself. This method uses the total order imposed by the method - * {@link Float#compareTo}: {@code -0.0f} is treated as less than value - * {@code 0.0f} and {@code Float.NaN} is considered greater than any - * other value and all {@code Float.NaN} values are considered equal. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(float[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - * - * @since 1.8 - */ - public static void parallelSort(float[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - int nelements = toIndex - fromIndex; - int gran = getSplitThreshold(nelements); - FJFloat.Sorter task = new FJFloat.Sorter(a, new float[a.length], fromIndex, - nelements, gran); - task.invoke(); - } - - /** - * Sorts the specified array into ascending numerical order. - * - *

The {@code <} relation does not provide a total order on all double - * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} - * value compares neither less than, greater than, nor equal to any value, - * even itself. This method uses the total order imposed by the method - * {@link Double#compareTo}: {@code -0.0d} is treated as less than value - * {@code 0.0d} and {@code Double.NaN} is considered greater than any - * other value and all {@code Double.NaN} values are considered equal. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(double[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * - * @since 1.8 - */ - public static void parallelSort(double[] a) { - parallelSort(a, 0, a.length); - } - - /** - * Sorts the specified range of the array into ascending order. The range - * to be sorted extends from the index {@code fromIndex}, inclusive, to - * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty. - * - *

The {@code <} relation does not provide a total order on all double - * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} - * value compares neither less than, greater than, nor equal to any value, - * even itself. This method uses the total order imposed by the method - * {@link Double#compareTo}: {@code -0.0d} is treated as less than value - * {@code 0.0d} and {@code Double.NaN} is considered greater than any - * other value and all {@code Double.NaN} values are considered equal. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(double[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - * - * @since 1.8 - */ - public static void parallelSort(double[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - int nelements = toIndex - fromIndex; - int gran = getSplitThreshold(nelements); - FJDouble.Sorter task = new FJDouble.Sorter(a, new double[a.length], - fromIndex, nelements, gran); - task.invoke(); - } - - /* - * Parallel sorting of complex type arrays. - */ - - /** - * Sorts the specified array of objects into ascending order, according - * to the {@linkplain Comparable natural ordering} of its elements. - * All elements in the array must implement the {@link Comparable} - * interface. Furthermore, all elements in the array must be - * mutually comparable (that is, {@code e1.compareTo(e2)} must - * not throw a {@code ClassCastException} for any elements {@code e1} - * and {@code e2} in the array). - * - *

This sort is not guaranteed to be stable: equal elements - * may be reordered as a result of the sort. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(Object[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * - * @throws ClassCastException if the array contains elements that are not - * mutually comparable (for example, strings and integers) - * @throws IllegalArgumentException (optional) if the natural - * ordering of the array elements is found to violate the - * {@link Comparable} contract - * - * @since 1.8 - */ - public static > void parallelSort(T[] a) { - parallelSort(a, 0, a.length); - } - - /** - * Sorts the specified range of the specified array of objects into - * ascending order, according to the - * {@linkplain Comparable natural ordering} of its - * elements. The range to be sorted extends from index - * {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive. - * (If {@code fromIndex==toIndex}, the range to be sorted is empty.) All - * elements in this range must implement the {@link Comparable} - * interface. Furthermore, all elements in this range must be mutually - * comparable (that is, {@code e1.compareTo(e2)} must not throw a - * {@code ClassCastException} for any elements {@code e1} and - * {@code e2} in the array). - * - *

This sort is not guaranteed to be stable: equal elements - * may be reordered as a result of the sort. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(Object[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element (inclusive) to be - * sorted - * @param toIndex the index of the last element (exclusive) to be sorted - * @throws IllegalArgumentException if {@code fromIndex > toIndex} or - * (optional) if the natural ordering of the array elements is - * found to violate the {@link Comparable} contract - * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or - * {@code toIndex > a.length} - * @throws ClassCastException if the array contains elements that are - * not mutually comparable (for example, strings and - * integers). - * - * @since 1.8 - */ - public static > - void parallelSort(T[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - int nelements = toIndex - fromIndex; - Class tc = a.getClass().getComponentType(); - @SuppressWarnings("unchecked") - T[] workspace = (T[])Array.newInstance(tc, a.length); - int gran = getSplitThreshold(nelements); - FJComparable.Sorter task = new FJComparable.Sorter<>(a, workspace, - fromIndex, - nelements, gran); - task.invoke(); - } - - /** - * Sorts the specified array of objects according to the order induced by - * the specified comparator. All elements in the array must be - * mutually comparable by the specified comparator (that is, - * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException} - * for any elements {@code e1} and {@code e2} in the array). - * - *

This sort is not guaranteed to be stable: equal elements - * may be reordered as a result of the sort. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(Object[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param c the comparator to determine the order of the array. A - * {@code null} value indicates that the elements' - * {@linkplain Comparable natural ordering} should be used. - * @throws ClassCastException if the array contains elements that are - * not mutually comparable using the specified comparator - * @throws IllegalArgumentException (optional) if the comparator is - * found to violate the {@link java.util.Comparator} contract - * - * @since 1.8 - */ - public static void parallelSort(T[] a, Comparator c) { - parallelSort(a, 0, a.length, c); - } - - /** - * Sorts the specified range of the specified array of objects according - * to the order induced by the specified comparator. The range to be - * sorted extends from index {@code fromIndex}, inclusive, to index - * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the - * range to be sorted is empty.) All elements in the range must be - * mutually comparable by the specified comparator (that is, - * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException} - * for any elements {@code e1} and {@code e2} in the range). - * - *

This sort is not guaranteed to be stable: equal elements - * may be reordered as a result of the sort. - * - *

Implementation note: The sorting algorithm is a parallel sort-merge - * that breaks the array into sub-arrays that are themselves sorted and then - * merged. When the sub-array length reaches a minimum granularity, the - * sub-array is sorted using the appropriate {@link Arrays#sort(Object[]) - * Arrays.sort} method. The algorithm requires a working space equal to the - * size of the original array. The {@link - * java.util.concurrent.ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element (inclusive) to be - * sorted - * @param toIndex the index of the last element (exclusive) to be sorted - * @param c the comparator to determine the order of the array. A - * {@code null} value indicates that the elements' - * {@linkplain Comparable natural ordering} should be used. - * @throws IllegalArgumentException if {@code fromIndex > toIndex} or - * (optional) if the natural ordering of the array elements is - * found to violate the {@link Comparable} contract - * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or - * {@code toIndex > a.length} - * @throws ClassCastException if the array contains elements that are - * not mutually comparable (for example, strings and - * integers). - * - * @since 1.8 - */ - public static void parallelSort(T[] a, int fromIndex, int toIndex, - Comparator c) { - rangeCheck(a.length, fromIndex, toIndex); - int nelements = toIndex - fromIndex; - Class tc = a.getClass().getComponentType(); - @SuppressWarnings("unchecked") - T[] workspace = (T[])Array.newInstance(tc, a.length); - int gran = getSplitThreshold(nelements); - FJComparator.Sorter task = new FJComparator.Sorter<>(a, workspace, - fromIndex, - nelements, gran, c); - task.invoke(); - } - - /** - * Returns the size threshold for splitting into subtasks. - * By default, uses about 8 times as many tasks as threads - * - * @param n number of elements in the array to be processed - */ - private static int getSplitThreshold(int n) { - int p = java.util.concurrent.ForkJoinPool.getCommonPoolParallelism(); - int t = (p > 1) ? (1 + n / (p << 3)) : n; - return t < MIN_ARRAY_SORT_GRAN ? MIN_ARRAY_SORT_GRAN : t; - } - - /** - * Checks that {@code fromIndex} and {@code toIndex} are in - * the range and throws an appropriate exception, if they aren't. - */ - private static void rangeCheck(int length, int fromIndex, int toIndex) { - if (fromIndex > toIndex) { - throw new IllegalArgumentException( - "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); - } - if (fromIndex < 0) { - throw new ArrayIndexOutOfBoundsException(fromIndex); - } - if (toIndex > length) { - throw new ArrayIndexOutOfBoundsException(toIndex); - } - } - // Searching /** diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/util/ArraysParallelSortHelpers.java --- a/jdk/src/share/classes/java/util/ArraysParallelSortHelpers.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/util/ArraysParallelSortHelpers.java Wed Jul 05 18:57:52 2017 +0200 @@ -25,6 +25,7 @@ package java.util; import java.util.concurrent.RecursiveAction; +import java.util.concurrent.CountedCompleter; /** * Helper utilities for the parallel sort methods in Arrays.parallelSort. @@ -44,1180 +45,966 @@ * c. merge them together * 3. merge together the two halves. * - * One reason for splitting in quarters is that this guarantees - * that the final sort is in the main array, not the workspace - * array. (workspace and main swap roles on each subsort step.) - * Leaf-level sorts use a Sequential quicksort, that in turn uses - * insertion sort if under threshold. Otherwise it uses median of - * three to pick pivot, and loops rather than recurses along left - * path. - * + * One reason for splitting in quarters is that this guarantees that + * the final sort is in the main array, not the workspace array. + * (workspace and main swap roles on each subsort step.) Leaf-level + * sorts use the associated sequential sort. * - * Merger classes perform merging for Sorter. If big enough, splits Left - * partition in half; finds the greatest point in Right partition - * less than the beginning of the second half of Left via binary - * search; and then, in parallel, merges left half of Left with - * elements of Right up to split point, and merges right half of - * Left with elements of R past split point. At leaf, it just - * sequentially merges. This is all messy to code; sadly we need - * distinct versions for each type. + * Merger classes perform merging for Sorter. They are structured + * such that if the underlying sort is stable (as is true for + * TimSort), then so is the full sort. If big enough, they split the + * largest of the two partitions in half, find the greatest point in + * smaller partition less than the beginning of the second half of + * larger via binary search; and then merge in parallel the two + * partitions. In part to ensure tasks are triggered in + * stability-preserving order, the current CountedCompleter design + * requires some little tasks to serve as place holders for triggering + * completion tasks. These classes (EmptyCompleter and Relay) don't + * need to keep track of the arrays, and are never themselves forked, + * so don't hold any task state. * + * The primitive class versions (FJByte... FJDouble) are + * identical to each other except for type declarations. + * + * The base sequential sorts rely on non-public versions of TimSort, + * ComparableTimSort, and DualPivotQuicksort sort methods that accept + * temp workspace array slices that we will have already allocated, so + * avoids redundant allocation. (Except for DualPivotQuicksort byte[] + * sort, that does not ever use a workspace array.) */ /*package*/ class ArraysParallelSortHelpers { - // RFE: we should only need a working array as large as the subarray - // to be sorted, but the logic assumes that indices in the two - // arrays always line-up + /* + * Style note: The task classes have a lot of parameters, that are + * stored as task fields and copied to local variables and used in + * compute() methods, We pack these into as few lines as possible, + * and hoist consistency checks among them before main loops, to + * reduce distraction. + */ - /** byte support class */ - static final class FJByte { - static final class Sorter extends RecursiveAction { - static final long serialVersionUID = 749471161188027634L; - final byte[] a; // array to be sorted. - final byte[] w; // workspace for merge - final int origin; // origin of the part of array we deal with - final int n; // Number of elements in (sub)arrays. - final int gran; // split control + /** + * A placeholder task for Sorters, used for the lowest + * quartile task, that does not need to maintain array state. + */ + static final class EmptyCompleter extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + EmptyCompleter(CountedCompleter p) { super(p); } + public final void compute() { } + } - Sorter(byte[] a, byte[] w, int origin, int n, int gran) { - this.a = a; - this.w = w; - this.origin = origin; - this.n = n; - this.gran = gran; - } + /** + * A trigger for secondary merge of two merges + */ + static final class Relay extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final CountedCompleter task; + Relay(CountedCompleter task) { + super(null, 1); + this.task = task; + } + public final void compute() { } + public final void onCompletion(CountedCompleter t) { + task.compute(); + } + } - public void compute() { - final int l = origin; - final int g = gran; - final int n = this.n; - final byte[] a = this.a; - final byte[] w = this.w; - if (n > g) { - int h = n >>> 1; // half - int q = n >>> 2; // lower quarter index - int u = h + q; // upper quarter - FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q, g), - new Sorter(a, w, l+q, h-q, g), - new Merger(a, w, l, q, - l+q, h-q, l, g, null)); - FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l+h, q, g), - new Sorter(a, w, l+u, n-u, g), - new Merger(a, w, l+h, q, - l+u, n-u, l+h, g, null)); - rs.fork(); - ls.compute(); - if (rs.tryUnfork()) rs.compute(); else rs.join(); - new Merger(w, a, l, h, - l+h, n-h, l, g, null).compute(); - } else { - DualPivotQuicksort.sort(a, l, l+n-1); //skip rangeCheck + /** Object + Comparator support class */ + static final class FJObject { + static final class Sorter extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final T[] a, w; + final int base, size, wbase, gran; + Comparator comparator; + Sorter(CountedCompleter par, T[] a, T[] w, int base, int size, + int wbase, int gran, + Comparator comparator) { + super(par); + this.a = a; this.w = w; this.base = base; this.size = size; + this.wbase = wbase; this.gran = gran; + this.comparator = comparator; + } + public final void compute() { + CountedCompleter s = this; + Comparator c = this.comparator; + T[] a = this.a, w = this.w; // localize all params + int b = this.base, n = this.size, wb = this.wbase, g = this.gran; + while (n > g) { + int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles + Relay fc = new Relay(new Merger(s, w, a, wb, h, + wb+h, n-h, b, g, c)); + Relay rc = new Relay(new Merger(fc, a, w, b+h, q, + b+u, n-u, wb+h, g, c)); + new Sorter(rc, a, w, b+u, n-u, wb+u, g, c).fork(); + new Sorter(rc, a, w, b+h, q, wb+h, g, c).fork();; + Relay bc = new Relay(new Merger(fc, a, w, b, q, + b+q, h-q, wb, g, c)); + new Sorter(bc, a, w, b+q, h-q, wb+q, g, c).fork(); + s = new EmptyCompleter(bc); + n = q; } + TimSort.sort(a, b, b + n, c, w, wb, n); + s.tryComplete(); } } - static final class Merger extends RecursiveAction { - static final long serialVersionUID = -9090258248781844470L; - final byte[] a; - final byte[] w; - final int lo; - final int ln; - final int ro; - final int rn; - final int wo; - final int gran; - final Merger next; + static final class Merger extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final T[] a, w; // main and workspace arrays + final int lbase, lsize, rbase, rsize, wbase, gran; + Comparator comparator; + Merger(CountedCompleter par, T[] a, T[] w, + int lbase, int lsize, int rbase, + int rsize, int wbase, int gran, + Comparator comparator) { + super(par); + this.a = a; this.w = w; + this.lbase = lbase; this.lsize = lsize; + this.rbase = rbase; this.rsize = rsize; + this.wbase = wbase; this.gran = gran; + this.comparator = comparator; + } - Merger(byte[] a, byte[] w, int lo, int ln, int ro, int rn, int wo, - int gran, Merger next) { - this.a = a; - this.w = w; - this.lo = lo; - this.ln = ln; - this.ro = ro; - this.rn = rn; - this.wo = wo; - this.gran = gran; - this.next = next; + public final void compute() { + Comparator c = this.comparator; + T[] a = this.a, w = this.w; // localize all params + int lb = this.lbase, ln = this.lsize, rb = this.rbase, + rn = this.rsize, k = this.wbase, g = this.gran; + if (a == null || w == null || lb < 0 || rb < 0 || k < 0 || + c == null) + throw new IllegalStateException(); // hoist checks + for (int lh, rh;;) { // split larger, find point in smaller + if (ln >= rn) { + if (ln <= g) + break; + rh = rn; + T split = a[(lh = ln >>> 1) + lb]; + for (int lo = 0; lo < rh; ) { + int rm = (lo + rh) >>> 1; + if (c.compare(split, a[rm + rb]) <= 0) + rh = rm; + else + lo = rm + 1; + } + } + else { + if (rn <= g) + break; + lh = ln; + T split = a[(rh = rn >>> 1) + rb]; + for (int lo = 0; lo < lh; ) { + int lm = (lo + lh) >>> 1; + if (c.compare(split, a[lm + lb]) <= 0) + lh = lm; + else + lo = lm + 1; + } + } + Merger m = new Merger(this, a, w, lb + lh, ln - lh, + rb + rh, rn - rh, + k + lh + rh, g, c); + rn = rh; + ln = lh; + addToPendingCount(1); + m.fork(); + } + + int lf = lb + ln, rf = rb + rn; // index bounds + while (lb < lf && rb < rf) { + T t, al, ar; + if (c.compare((al = a[lb]), (ar = a[rb])) <= 0) { + lb++; t = al; + } + else { + rb++; t = ar; + } + w[k++] = t; + } + if (rb < rf) + System.arraycopy(a, rb, w, k, rf - rb); + else if (lb < lf) + System.arraycopy(a, lb, w, k, lf - lb); + + tryComplete(); } - public void compute() { - final byte[] a = this.a; - final byte[] w = this.w; - Merger rights = null; - int nleft = ln; - int nright = rn; - while (nleft > gran) { - int lh = nleft >>> 1; - int splitIndex = lo + lh; - byte split = a[splitIndex]; - int rl = 0; - int rh = nright; - while (rl < rh) { - int mid = (rl + rh) >>> 1; - if (split <= a[ro + mid]) - rh = mid; - else - rl = mid + 1; + } + } // FJObject + + /** byte support class */ + static final class FJByte { + static final class Sorter extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final byte[] a, w; + final int base, size, wbase, gran; + Sorter(CountedCompleter par, byte[] a, byte[] w, int base, + int size, int wbase, int gran) { + super(par); + this.a = a; this.w = w; this.base = base; this.size = size; + this.wbase = wbase; this.gran = gran; + } + public final void compute() { + CountedCompleter s = this; + byte[] a = this.a, w = this.w; // localize all params + int b = this.base, n = this.size, wb = this.wbase, g = this.gran; + while (n > g) { + int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles + Relay fc = new Relay(new Merger(s, w, a, wb, h, + wb+h, n-h, b, g)); + Relay rc = new Relay(new Merger(fc, a, w, b+h, q, + b+u, n-u, wb+h, g)); + new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); + new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; + Relay bc = new Relay(new Merger(fc, a, w, b, q, + b+q, h-q, wb, g)); + new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); + s = new EmptyCompleter(bc); + n = q; + } + DualPivotQuicksort.sort(a, b, b + n - 1); + s.tryComplete(); + } + } + + static final class Merger extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final byte[] a, w; // main and workspace arrays + final int lbase, lsize, rbase, rsize, wbase, gran; + Merger(CountedCompleter par, byte[] a, byte[] w, + int lbase, int lsize, int rbase, + int rsize, int wbase, int gran) { + super(par); + this.a = a; this.w = w; + this.lbase = lbase; this.lsize = lsize; + this.rbase = rbase; this.rsize = rsize; + this.wbase = wbase; this.gran = gran; + } + + public final void compute() { + byte[] a = this.a, w = this.w; // localize all params + int lb = this.lbase, ln = this.lsize, rb = this.rbase, + rn = this.rsize, k = this.wbase, g = this.gran; + if (a == null || w == null || lb < 0 || rb < 0 || k < 0) + throw new IllegalStateException(); // hoist checks + for (int lh, rh;;) { // split larger, find point in smaller + if (ln >= rn) { + if (ln <= g) + break; + rh = rn; + byte split = a[(lh = ln >>> 1) + lb]; + for (int lo = 0; lo < rh; ) { + int rm = (lo + rh) >>> 1; + if (split <= a[rm + rb]) + rh = rm; + else + lo = rm + 1; + } } - (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh, - nright-rh, wo+lh+rh, gran, rights)).fork(); - nleft = lh; - nright = rh; + else { + if (rn <= g) + break; + lh = ln; + byte split = a[(rh = rn >>> 1) + rb]; + for (int lo = 0; lo < lh; ) { + int lm = (lo + lh) >>> 1; + if (split <= a[lm + lb]) + lh = lm; + else + lo = lm + 1; + } + } + Merger m = new Merger(this, a, w, lb + lh, ln - lh, + rb + rh, rn - rh, + k + lh + rh, g); + rn = rh; + ln = lh; + addToPendingCount(1); + m.fork(); } - int l = lo; - int lFence = l + nleft; - int r = ro; - int rFence = r + nright; - int k = wo; - while (l < lFence && r < rFence) { - byte al = a[l]; - byte ar = a[r]; - byte t; - if (al <= ar) {++l; t=al;} else {++r; t = ar;} + int lf = lb + ln, rf = rb + rn; // index bounds + while (lb < lf && rb < rf) { + byte t, al, ar; + if ((al = a[lb]) <= (ar = a[rb])) { + lb++; t = al; + } + else { + rb++; t = ar; + } w[k++] = t; } - while (l < lFence) - w[k++] = a[l++]; - while (r < rFence) - w[k++] = a[r++]; - while (rights != null) { - if (rights.tryUnfork()) - rights.compute(); - else - rights.join(); - rights = rights.next; - } + if (rb < rf) + System.arraycopy(a, rb, w, k, rf - rb); + else if (lb < lf) + System.arraycopy(a, lb, w, k, lf - lb); + tryComplete(); } } } // FJByte /** char support class */ static final class FJChar { - static final class Sorter extends RecursiveAction { - static final long serialVersionUID = 8723376019074596641L; - final char[] a; // array to be sorted. - final char[] w; // workspace for merge - final int origin; // origin of the part of array we deal with - final int n; // Number of elements in (sub)arrays. - final int gran; // split control - - Sorter(char[] a, char[] w, int origin, int n, int gran) { - this.a = a; - this.w = w; - this.origin = origin; - this.n = n; - this.gran = gran; + static final class Sorter extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final char[] a, w; + final int base, size, wbase, gran; + Sorter(CountedCompleter par, char[] a, char[] w, int base, + int size, int wbase, int gran) { + super(par); + this.a = a; this.w = w; this.base = base; this.size = size; + this.wbase = wbase; this.gran = gran; } - - public void compute() { - final int l = origin; - final int g = gran; - final int n = this.n; - final char[] a = this.a; - final char[] w = this.w; - if (n > g) { - int h = n >>> 1; // half - int q = n >>> 2; // lower quarter index - int u = h + q; // upper quarter - FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q, g), - new Sorter(a, w, l+q, h-q, g), - new Merger(a, w, l, q, - l+q, h-q, l, g, null)); - FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q, g), - new Sorter(a, w, l+u, n-u, g), - new Merger(a, w, l+h, q, - l+u, n-u, l+h, g, null)); - rs.fork(); - ls.compute(); - if (rs.tryUnfork()) rs.compute(); else rs.join(); - new Merger(w, a, l, h, l + h, n - h, l, g, null).compute(); - } else { - DualPivotQuicksort.sort(a, l, l+n-1); // skip rangeCheck + public final void compute() { + CountedCompleter s = this; + char[] a = this.a, w = this.w; // localize all params + int b = this.base, n = this.size, wb = this.wbase, g = this.gran; + while (n > g) { + int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles + Relay fc = new Relay(new Merger(s, w, a, wb, h, + wb+h, n-h, b, g)); + Relay rc = new Relay(new Merger(fc, a, w, b+h, q, + b+u, n-u, wb+h, g)); + new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); + new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; + Relay bc = new Relay(new Merger(fc, a, w, b, q, + b+q, h-q, wb, g)); + new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); + s = new EmptyCompleter(bc); + n = q; } + DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); + s.tryComplete(); } } - static final class Merger extends RecursiveAction { - static final long serialVersionUID = -1383975444621698926L; - final char[] a; - final char[] w; - final int lo; - final int ln; - final int ro; - final int rn; - final int wo; - final int gran; - final Merger next; - - Merger(char[] a, char[] w, int lo, int ln, int ro, int rn, int wo, - int gran, Merger next) { - this.a = a; - this.w = w; - this.lo = lo; - this.ln = ln; - this.ro = ro; - this.rn = rn; - this.wo = wo; - this.gran = gran; - this.next = next; + static final class Merger extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final char[] a, w; // main and workspace arrays + final int lbase, lsize, rbase, rsize, wbase, gran; + Merger(CountedCompleter par, char[] a, char[] w, + int lbase, int lsize, int rbase, + int rsize, int wbase, int gran) { + super(par); + this.a = a; this.w = w; + this.lbase = lbase; this.lsize = lsize; + this.rbase = rbase; this.rsize = rsize; + this.wbase = wbase; this.gran = gran; } - public void compute() { - final char[] a = this.a; - final char[] w = this.w; - Merger rights = null; - int nleft = ln; - int nright = rn; - while (nleft > gran) { - int lh = nleft >>> 1; - int splitIndex = lo + lh; - char split = a[splitIndex]; - int rl = 0; - int rh = nright; - while (rl < rh) { - int mid = (rl + rh) >>> 1; - if (split <= a[ro + mid]) - rh = mid; - else - rl = mid + 1; + public final void compute() { + char[] a = this.a, w = this.w; // localize all params + int lb = this.lbase, ln = this.lsize, rb = this.rbase, + rn = this.rsize, k = this.wbase, g = this.gran; + if (a == null || w == null || lb < 0 || rb < 0 || k < 0) + throw new IllegalStateException(); // hoist checks + for (int lh, rh;;) { // split larger, find point in smaller + if (ln >= rn) { + if (ln <= g) + break; + rh = rn; + char split = a[(lh = ln >>> 1) + lb]; + for (int lo = 0; lo < rh; ) { + int rm = (lo + rh) >>> 1; + if (split <= a[rm + rb]) + rh = rm; + else + lo = rm + 1; + } } - (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh, - nright-rh, wo+lh+rh, gran, rights)).fork(); - nleft = lh; - nright = rh; + else { + if (rn <= g) + break; + lh = ln; + char split = a[(rh = rn >>> 1) + rb]; + for (int lo = 0; lo < lh; ) { + int lm = (lo + lh) >>> 1; + if (split <= a[lm + lb]) + lh = lm; + else + lo = lm + 1; + } + } + Merger m = new Merger(this, a, w, lb + lh, ln - lh, + rb + rh, rn - rh, + k + lh + rh, g); + rn = rh; + ln = lh; + addToPendingCount(1); + m.fork(); } - int l = lo; - int lFence = l + nleft; - int r = ro; - int rFence = r + nright; - int k = wo; - while (l < lFence && r < rFence) { - char al = a[l]; - char ar = a[r]; - char t; - if (al <= ar) {++l; t=al;} else {++r; t = ar;} + int lf = lb + ln, rf = rb + rn; // index bounds + while (lb < lf && rb < rf) { + char t, al, ar; + if ((al = a[lb]) <= (ar = a[rb])) { + lb++; t = al; + } + else { + rb++; t = ar; + } w[k++] = t; } - while (l < lFence) - w[k++] = a[l++]; - while (r < rFence) - w[k++] = a[r++]; - while (rights != null) { - if (rights.tryUnfork()) - rights.compute(); - else - rights.join(); - rights = rights.next; - } + if (rb < rf) + System.arraycopy(a, rb, w, k, rf - rb); + else if (lb < lf) + System.arraycopy(a, lb, w, k, lf - lb); + tryComplete(); } } } // FJChar /** short support class */ static final class FJShort { - static final class Sorter extends RecursiveAction { - static final long serialVersionUID = -7886754793730583084L; - final short[] a; // array to be sorted. - final short[] w; // workspace for merge - final int origin; // origin of the part of array we deal with - final int n; // Number of elements in (sub)arrays. - final int gran; // split control - - Sorter(short[] a, short[] w, int origin, int n, int gran) { - this.a = a; - this.w = w; - this.origin = origin; - this.n = n; - this.gran = gran; + static final class Sorter extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final short[] a, w; + final int base, size, wbase, gran; + Sorter(CountedCompleter par, short[] a, short[] w, int base, + int size, int wbase, int gran) { + super(par); + this.a = a; this.w = w; this.base = base; this.size = size; + this.wbase = wbase; this.gran = gran; } - - public void compute() { - final int l = origin; - final int g = gran; - final int n = this.n; - final short[] a = this.a; - final short[] w = this.w; - if (n > g) { - int h = n >>> 1; // half - int q = n >>> 2; // lower quarter index - int u = h + q; // upper quarter - FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q, g), - new Sorter(a, w, l+q, h-q, g), - new Merger(a, w, l, q, - l+q, h-q, l, g, null)); - FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q, g), - new Sorter(a, w, l+u, n-u, g), - new Merger(a, w, l+h, q, - l+u, n-u, l+h, g, null)); - rs.fork(); - ls.compute(); - if (rs.tryUnfork()) rs.compute(); else rs.join(); - new Merger(w, a, l, h, l + h, n - h, l, g, null).compute(); - } else { - DualPivotQuicksort.sort(a, l, l+n-1); // skip rangeCheck + public final void compute() { + CountedCompleter s = this; + short[] a = this.a, w = this.w; // localize all params + int b = this.base, n = this.size, wb = this.wbase, g = this.gran; + while (n > g) { + int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles + Relay fc = new Relay(new Merger(s, w, a, wb, h, + wb+h, n-h, b, g)); + Relay rc = new Relay(new Merger(fc, a, w, b+h, q, + b+u, n-u, wb+h, g)); + new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); + new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; + Relay bc = new Relay(new Merger(fc, a, w, b, q, + b+q, h-q, wb, g)); + new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); + s = new EmptyCompleter(bc); + n = q; } + DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); + s.tryComplete(); } } - static final class Merger extends RecursiveAction { - static final long serialVersionUID = 3895749408536700048L; - final short[] a; - final short[] w; - final int lo; - final int ln; - final int ro; - final int rn; - final int wo; - final int gran; - final Merger next; - - Merger(short[] a, short[] w, int lo, int ln, int ro, int rn, int wo, - int gran, Merger next) { - this.a = a; - this.w = w; - this.lo = lo; - this.ln = ln; - this.ro = ro; - this.rn = rn; - this.wo = wo; - this.gran = gran; - this.next = next; + static final class Merger extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final short[] a, w; // main and workspace arrays + final int lbase, lsize, rbase, rsize, wbase, gran; + Merger(CountedCompleter par, short[] a, short[] w, + int lbase, int lsize, int rbase, + int rsize, int wbase, int gran) { + super(par); + this.a = a; this.w = w; + this.lbase = lbase; this.lsize = lsize; + this.rbase = rbase; this.rsize = rsize; + this.wbase = wbase; this.gran = gran; } - public void compute() { - final short[] a = this.a; - final short[] w = this.w; - Merger rights = null; - int nleft = ln; - int nright = rn; - while (nleft > gran) { - int lh = nleft >>> 1; - int splitIndex = lo + lh; - short split = a[splitIndex]; - int rl = 0; - int rh = nright; - while (rl < rh) { - int mid = (rl + rh) >>> 1; - if (split <= a[ro + mid]) - rh = mid; - else - rl = mid + 1; + public final void compute() { + short[] a = this.a, w = this.w; // localize all params + int lb = this.lbase, ln = this.lsize, rb = this.rbase, + rn = this.rsize, k = this.wbase, g = this.gran; + if (a == null || w == null || lb < 0 || rb < 0 || k < 0) + throw new IllegalStateException(); // hoist checks + for (int lh, rh;;) { // split larger, find point in smaller + if (ln >= rn) { + if (ln <= g) + break; + rh = rn; + short split = a[(lh = ln >>> 1) + lb]; + for (int lo = 0; lo < rh; ) { + int rm = (lo + rh) >>> 1; + if (split <= a[rm + rb]) + rh = rm; + else + lo = rm + 1; + } } - (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh, - nright-rh, wo+lh+rh, gran, rights)).fork(); - nleft = lh; - nright = rh; + else { + if (rn <= g) + break; + lh = ln; + short split = a[(rh = rn >>> 1) + rb]; + for (int lo = 0; lo < lh; ) { + int lm = (lo + lh) >>> 1; + if (split <= a[lm + lb]) + lh = lm; + else + lo = lm + 1; + } + } + Merger m = new Merger(this, a, w, lb + lh, ln - lh, + rb + rh, rn - rh, + k + lh + rh, g); + rn = rh; + ln = lh; + addToPendingCount(1); + m.fork(); } - int l = lo; - int lFence = l + nleft; - int r = ro; - int rFence = r + nright; - int k = wo; - while (l < lFence && r < rFence) { - short al = a[l]; - short ar = a[r]; - short t; - if (al <= ar) {++l; t=al;} else {++r; t = ar;} + int lf = lb + ln, rf = rb + rn; // index bounds + while (lb < lf && rb < rf) { + short t, al, ar; + if ((al = a[lb]) <= (ar = a[rb])) { + lb++; t = al; + } + else { + rb++; t = ar; + } w[k++] = t; } - while (l < lFence) - w[k++] = a[l++]; - while (r < rFence) - w[k++] = a[r++]; - while (rights != null) { - if (rights.tryUnfork()) - rights.compute(); - else - rights.join(); - rights = rights.next; - } + if (rb < rf) + System.arraycopy(a, rb, w, k, rf - rb); + else if (lb < lf) + System.arraycopy(a, lb, w, k, lf - lb); + tryComplete(); } } } // FJShort /** int support class */ static final class FJInt { - static final class Sorter extends RecursiveAction { - static final long serialVersionUID = 4263311808957292729L; - final int[] a; // array to be sorted. - final int[] w; // workspace for merge - final int origin; // origin of the part of array we deal with - final int n; // Number of elements in (sub)arrays. - final int gran; // split control - - Sorter(int[] a, int[] w, int origin, int n, int gran) { - this.a = a; - this.w = w; - this.origin = origin; - this.n = n; - this.gran = gran; + static final class Sorter extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final int[] a, w; + final int base, size, wbase, gran; + Sorter(CountedCompleter par, int[] a, int[] w, int base, + int size, int wbase, int gran) { + super(par); + this.a = a; this.w = w; this.base = base; this.size = size; + this.wbase = wbase; this.gran = gran; } - - public void compute() { - final int l = origin; - final int g = gran; - final int n = this.n; - final int[] a = this.a; - final int[] w = this.w; - if (n > g) { - int h = n >>> 1; // half - int q = n >>> 2; // lower quarter index - int u = h + q; // upper quarter - FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q, g), - new Sorter(a, w, l+q, h-q, g), - new Merger(a, w, l, q, - l+q, h-q, l, g, null)); - FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q, g), - new Sorter(a, w, l+u, n-u, g), - new Merger(a, w, l+h, q, - l+u, n-u, l+h, g, null)); - rs.fork(); - ls.compute(); - if (rs.tryUnfork()) rs.compute(); else rs.join(); - new Merger(w, a, l, h, l + h, n - h, l, g, null).compute(); - } else { - DualPivotQuicksort.sort(a, l, l+n-1); // skip rangeCheck + public final void compute() { + CountedCompleter s = this; + int[] a = this.a, w = this.w; // localize all params + int b = this.base, n = this.size, wb = this.wbase, g = this.gran; + while (n > g) { + int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles + Relay fc = new Relay(new Merger(s, w, a, wb, h, + wb+h, n-h, b, g)); + Relay rc = new Relay(new Merger(fc, a, w, b+h, q, + b+u, n-u, wb+h, g)); + new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); + new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; + Relay bc = new Relay(new Merger(fc, a, w, b, q, + b+q, h-q, wb, g)); + new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); + s = new EmptyCompleter(bc); + n = q; } + DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); + s.tryComplete(); } } - static final class Merger extends RecursiveAction { - static final long serialVersionUID = -8727507284219982792L; - final int[] a; - final int[] w; - final int lo; - final int ln; - final int ro; - final int rn; - final int wo; - final int gran; - final Merger next; - - Merger(int[] a, int[] w, int lo, int ln, int ro, int rn, int wo, - int gran, Merger next) { - this.a = a; - this.w = w; - this.lo = lo; - this.ln = ln; - this.ro = ro; - this.rn = rn; - this.wo = wo; - this.gran = gran; - this.next = next; + static final class Merger extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final int[] a, w; // main and workspace arrays + final int lbase, lsize, rbase, rsize, wbase, gran; + Merger(CountedCompleter par, int[] a, int[] w, + int lbase, int lsize, int rbase, + int rsize, int wbase, int gran) { + super(par); + this.a = a; this.w = w; + this.lbase = lbase; this.lsize = lsize; + this.rbase = rbase; this.rsize = rsize; + this.wbase = wbase; this.gran = gran; } - public void compute() { - final int[] a = this.a; - final int[] w = this.w; - Merger rights = null; - int nleft = ln; - int nright = rn; - while (nleft > gran) { - int lh = nleft >>> 1; - int splitIndex = lo + lh; - int split = a[splitIndex]; - int rl = 0; - int rh = nright; - while (rl < rh) { - int mid = (rl + rh) >>> 1; - if (split <= a[ro + mid]) - rh = mid; - else - rl = mid + 1; + public final void compute() { + int[] a = this.a, w = this.w; // localize all params + int lb = this.lbase, ln = this.lsize, rb = this.rbase, + rn = this.rsize, k = this.wbase, g = this.gran; + if (a == null || w == null || lb < 0 || rb < 0 || k < 0) + throw new IllegalStateException(); // hoist checks + for (int lh, rh;;) { // split larger, find point in smaller + if (ln >= rn) { + if (ln <= g) + break; + rh = rn; + int split = a[(lh = ln >>> 1) + lb]; + for (int lo = 0; lo < rh; ) { + int rm = (lo + rh) >>> 1; + if (split <= a[rm + rb]) + rh = rm; + else + lo = rm + 1; + } } - (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh, - nright-rh, wo+lh+rh, gran, rights)).fork(); - nleft = lh; - nright = rh; + else { + if (rn <= g) + break; + lh = ln; + int split = a[(rh = rn >>> 1) + rb]; + for (int lo = 0; lo < lh; ) { + int lm = (lo + lh) >>> 1; + if (split <= a[lm + lb]) + lh = lm; + else + lo = lm + 1; + } + } + Merger m = new Merger(this, a, w, lb + lh, ln - lh, + rb + rh, rn - rh, + k + lh + rh, g); + rn = rh; + ln = lh; + addToPendingCount(1); + m.fork(); } - int l = lo; - int lFence = l + nleft; - int r = ro; - int rFence = r + nright; - int k = wo; - while (l < lFence && r < rFence) { - int al = a[l]; - int ar = a[r]; - int t; - if (al <= ar) {++l; t=al;} else {++r; t = ar;} + int lf = lb + ln, rf = rb + rn; // index bounds + while (lb < lf && rb < rf) { + int t, al, ar; + if ((al = a[lb]) <= (ar = a[rb])) { + lb++; t = al; + } + else { + rb++; t = ar; + } w[k++] = t; } - while (l < lFence) - w[k++] = a[l++]; - while (r < rFence) - w[k++] = a[r++]; - while (rights != null) { - if (rights.tryUnfork()) - rights.compute(); - else - rights.join(); - rights = rights.next; - } + if (rb < rf) + System.arraycopy(a, rb, w, k, rf - rb); + else if (lb < lf) + System.arraycopy(a, lb, w, k, lf - lb); + tryComplete(); } } } // FJInt /** long support class */ static final class FJLong { - static final class Sorter extends RecursiveAction { - static final long serialVersionUID = 6553695007444392455L; - final long[] a; // array to be sorted. - final long[] w; // workspace for merge - final int origin; // origin of the part of array we deal with - final int n; // Number of elements in (sub)arrays. - final int gran; // split control - - Sorter(long[] a, long[] w, int origin, int n, int gran) { - this.a = a; - this.w = w; - this.origin = origin; - this.n = n; - this.gran = gran; + static final class Sorter extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final long[] a, w; + final int base, size, wbase, gran; + Sorter(CountedCompleter par, long[] a, long[] w, int base, + int size, int wbase, int gran) { + super(par); + this.a = a; this.w = w; this.base = base; this.size = size; + this.wbase = wbase; this.gran = gran; } - - public void compute() { - final int l = origin; - final int g = gran; - final int n = this.n; - final long[] a = this.a; - final long[] w = this.w; - if (n > g) { - int h = n >>> 1; // half - int q = n >>> 2; // lower quarter index - int u = h + q; // upper quarter - FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q, g), - new Sorter(a, w, l+q, h-q, g), - new Merger(a, w, l, q, - l+q, h-q, l, g, null)); - FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q, g), - new Sorter(a, w, l+u, n-u, g), - new Merger(a, w, l+h, q, - l+u, n-u, l+h, g, null)); - rs.fork(); - ls.compute(); - if (rs.tryUnfork()) rs.compute(); else rs.join(); - new Merger(w, a, l, h, l + h, n - h, l, g, null).compute(); - } else { - DualPivotQuicksort.sort(a, l, l+n-1); // skip rangeCheck + public final void compute() { + CountedCompleter s = this; + long[] a = this.a, w = this.w; // localize all params + int b = this.base, n = this.size, wb = this.wbase, g = this.gran; + while (n > g) { + int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles + Relay fc = new Relay(new Merger(s, w, a, wb, h, + wb+h, n-h, b, g)); + Relay rc = new Relay(new Merger(fc, a, w, b+h, q, + b+u, n-u, wb+h, g)); + new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); + new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; + Relay bc = new Relay(new Merger(fc, a, w, b, q, + b+q, h-q, wb, g)); + new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); + s = new EmptyCompleter(bc); + n = q; } + DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); + s.tryComplete(); } } - static final class Merger extends RecursiveAction { - static final long serialVersionUID = 8843567516333283861L; - final long[] a; - final long[] w; - final int lo; - final int ln; - final int ro; - final int rn; - final int wo; - final int gran; - final Merger next; - - Merger(long[] a, long[] w, int lo, int ln, int ro, int rn, int wo, - int gran, Merger next) { - this.a = a; - this.w = w; - this.lo = lo; - this.ln = ln; - this.ro = ro; - this.rn = rn; - this.wo = wo; - this.gran = gran; - this.next = next; + static final class Merger extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final long[] a, w; // main and workspace arrays + final int lbase, lsize, rbase, rsize, wbase, gran; + Merger(CountedCompleter par, long[] a, long[] w, + int lbase, int lsize, int rbase, + int rsize, int wbase, int gran) { + super(par); + this.a = a; this.w = w; + this.lbase = lbase; this.lsize = lsize; + this.rbase = rbase; this.rsize = rsize; + this.wbase = wbase; this.gran = gran; } - public void compute() { - final long[] a = this.a; - final long[] w = this.w; - Merger rights = null; - int nleft = ln; - int nright = rn; - while (nleft > gran) { - int lh = nleft >>> 1; - int splitIndex = lo + lh; - long split = a[splitIndex]; - int rl = 0; - int rh = nright; - while (rl < rh) { - int mid = (rl + rh) >>> 1; - if (split <= a[ro + mid]) - rh = mid; - else - rl = mid + 1; + public final void compute() { + long[] a = this.a, w = this.w; // localize all params + int lb = this.lbase, ln = this.lsize, rb = this.rbase, + rn = this.rsize, k = this.wbase, g = this.gran; + if (a == null || w == null || lb < 0 || rb < 0 || k < 0) + throw new IllegalStateException(); // hoist checks + for (int lh, rh;;) { // split larger, find point in smaller + if (ln >= rn) { + if (ln <= g) + break; + rh = rn; + long split = a[(lh = ln >>> 1) + lb]; + for (int lo = 0; lo < rh; ) { + int rm = (lo + rh) >>> 1; + if (split <= a[rm + rb]) + rh = rm; + else + lo = rm + 1; + } } - (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh, - nright-rh, wo+lh+rh, gran, rights)).fork(); - nleft = lh; - nright = rh; + else { + if (rn <= g) + break; + lh = ln; + long split = a[(rh = rn >>> 1) + rb]; + for (int lo = 0; lo < lh; ) { + int lm = (lo + lh) >>> 1; + if (split <= a[lm + lb]) + lh = lm; + else + lo = lm + 1; + } + } + Merger m = new Merger(this, a, w, lb + lh, ln - lh, + rb + rh, rn - rh, + k + lh + rh, g); + rn = rh; + ln = lh; + addToPendingCount(1); + m.fork(); } - int l = lo; - int lFence = l + nleft; - int r = ro; - int rFence = r + nright; - int k = wo; - while (l < lFence && r < rFence) { - long al = a[l]; - long ar = a[r]; - long t; - if (al <= ar) {++l; t=al;} else {++r; t = ar;} + int lf = lb + ln, rf = rb + rn; // index bounds + while (lb < lf && rb < rf) { + long t, al, ar; + if ((al = a[lb]) <= (ar = a[rb])) { + lb++; t = al; + } + else { + rb++; t = ar; + } w[k++] = t; } - while (l < lFence) - w[k++] = a[l++]; - while (r < rFence) - w[k++] = a[r++]; - while (rights != null) { - if (rights.tryUnfork()) - rights.compute(); - else - rights.join(); - rights = rights.next; - } + if (rb < rf) + System.arraycopy(a, rb, w, k, rf - rb); + else if (lb < lf) + System.arraycopy(a, lb, w, k, lf - lb); + tryComplete(); } } } // FJLong /** float support class */ static final class FJFloat { - static final class Sorter extends RecursiveAction { - static final long serialVersionUID = 1602600178202763377L; - final float[] a; // array to be sorted. - final float[] w; // workspace for merge - final int origin; // origin of the part of array we deal with - final int n; // Number of elements in (sub)arrays. - final int gran; // split control - - Sorter(float[] a, float[] w, int origin, int n, int gran) { - this.a = a; - this.w = w; - this.origin = origin; - this.n = n; - this.gran = gran; + static final class Sorter extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final float[] a, w; + final int base, size, wbase, gran; + Sorter(CountedCompleter par, float[] a, float[] w, int base, + int size, int wbase, int gran) { + super(par); + this.a = a; this.w = w; this.base = base; this.size = size; + this.wbase = wbase; this.gran = gran; } - - public void compute() { - final int l = origin; - final int g = gran; - final int n = this.n; - final float[] a = this.a; - final float[] w = this.w; - if (n > g) { - int h = n >>> 1; // half - int q = n >>> 2; // lower quarter index - int u = h + q; // upper quarter - FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q, g), - new Sorter(a, w, l+q, h-q, g), - new Merger(a, w, l, q, - l+q, h-q, l, g, null)); - FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q, g), - new Sorter(a, w, l+u, n-u, g), - new Merger(a, w, l+h, q, - l+u, n-u, l+h, g, null)); - rs.fork(); - ls.compute(); - if (rs.tryUnfork()) rs.compute(); else rs.join(); - new Merger(w, a, l, h, l + h, n - h, l, g, null).compute(); - } else { - DualPivotQuicksort.sort(a, l, l+n-1); // skip rangeCheck + public final void compute() { + CountedCompleter s = this; + float[] a = this.a, w = this.w; // localize all params + int b = this.base, n = this.size, wb = this.wbase, g = this.gran; + while (n > g) { + int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles + Relay fc = new Relay(new Merger(s, w, a, wb, h, + wb+h, n-h, b, g)); + Relay rc = new Relay(new Merger(fc, a, w, b+h, q, + b+u, n-u, wb+h, g)); + new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); + new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; + Relay bc = new Relay(new Merger(fc, a, w, b, q, + b+q, h-q, wb, g)); + new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); + s = new EmptyCompleter(bc); + n = q; } + DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); + s.tryComplete(); } } - static final class Merger extends RecursiveAction { - static final long serialVersionUID = 1518176433845397426L; - final float[] a; - final float[] w; - final int lo; - final int ln; - final int ro; - final int rn; - final int wo; - final int gran; - final Merger next; - - Merger(float[] a, float[] w, int lo, int ln, int ro, int rn, int wo, - int gran, Merger next) { - this.a = a; - this.w = w; - this.lo = lo; - this.ln = ln; - this.ro = ro; - this.rn = rn; - this.wo = wo; - this.gran = gran; - this.next = next; + static final class Merger extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final float[] a, w; // main and workspace arrays + final int lbase, lsize, rbase, rsize, wbase, gran; + Merger(CountedCompleter par, float[] a, float[] w, + int lbase, int lsize, int rbase, + int rsize, int wbase, int gran) { + super(par); + this.a = a; this.w = w; + this.lbase = lbase; this.lsize = lsize; + this.rbase = rbase; this.rsize = rsize; + this.wbase = wbase; this.gran = gran; } - public void compute() { - final float[] a = this.a; - final float[] w = this.w; - Merger rights = null; - int nleft = ln; - int nright = rn; - while (nleft > gran) { - int lh = nleft >>> 1; - int splitIndex = lo + lh; - float split = a[splitIndex]; - int rl = 0; - int rh = nright; - while (rl < rh) { - int mid = (rl + rh) >>> 1; - if (Float.compare(split, a[ro+mid]) <= 0) - rh = mid; - else - rl = mid + 1; + public final void compute() { + float[] a = this.a, w = this.w; // localize all params + int lb = this.lbase, ln = this.lsize, rb = this.rbase, + rn = this.rsize, k = this.wbase, g = this.gran; + if (a == null || w == null || lb < 0 || rb < 0 || k < 0) + throw new IllegalStateException(); // hoist checks + for (int lh, rh;;) { // split larger, find point in smaller + if (ln >= rn) { + if (ln <= g) + break; + rh = rn; + float split = a[(lh = ln >>> 1) + lb]; + for (int lo = 0; lo < rh; ) { + int rm = (lo + rh) >>> 1; + if (split <= a[rm + rb]) + rh = rm; + else + lo = rm + 1; + } } - (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh, - nright-rh, wo+lh+rh, gran, rights)).fork(); - nleft = lh; - nright = rh; + else { + if (rn <= g) + break; + lh = ln; + float split = a[(rh = rn >>> 1) + rb]; + for (int lo = 0; lo < lh; ) { + int lm = (lo + lh) >>> 1; + if (split <= a[lm + lb]) + lh = lm; + else + lo = lm + 1; + } + } + Merger m = new Merger(this, a, w, lb + lh, ln - lh, + rb + rh, rn - rh, + k + lh + rh, g); + rn = rh; + ln = lh; + addToPendingCount(1); + m.fork(); } - int l = lo; - int lFence = l + nleft; - int r = ro; - int rFence = r + nright; - int k = wo; - while (l < lFence && r < rFence) { - float al = a[l]; - float ar = a[r]; - float t; - if (Float.compare(al, ar) <= 0) { - ++l; - t = al; - } else { - ++r; - t = ar; + int lf = lb + ln, rf = rb + rn; // index bounds + while (lb < lf && rb < rf) { + float t, al, ar; + if ((al = a[lb]) <= (ar = a[rb])) { + lb++; t = al; + } + else { + rb++; t = ar; } w[k++] = t; } - while (l < lFence) - w[k++] = a[l++]; - while (r < rFence) - w[k++] = a[r++]; - while (rights != null) { - if (rights.tryUnfork()) - rights.compute(); - else - rights.join(); - rights = rights.next; - } + if (rb < rf) + System.arraycopy(a, rb, w, k, rf - rb); + else if (lb < lf) + System.arraycopy(a, lb, w, k, lf - lb); + tryComplete(); } } } // FJFloat /** double support class */ static final class FJDouble { - static final class Sorter extends RecursiveAction { + static final class Sorter extends CountedCompleter { static final long serialVersionUID = 2446542900576103244L; - final double[] a; // array to be sorted. - final double[] w; // workspace for merge - final int origin; // origin of the part of array we deal with - final int n; // Number of elements in (sub)arrays. - final int gran; // split control - - Sorter(double[] a, double[] w, int origin, int n, int gran) { - this.a = a; - this.w = w; - this.origin = origin; - this.n = n; - this.gran = gran; + final double[] a, w; + final int base, size, wbase, gran; + Sorter(CountedCompleter par, double[] a, double[] w, int base, + int size, int wbase, int gran) { + super(par); + this.a = a; this.w = w; this.base = base; this.size = size; + this.wbase = wbase; this.gran = gran; } - - public void compute() { - final int l = origin; - final int g = gran; - final int n = this.n; - final double[] a = this.a; - final double[] w = this.w; - if (n > g) { - int h = n >>> 1; // half - int q = n >>> 2; // lower quarter index - int u = h + q; // upper quarter - FJSubSorter ls = new FJSubSorter(new Sorter(a, w, l, q, g), - new Sorter(a, w, l+q, h-q, g), - new Merger(a, w, l, q, - l+q, h-q, l, g, null)); - FJSubSorter rs = new FJSubSorter(new Sorter(a, w, l + h, q, g), - new Sorter(a, w, l+u, n-u, g), - new Merger(a, w, l+h, q, - l+u, n-u, l+h, g, null)); - rs.fork(); - ls.compute(); - if (rs.tryUnfork()) rs.compute(); else rs.join(); - new Merger(w, a, l, h, l + h, n - h, l, g, null).compute(); - } else { - DualPivotQuicksort.sort(a, l, l+n-1); // skip rangeCheck + public final void compute() { + CountedCompleter s = this; + double[] a = this.a, w = this.w; // localize all params + int b = this.base, n = this.size, wb = this.wbase, g = this.gran; + while (n > g) { + int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles + Relay fc = new Relay(new Merger(s, w, a, wb, h, + wb+h, n-h, b, g)); + Relay rc = new Relay(new Merger(fc, a, w, b+h, q, + b+u, n-u, wb+h, g)); + new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); + new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; + Relay bc = new Relay(new Merger(fc, a, w, b, q, + b+q, h-q, wb, g)); + new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); + s = new EmptyCompleter(bc); + n = q; } + DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); + s.tryComplete(); } } - static final class Merger extends RecursiveAction { - static final long serialVersionUID = 8076242187166127592L; - final double[] a; - final double[] w; - final int lo; - final int ln; - final int ro; - final int rn; - final int wo; - final int gran; - final Merger next; - - Merger(double[] a, double[] w, int lo, int ln, int ro, int rn, int wo, - int gran, Merger next) { - this.a = a; - this.w = w; - this.lo = lo; - this.ln = ln; - this.ro = ro; - this.rn = rn; - this.wo = wo; - this.gran = gran; - this.next = next; + static final class Merger extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final double[] a, w; // main and workspace arrays + final int lbase, lsize, rbase, rsize, wbase, gran; + Merger(CountedCompleter par, double[] a, double[] w, + int lbase, int lsize, int rbase, + int rsize, int wbase, int gran) { + super(par); + this.a = a; this.w = w; + this.lbase = lbase; this.lsize = lsize; + this.rbase = rbase; this.rsize = rsize; + this.wbase = wbase; this.gran = gran; } - public void compute() { - final double[] a = this.a; - final double[] w = this.w; - Merger rights = null; - int nleft = ln; - int nright = rn; - while (nleft > gran) { - int lh = nleft >>> 1; - int splitIndex = lo + lh; - double split = a[splitIndex]; - int rl = 0; - int rh = nright; - while (rl < rh) { - int mid = (rl + rh) >>> 1; - if (Double.compare(split, a[ro+mid]) <= 0) - rh = mid; - else - rl = mid + 1; + public final void compute() { + double[] a = this.a, w = this.w; // localize all params + int lb = this.lbase, ln = this.lsize, rb = this.rbase, + rn = this.rsize, k = this.wbase, g = this.gran; + if (a == null || w == null || lb < 0 || rb < 0 || k < 0) + throw new IllegalStateException(); // hoist checks + for (int lh, rh;;) { // split larger, find point in smaller + if (ln >= rn) { + if (ln <= g) + break; + rh = rn; + double split = a[(lh = ln >>> 1) + lb]; + for (int lo = 0; lo < rh; ) { + int rm = (lo + rh) >>> 1; + if (split <= a[rm + rb]) + rh = rm; + else + lo = rm + 1; + } } - (rights = new Merger(a, w, splitIndex, nleft-lh, ro+rh, - nright-rh, wo+lh+rh, gran, rights)).fork(); - nleft = lh; - nright = rh; + else { + if (rn <= g) + break; + lh = ln; + double split = a[(rh = rn >>> 1) + rb]; + for (int lo = 0; lo < lh; ) { + int lm = (lo + lh) >>> 1; + if (split <= a[lm + lb]) + lh = lm; + else + lo = lm + 1; + } + } + Merger m = new Merger(this, a, w, lb + lh, ln - lh, + rb + rh, rn - rh, + k + lh + rh, g); + rn = rh; + ln = lh; + addToPendingCount(1); + m.fork(); } - int l = lo; - int lFence = l + nleft; - int r = ro; - int rFence = r + nright; - int k = wo; - while (l < lFence && r < rFence) { - double al = a[l]; - double ar = a[r]; - double t; - if (Double.compare(al, ar) <= 0) { - ++l; - t = al; - } else { - ++r; - t = ar; + int lf = lb + ln, rf = rb + rn; // index bounds + while (lb < lf && rb < rf) { + double t, al, ar; + if ((al = a[lb]) <= (ar = a[rb])) { + lb++; t = al; + } + else { + rb++; t = ar; } w[k++] = t; } - while (l < lFence) - w[k++] = a[l++]; - while (r < rFence) - w[k++] = a[r++]; - while (rights != null) { - if (rights.tryUnfork()) - rights.compute(); - else - rights.join(); - rights = rights.next; - } + if (rb < rf) + System.arraycopy(a, rb, w, k, rf - rb); + else if (lb < lf) + System.arraycopy(a, lb, w, k, lf - lb); + tryComplete(); } } } // FJDouble - /** Comparable support class */ - static final class FJComparable { - static final class Sorter> extends RecursiveAction { - static final long serialVersionUID = -1024003289463302522L; - final T[] a; - final T[] w; - final int origin; - final int n; - final int gran; - - Sorter(T[] a, T[] w, int origin, int n, int gran) { - this.a = a; - this.w = w; - this.origin = origin; - this.n = n; - this.gran = gran; - } - - public void compute() { - final int l = origin; - final int g = gran; - final int n = this.n; - final T[] a = this.a; - final T[] w = this.w; - if (n > g) { - int h = n >>> 1; - int q = n >>> 2; - int u = h + q; - FJSubSorter ls = new FJSubSorter(new Sorter<>(a, w, l, q, g), - new Sorter<>(a, w, l+q, h-q, g), - new Merger<>(a, w, l, q, - l+q, h-q, l, g, null)); - FJSubSorter rs = new FJSubSorter(new Sorter<>(a, w, l+h, q, g), - new Sorter<>(a, w, l+u, n-u, g), - new Merger<>(a, w, l+h, q, - l+u, n-u, l+h, g, null)); - rs.fork(); - ls.compute(); - if (rs.tryUnfork()) rs.compute(); else rs.join(); - new Merger<>(w, a, l, h, l + h, n - h, l, g, null).compute(); - } else { - Arrays.sort(a, l, l+n); - } - } - } - - static final class Merger> extends RecursiveAction { - static final long serialVersionUID = -3989771675258379302L; - final T[] a; - final T[] w; - final int lo; - final int ln; - final int ro; - final int rn; - final int wo; - final int gran; - final Merger next; - - Merger(T[] a, T[] w, int lo, int ln, int ro, int rn, int wo, - int gran, Merger next) { - this.a = a; - this.w = w; - this.lo = lo; - this.ln = ln; - this.ro = ro; - this.rn = rn; - this.wo = wo; - this.gran = gran; - this.next = next; - } - - public void compute() { - final T[] a = this.a; - final T[] w = this.w; - Merger rights = null; - int nleft = ln; - int nright = rn; - while (nleft > gran) { - int lh = nleft >>> 1; - int splitIndex = lo + lh; - T split = a[splitIndex]; - int rl = 0; - int rh = nright; - while (rl < rh) { - int mid = (rl + rh) >>> 1; - if (split.compareTo(a[ro + mid]) <= 0) - rh = mid; - else - rl = mid + 1; - } - (rights = new Merger<>(a, w, splitIndex, nleft-lh, ro+rh, - nright-rh, wo+lh+rh, gran, rights)).fork(); - nleft = lh; - nright = rh; - } - - int l = lo; - int lFence = l + nleft; - int r = ro; - int rFence = r + nright; - int k = wo; - while (l < lFence && r < rFence) { - T al = a[l]; - T ar = a[r]; - T t; - if (al.compareTo(ar) <= 0) {++l; t=al;} else {++r; t=ar; } - w[k++] = t; - } - while (l < lFence) - w[k++] = a[l++]; - while (r < rFence) - w[k++] = a[r++]; - while (rights != null) { - if (rights.tryUnfork()) - rights.compute(); - else - rights.join(); - rights = rights.next; - } - } - } - } // FJComparable - - /** Object + Comparator support class */ - static final class FJComparator { - static final class Sorter extends RecursiveAction { - static final long serialVersionUID = 9191600840025808581L; - final T[] a; // array to be sorted. - final T[] w; // workspace for merge - final int origin; // origin of the part of array we deal with - final int n; // Number of elements in (sub)arrays. - final int gran; // split control - final Comparator cmp; // Comparator to use - - Sorter(T[] a, T[] w, int origin, int n, int gran, Comparator cmp) { - this.a = a; - this.w = w; - this.origin = origin; - this.n = n; - this.cmp = cmp; - this.gran = gran; - } - - public void compute() { - final int l = origin; - final int g = gran; - final int n = this.n; - final T[] a = this.a; - final T[] w = this.w; - if (n > g) { - int h = n >>> 1; // half - int q = n >>> 2; // lower quarter index - int u = h + q; // upper quarter - FJSubSorter ls = new FJSubSorter(new Sorter<>(a, w, l, q, g, cmp), - new Sorter<>(a, w, l+q, h-q, g, cmp), - new Merger<>(a, w, l, q, - l+q, h-q, l, g, null, cmp)); - FJSubSorter rs = new FJSubSorter(new Sorter<>(a, w, l + h, q, g, cmp), - new Sorter<>(a, w, l+u, n-u, g, cmp), - new Merger<>(a, w, l+h, q, - l+u, n-u, l+h, g, null, cmp)); - rs.fork(); - ls.compute(); - if (rs.tryUnfork()) rs.compute(); else rs.join(); - new Merger<>(w, a, l, h, l + h, n - h, l, g, null, cmp).compute(); - } else { - Arrays.sort(a, l, l+n, cmp); - } - } - } - - static final class Merger extends RecursiveAction { - static final long serialVersionUID = -2679539040379156203L; - final T[] a; - final T[] w; - final int lo; - final int ln; - final int ro; - final int rn; - final int wo; - final int gran; - final Merger next; - final Comparator cmp; - - Merger(T[] a, T[] w, int lo, int ln, int ro, int rn, int wo, - int gran, Merger next, Comparator cmp) { - this.a = a; - this.w = w; - this.lo = lo; - this.ln = ln; - this.ro = ro; - this.rn = rn; - this.wo = wo; - this.gran = gran; - this.next = next; - this.cmp = cmp; - } - - public void compute() { - final T[] a = this.a; - final T[] w = this.w; - Merger rights = null; - int nleft = ln; - int nright = rn; - while (nleft > gran) { - int lh = nleft >>> 1; - int splitIndex = lo + lh; - T split = a[splitIndex]; - int rl = 0; - int rh = nright; - while (rl < rh) { - int mid = (rl + rh) >>> 1; - if (cmp.compare(split, a[ro+mid]) <= 0) - rh = mid; - else - rl = mid + 1; - } - (rights = new Merger<>(a, w, splitIndex, nleft-lh, ro+rh, - nright-rh, wo+lh+rh, gran, rights, cmp)).fork(); - nleft = lh; - nright = rh; - } - - int l = lo; - int lFence = l + nleft; - int r = ro; - int rFence = r + nright; - int k = wo; - while (l < lFence && r < rFence) { - T al = a[l]; - T ar = a[r]; - T t; - if (cmp.compare(al, ar) <= 0) { - ++l; - t = al; - } else { - ++r; - t = ar; - } - w[k++] = t; - } - while (l < lFence) - w[k++] = a[l++]; - while (r < rFence) - w[k++] = a[r++]; - while (rights != null) { - if (rights.tryUnfork()) - rights.compute(); - else - rights.join(); - rights = rights.next; - } - } - } - } // FJComparator - - /** Utility class to sort half a partitioned array */ - private static final class FJSubSorter extends RecursiveAction { - static final long serialVersionUID = 9159249695527935512L; - final RecursiveAction left; - final RecursiveAction right; - final RecursiveAction merger; - - FJSubSorter(RecursiveAction left, RecursiveAction right, - RecursiveAction merger) { - this.left = left; - this.right = right; - this.merger = merger; - } - - public void compute() { - right.fork(); - left.invoke(); - right.join(); - merger.invoke(); - } - } } diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/util/ComparableTimSort.java --- a/jdk/src/share/classes/java/util/ComparableTimSort.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/util/ComparableTimSort.java Wed Jul 05 18:57:52 2017 +0200 @@ -86,9 +86,13 @@ private static final int INITIAL_TMP_STORAGE_LENGTH = 256; /** - * Temp storage for merges. + * Temp storage for merges. A workspace array may optionally be + * provided in constructor, and if so will be used as long as it + * is big enough. */ private Object[] tmp; + private int tmpBase; // base of tmp array slice + private int tmpLen; // length of tmp array slice /** * A stack of pending runs yet to be merged. Run i starts at @@ -108,15 +112,27 @@ * Creates a TimSort instance to maintain the state of an ongoing sort. * * @param a the array to be sorted + * @param work a workspace array (slice) + * @param workBase origin of usable space in work array + * @param workLen usable size of work array */ - private ComparableTimSort(Object[] a) { + private ComparableTimSort(Object[] a, Object[] work, int workBase, int workLen) { this.a = a; // Allocate temp storage (which may be increased later if necessary) int len = a.length; - Object[] newArray = new Object[len < 2 * INITIAL_TMP_STORAGE_LENGTH ? - len >>> 1 : INITIAL_TMP_STORAGE_LENGTH]; - tmp = newArray; + int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ? + len >>> 1 : INITIAL_TMP_STORAGE_LENGTH; + if (work == null || workLen < tlen || workBase + tlen > work.length) { + tmp = new Object[tlen]; + tmpBase = 0; + tmpLen = tlen; + } + else { + tmp = work; + tmpBase = workBase; + tmpLen = workLen; + } /* * Allocate runs-to-be-merged stack (which cannot be expanded). The @@ -136,17 +152,28 @@ } /* - * The next two methods (which are package private and static) constitute - * the entire API of this class. Each of these methods obeys the contract - * of the public method with the same signature in java.util.Arrays. + * The next method (package private and static) constitutes the + * entire API of this class. */ - static void sort(Object[] a) { - sort(a, 0, a.length); - } + /** + * Sorts the given range, using the given workspace array slice + * for temp storage when possible. This method is designed to be + * invoked from public methods (in class Arrays) after performing + * any necessary array bounds checks and expanding parameters into + * the required forms. + * + * @param a the array to be sorted + * @param lo the index of the first element, inclusive, to be sorted + * @param hi the index of the last element, exclusive, to be sorted + * @param work a workspace array (slice) + * @param workBase origin of usable space in work array + * @param workLen usable size of work array + * @since 1.8 + */ + static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) { + assert a != null && lo >= 0 && lo <= hi && hi <= a.length; - static void sort(Object[] a, int lo, int hi) { - rangeCheck(a.length, lo, hi); int nRemaining = hi - lo; if (nRemaining < 2) return; // Arrays of size 0 and 1 are always sorted @@ -163,7 +190,7 @@ * extending short natural runs to minRun elements, and merging runs * to maintain stack invariant. */ - ComparableTimSort ts = new ComparableTimSort(a); + ComparableTimSort ts = new ComparableTimSort(a, work, workBase, workLen); int minRun = minRunLength(nRemaining); do { // Identify next run @@ -619,11 +646,11 @@ // Copy first run into temp array Object[] a = this.a; // For performance Object[] tmp = ensureCapacity(len1); - System.arraycopy(a, base1, tmp, 0, len1); - int cursor1 = 0; // Indexes into tmp array + int cursor1 = tmpBase; // Indexes into tmp array int cursor2 = base2; // Indexes int a int dest = base1; // Indexes int a + System.arraycopy(a, base1, tmp, cursor1, len1); // Move first element of second run and deal with degenerate cases a[dest++] = a[cursor2++]; @@ -736,16 +763,17 @@ // Copy second run into temp array Object[] a = this.a; // For performance Object[] tmp = ensureCapacity(len2); - System.arraycopy(a, base2, tmp, 0, len2); + int tmpBase = this.tmpBase; + System.arraycopy(a, base2, tmp, tmpBase, len2); int cursor1 = base1 + len1 - 1; // Indexes into a - int cursor2 = len2 - 1; // Indexes into tmp array + int cursor2 = tmpBase + len2 - 1; // Indexes into tmp array int dest = base2 + len2 - 1; // Indexes into a // Move last element of first run and deal with degenerate cases a[dest--] = a[cursor1--]; if (--len1 == 0) { - System.arraycopy(tmp, 0, a, dest - (len2 - 1), len2); + System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2); return; } if (len2 == 1) { @@ -803,7 +831,7 @@ if (--len2 == 1) break outer; - count2 = len2 - gallopLeft((Comparable) a[cursor1], tmp, 0, len2, len2 - 1); + count2 = len2 - gallopLeft((Comparable) a[cursor1], tmp, tmpBase, len2, len2 - 1); if (count2 != 0) { dest -= count2; cursor2 -= count2; @@ -835,7 +863,7 @@ } else { assert len1 == 0; assert len2 > 0; - System.arraycopy(tmp, 0, a, dest - (len2 - 1), len2); + System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2); } } @@ -848,7 +876,7 @@ * @return tmp, whether or not it grew */ private Object[] ensureCapacity(int minCapacity) { - if (tmp.length < minCapacity) { + if (tmpLen < minCapacity) { // Compute smallest power of 2 > minCapacity int newSize = minCapacity; newSize |= newSize >> 1; @@ -863,30 +891,13 @@ else newSize = Math.min(newSize, a.length >>> 1); + @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) Object[] newArray = new Object[newSize]; tmp = newArray; + tmpLen = newSize; + tmpBase = 0; } return tmp; } - /** - * Checks that fromIndex and toIndex are in range, and throws an - * appropriate exception if they aren't. - * - * @param arrayLen the length of the array - * @param fromIndex the index of the first element of the range - * @param toIndex the index after the last element of the range - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 - * or toIndex > arrayLen - */ - private static void rangeCheck(int arrayLen, int fromIndex, int toIndex) { - if (fromIndex > toIndex) - throw new IllegalArgumentException("fromIndex(" + fromIndex + - ") > toIndex(" + toIndex+")"); - if (fromIndex < 0) - throw new ArrayIndexOutOfBoundsException(fromIndex); - if (toIndex > arrayLen) - throw new ArrayIndexOutOfBoundsException(toIndex); - } } diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/util/DualPivotQuicksort.java --- a/jdk/src/share/classes/java/util/DualPivotQuicksort.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/util/DualPivotQuicksort.java Wed Jul 05 18:57:52 2017 +0200 @@ -32,6 +32,11 @@ * quicksorts to degrade to quadratic performance, and is typically * faster than traditional (one-pivot) Quicksort implementations. * + * All exposed methods are package-private, designed to be invoked + * from public methods (in class Arrays) after performing any + * necessary array bounds checks and expanding parameters into the + * required forms. + * * @author Vladimir Yaroslavskiy * @author Jon Bentley * @author Josh Bloch @@ -89,22 +94,18 @@ */ /** - * Sorts the specified array. - * - * @param a the array to be sorted - */ - public static void sort(int[] a) { - sort(a, 0, a.length - 1); - } - - /** - * Sorts the specified range of the array. + * Sorts the specified range of the array using the given + * workspace array slice if possible for merging * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted + * @param work a workspace array (slice) + * @param workBase origin of usable space in work array + * @param workLen usable size of work array */ - public static void sort(int[] a, int left, int right) { + static void sort(int[] a, int left, int right, + int[] work, int workBase, int workLen) { // Use Quicksort on small arrays if (right - left < QUICKSORT_THRESHOLD) { sort(a, left, right, true); @@ -147,24 +148,35 @@ } // Check special cases + // Implementation note: variable "right" is increased by 1. if (run[count] == right++) { // The last run contains one element run[++count] = right; } else if (count == 1) { // The array is already sorted return; } - /* - * Create temporary array, which is used for merging. - * Implementation note: variable "right" is increased by 1. - */ - int[] b; byte odd = 0; + // Determine alternation base for merge + byte odd = 0; for (int n = 1; (n <<= 1) < count; odd ^= 1); + // Use or create temporary array b for merging + int[] b; // temp array; alternates with a + int ao, bo; // array offsets from 'left' + int blen = right - left; // space needed for b + if (work == null || workLen < blen || workBase + blen > work.length) { + work = new int[blen]; + workBase = 0; + } if (odd == 0) { - b = a; a = new int[b.length]; - for (int i = left - 1; ++i < right; a[i] = b[i]); + System.arraycopy(a, left, work, workBase, blen); + b = a; + bo = 0; + a = work; + ao = workBase - left; } else { - b = new int[a.length]; + b = work; + ao = 0; + bo = workBase - left; } // Merging @@ -172,21 +184,22 @@ for (int k = (last = 0) + 2; k <= count; k += 2) { int hi = run[k], mi = run[k - 1]; for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) { - if (q >= hi || p < mi && a[p] <= a[q]) { - b[i] = a[p++]; + if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) { + b[i + bo] = a[p++ + ao]; } else { - b[i] = a[q++]; + b[i + bo] = a[q++ + ao]; } } run[++last] = hi; } if ((count & 1) != 0) { for (int i = right, lo = run[count - 1]; --i >= lo; - b[i] = a[i] + b[i + bo] = a[i + ao] ); run[++last] = right; } int[] t = a; a = b; b = t; + int o = ao; ao = bo; bo = o; } } @@ -529,22 +542,18 @@ } /** - * Sorts the specified array. - * - * @param a the array to be sorted - */ - public static void sort(long[] a) { - sort(a, 0, a.length - 1); - } - - /** - * Sorts the specified range of the array. + * Sorts the specified range of the array using the given + * workspace array slice if possible for merging * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted + * @param work a workspace array (slice) + * @param workBase origin of usable space in work array + * @param workLen usable size of work array */ - public static void sort(long[] a, int left, int right) { + static void sort(long[] a, int left, int right, + long[] work, int workBase, int workLen) { // Use Quicksort on small arrays if (right - left < QUICKSORT_THRESHOLD) { sort(a, left, right, true); @@ -587,24 +596,35 @@ } // Check special cases + // Implementation note: variable "right" is increased by 1. if (run[count] == right++) { // The last run contains one element run[++count] = right; } else if (count == 1) { // The array is already sorted return; } - /* - * Create temporary array, which is used for merging. - * Implementation note: variable "right" is increased by 1. - */ - long[] b; byte odd = 0; + // Determine alternation base for merge + byte odd = 0; for (int n = 1; (n <<= 1) < count; odd ^= 1); + // Use or create temporary array b for merging + long[] b; // temp array; alternates with a + int ao, bo; // array offsets from 'left' + int blen = right - left; // space needed for b + if (work == null || workLen < blen || workBase + blen > work.length) { + work = new long[blen]; + workBase = 0; + } if (odd == 0) { - b = a; a = new long[b.length]; - for (int i = left - 1; ++i < right; a[i] = b[i]); + System.arraycopy(a, left, work, workBase, blen); + b = a; + bo = 0; + a = work; + ao = workBase - left; } else { - b = new long[a.length]; + b = work; + ao = 0; + bo = workBase - left; } // Merging @@ -612,21 +632,22 @@ for (int k = (last = 0) + 2; k <= count; k += 2) { int hi = run[k], mi = run[k - 1]; for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) { - if (q >= hi || p < mi && a[p] <= a[q]) { - b[i] = a[p++]; + if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) { + b[i + bo] = a[p++ + ao]; } else { - b[i] = a[q++]; + b[i + bo] = a[q++ + ao]; } } run[++last] = hi; } if ((count & 1) != 0) { for (int i = right, lo = run[count - 1]; --i >= lo; - b[i] = a[i] + b[i + bo] = a[i + ao] ); run[++last] = right; } long[] t = a; a = b; b = t; + int o = ao; ao = bo; bo = o; } } @@ -969,22 +990,18 @@ } /** - * Sorts the specified array. - * - * @param a the array to be sorted - */ - public static void sort(short[] a) { - sort(a, 0, a.length - 1); - } - - /** - * Sorts the specified range of the array. + * Sorts the specified range of the array using the given + * workspace array slice if possible for merging * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted + * @param work a workspace array (slice) + * @param workBase origin of usable space in work array + * @param workLen usable size of work array */ - public static void sort(short[] a, int left, int right) { + static void sort(short[] a, int left, int right, + short[] work, int workBase, int workLen) { // Use counting sort on large arrays if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { int[] count = new int[NUM_SHORT_VALUES]; @@ -1002,7 +1019,7 @@ } while (--s > 0); } } else { // Use Dual-Pivot Quicksort on small arrays - doSort(a, left, right); + doSort(a, left, right, work, workBase, workLen); } } @@ -1015,8 +1032,12 @@ * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted + * @param work a workspace array (slice) + * @param workBase origin of usable space in work array + * @param workLen usable size of work array */ - private static void doSort(short[] a, int left, int right) { + private static void doSort(short[] a, int left, int right, + short[] work, int workBase, int workLen) { // Use Quicksort on small arrays if (right - left < QUICKSORT_THRESHOLD) { sort(a, left, right, true); @@ -1059,24 +1080,35 @@ } // Check special cases + // Implementation note: variable "right" is increased by 1. if (run[count] == right++) { // The last run contains one element run[++count] = right; } else if (count == 1) { // The array is already sorted return; } - /* - * Create temporary array, which is used for merging. - * Implementation note: variable "right" is increased by 1. - */ - short[] b; byte odd = 0; + // Determine alternation base for merge + byte odd = 0; for (int n = 1; (n <<= 1) < count; odd ^= 1); + // Use or create temporary array b for merging + short[] b; // temp array; alternates with a + int ao, bo; // array offsets from 'left' + int blen = right - left; // space needed for b + if (work == null || workLen < blen || workBase + blen > work.length) { + work = new short[blen]; + workBase = 0; + } if (odd == 0) { - b = a; a = new short[b.length]; - for (int i = left - 1; ++i < right; a[i] = b[i]); + System.arraycopy(a, left, work, workBase, blen); + b = a; + bo = 0; + a = work; + ao = workBase - left; } else { - b = new short[a.length]; + b = work; + ao = 0; + bo = workBase - left; } // Merging @@ -1084,21 +1116,22 @@ for (int k = (last = 0) + 2; k <= count; k += 2) { int hi = run[k], mi = run[k - 1]; for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) { - if (q >= hi || p < mi && a[p] <= a[q]) { - b[i] = a[p++]; + if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) { + b[i + bo] = a[p++ + ao]; } else { - b[i] = a[q++]; + b[i + bo] = a[q++ + ao]; } } run[++last] = hi; } if ((count & 1) != 0) { for (int i = right, lo = run[count - 1]; --i >= lo; - b[i] = a[i] + b[i + bo] = a[i + ao] ); run[++last] = right; } short[] t = a; a = b; b = t; + int o = ao; ao = bo; bo = o; } } @@ -1441,22 +1474,18 @@ } /** - * Sorts the specified array. - * - * @param a the array to be sorted - */ - public static void sort(char[] a) { - sort(a, 0, a.length - 1); - } - - /** - * Sorts the specified range of the array. + * Sorts the specified range of the array using the given + * workspace array slice if possible for merging * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted + * @param work a workspace array (slice) + * @param workBase origin of usable space in work array + * @param workLen usable size of work array */ - public static void sort(char[] a, int left, int right) { + static void sort(char[] a, int left, int right, + char[] work, int workBase, int workLen) { // Use counting sort on large arrays if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { int[] count = new int[NUM_CHAR_VALUES]; @@ -1474,7 +1503,7 @@ } while (--s > 0); } } else { // Use Dual-Pivot Quicksort on small arrays - doSort(a, left, right); + doSort(a, left, right, work, workBase, workLen); } } @@ -1487,8 +1516,12 @@ * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted + * @param work a workspace array (slice) + * @param workBase origin of usable space in work array + * @param workLen usable size of work array */ - private static void doSort(char[] a, int left, int right) { + private static void doSort(char[] a, int left, int right, + char[] work, int workBase, int workLen) { // Use Quicksort on small arrays if (right - left < QUICKSORT_THRESHOLD) { sort(a, left, right, true); @@ -1531,24 +1564,35 @@ } // Check special cases + // Implementation note: variable "right" is increased by 1. if (run[count] == right++) { // The last run contains one element run[++count] = right; } else if (count == 1) { // The array is already sorted return; } - /* - * Create temporary array, which is used for merging. - * Implementation note: variable "right" is increased by 1. - */ - char[] b; byte odd = 0; + // Determine alternation base for merge + byte odd = 0; for (int n = 1; (n <<= 1) < count; odd ^= 1); + // Use or create temporary array b for merging + char[] b; // temp array; alternates with a + int ao, bo; // array offsets from 'left' + int blen = right - left; // space needed for b + if (work == null || workLen < blen || workBase + blen > work.length) { + work = new char[blen]; + workBase = 0; + } if (odd == 0) { - b = a; a = new char[b.length]; - for (int i = left - 1; ++i < right; a[i] = b[i]); + System.arraycopy(a, left, work, workBase, blen); + b = a; + bo = 0; + a = work; + ao = workBase - left; } else { - b = new char[a.length]; + b = work; + ao = 0; + bo = workBase - left; } // Merging @@ -1556,21 +1600,22 @@ for (int k = (last = 0) + 2; k <= count; k += 2) { int hi = run[k], mi = run[k - 1]; for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) { - if (q >= hi || p < mi && a[p] <= a[q]) { - b[i] = a[p++]; + if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) { + b[i + bo] = a[p++ + ao]; } else { - b[i] = a[q++]; + b[i + bo] = a[q++ + ao]; } } run[++last] = hi; } if ((count & 1) != 0) { for (int i = right, lo = run[count - 1]; --i >= lo; - b[i] = a[i] + b[i + bo] = a[i + ao] ); run[++last] = right; } char[] t = a; a = b; b = t; + int o = ao; ao = bo; bo = o; } } @@ -1916,22 +1961,13 @@ private static final int NUM_BYTE_VALUES = 1 << 8; /** - * Sorts the specified array. - * - * @param a the array to be sorted - */ - public static void sort(byte[] a) { - sort(a, 0, a.length - 1); - } - - /** * Sorts the specified range of the array. * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted */ - public static void sort(byte[] a, int left, int right) { + static void sort(byte[] a, int left, int right) { // Use counting sort on large arrays if (right - left > COUNTING_SORT_THRESHOLD_FOR_BYTE) { int[] count = new int[NUM_BYTE_VALUES]; @@ -1963,22 +1999,18 @@ } /** - * Sorts the specified array. - * - * @param a the array to be sorted - */ - public static void sort(float[] a) { - sort(a, 0, a.length - 1); - } - - /** - * Sorts the specified range of the array. + * Sorts the specified range of the array using the given + * workspace array slice if possible for merging * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted + * @param work a workspace array (slice) + * @param workBase origin of usable space in work array + * @param workLen usable size of work array */ - public static void sort(float[] a, int left, int right) { + static void sort(float[] a, int left, int right, + float[] work, int workBase, int workLen) { /* * Phase 1: Move NaNs to the end of the array. */ @@ -1997,7 +2029,7 @@ /* * Phase 2: Sort everything except NaNs (which are already in place). */ - doSort(a, left, right); + doSort(a, left, right, work, workBase, workLen); /* * Phase 3: Place negative zeros before positive zeros. @@ -2064,8 +2096,12 @@ * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted + * @param work a workspace array (slice) + * @param workBase origin of usable space in work array + * @param workLen usable size of work array */ - private static void doSort(float[] a, int left, int right) { + private static void doSort(float[] a, int left, int right, + float[] work, int workBase, int workLen) { // Use Quicksort on small arrays if (right - left < QUICKSORT_THRESHOLD) { sort(a, left, right, true); @@ -2108,24 +2144,35 @@ } // Check special cases + // Implementation note: variable "right" is increased by 1. if (run[count] == right++) { // The last run contains one element run[++count] = right; } else if (count == 1) { // The array is already sorted return; } - /* - * Create temporary array, which is used for merging. - * Implementation note: variable "right" is increased by 1. - */ - float[] b; byte odd = 0; + // Determine alternation base for merge + byte odd = 0; for (int n = 1; (n <<= 1) < count; odd ^= 1); + // Use or create temporary array b for merging + float[] b; // temp array; alternates with a + int ao, bo; // array offsets from 'left' + int blen = right - left; // space needed for b + if (work == null || workLen < blen || workBase + blen > work.length) { + work = new float[blen]; + workBase = 0; + } if (odd == 0) { - b = a; a = new float[b.length]; - for (int i = left - 1; ++i < right; a[i] = b[i]); + System.arraycopy(a, left, work, workBase, blen); + b = a; + bo = 0; + a = work; + ao = workBase - left; } else { - b = new float[a.length]; + b = work; + ao = 0; + bo = workBase - left; } // Merging @@ -2133,21 +2180,22 @@ for (int k = (last = 0) + 2; k <= count; k += 2) { int hi = run[k], mi = run[k - 1]; for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) { - if (q >= hi || p < mi && a[p] <= a[q]) { - b[i] = a[p++]; + if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) { + b[i + bo] = a[p++ + ao]; } else { - b[i] = a[q++]; + b[i + bo] = a[q++ + ao]; } } run[++last] = hi; } if ((count & 1) != 0) { for (int i = right, lo = run[count - 1]; --i >= lo; - b[i] = a[i] + b[i + bo] = a[i + ao] ); run[++last] = right; } float[] t = a; a = b; b = t; + int o = ao; ao = bo; bo = o; } } @@ -2490,22 +2538,18 @@ } /** - * Sorts the specified array. - * - * @param a the array to be sorted - */ - public static void sort(double[] a) { - sort(a, 0, a.length - 1); - } - - /** - * Sorts the specified range of the array. + * Sorts the specified range of the array using the given + * workspace array slice if possible for merging * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted + * @param work a workspace array (slice) + * @param workBase origin of usable space in work array + * @param workLen usable size of work array */ - public static void sort(double[] a, int left, int right) { + static void sort(double[] a, int left, int right, + double[] work, int workBase, int workLen) { /* * Phase 1: Move NaNs to the end of the array. */ @@ -2524,7 +2568,7 @@ /* * Phase 2: Sort everything except NaNs (which are already in place). */ - doSort(a, left, right); + doSort(a, left, right, work, workBase, workLen); /* * Phase 3: Place negative zeros before positive zeros. @@ -2591,8 +2635,12 @@ * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted + * @param work a workspace array (slice) + * @param workBase origin of usable space in work array + * @param workLen usable size of work array */ - private static void doSort(double[] a, int left, int right) { + private static void doSort(double[] a, int left, int right, + double[] work, int workBase, int workLen) { // Use Quicksort on small arrays if (right - left < QUICKSORT_THRESHOLD) { sort(a, left, right, true); @@ -2635,24 +2683,35 @@ } // Check special cases + // Implementation note: variable "right" is increased by 1. if (run[count] == right++) { // The last run contains one element run[++count] = right; } else if (count == 1) { // The array is already sorted return; } - /* - * Create temporary array, which is used for merging. - * Implementation note: variable "right" is increased by 1. - */ - double[] b; byte odd = 0; + // Determine alternation base for merge + byte odd = 0; for (int n = 1; (n <<= 1) < count; odd ^= 1); + // Use or create temporary array b for merging + double[] b; // temp array; alternates with a + int ao, bo; // array offsets from 'left' + int blen = right - left; // space needed for b + if (work == null || workLen < blen || workBase + blen > work.length) { + work = new double[blen]; + workBase = 0; + } if (odd == 0) { - b = a; a = new double[b.length]; - for (int i = left - 1; ++i < right; a[i] = b[i]); + System.arraycopy(a, left, work, workBase, blen); + b = a; + bo = 0; + a = work; + ao = workBase - left; } else { - b = new double[a.length]; + b = work; + ao = 0; + bo = workBase - left; } // Merging @@ -2660,21 +2719,22 @@ for (int k = (last = 0) + 2; k <= count; k += 2) { int hi = run[k], mi = run[k - 1]; for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) { - if (q >= hi || p < mi && a[p] <= a[q]) { - b[i] = a[p++]; + if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) { + b[i + bo] = a[p++ + ao]; } else { - b[i] = a[q++]; + b[i + bo] = a[q++ + ao]; } } run[++last] = hi; } if ((count & 1) != 0) { for (int i = right, lo = run[count - 1]; --i >= lo; - b[i] = a[i] + b[i + bo] = a[i + ao] ); run[++last] = right; } double[] t = a; a = b; b = t; + int o = ao; ao = bo; bo = o; } } diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/util/ListResourceBundle.java --- a/jdk/src/share/classes/java/util/ListResourceBundle.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/util/ListResourceBundle.java Wed Jul 05 18:57:52 2017 +0200 @@ -89,7 +89,7 @@ * * public class MyResources_fr extends ListResourceBundle { * protected Object[][] getContents() { - * return new Object[][] = { + * return new Object[][] { * // LOCALIZE THIS * {"s1", "Le disque \"{1}\" {0}."}, // MessageFormat pattern * {"s2", "1"}, // location of {0} in pattern diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/util/PropertyResourceBundle.java --- a/jdk/src/share/classes/java/util/PropertyResourceBundle.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/util/PropertyResourceBundle.java Wed Jul 05 18:57:52 2017 +0200 @@ -124,6 +124,8 @@ * to read from. * @throws IOException if an I/O error occurs * @throws NullPointerException if stream is null + * @throws IllegalArgumentException if {@code stream} contains a + * malformed Unicode escape sequence. */ @SuppressWarnings({"unchecked", "rawtypes"}) public PropertyResourceBundle (InputStream stream) throws IOException { @@ -142,6 +144,8 @@ * read from. * @throws IOException if an I/O error occurs * @throws NullPointerException if reader is null + * @throws IllegalArgumentException if a malformed Unicode escape sequence appears + * from {@code reader}. * @since 1.6 */ @SuppressWarnings({"unchecked", "rawtypes"}) diff -r a233c04832cf -r a08d0f5b08bc jdk/src/share/classes/java/util/Spliterator.java --- a/jdk/src/share/classes/java/util/Spliterator.java Thu May 30 10:58:13 2013 -0700 +++ b/jdk/src/share/classes/java/util/Spliterator.java Wed Jul 05 18:57:52 2017 +0200 @@ -140,32 +140,32 @@ * (in approximate order of decreasing desirability): *

    *
  • The source cannot be structurally interfered with. - *
    For example, an instance of + *
    For example, an instance of * {@link java.util.concurrent.CopyOnWriteArrayList} is an immutable source. * A Spliterator created from the source reports a characteristic of * {@code IMMUTABLE}.
  • *
  • The source manages concurrent modifications. - *
    For example, a key set of a {@link java.util.concurrent.ConcurrentHashMap} + *
    For example, a key set of a {@link java.util.concurrent.ConcurrentHashMap} * is a concurrent source. A Spliterator created from the source reports a * characteristic of {@code CONCURRENT}.
  • *
  • The mutable source provides a late-binding and fail-fast Spliterator. - *
    Late binding narrows the window during which interference can affect + *
    Late binding narrows the window during which interference can affect * the calculation; fail-fast detects, on a best-effort basis, that structural * interference has occurred after traversal has commenced and throws * {@link ConcurrentModificationException}. For example, {@link ArrayList}, * and many other non-concurrent {@code Collection} classes in the JDK, provide * a late-binding, fail-fast spliterator.
  • *
  • The mutable source provides a non-late-binding but fail-fast Spliterator. - *
    The source increases the likelihood of throwing + *
    The source increases the likelihood of throwing * {@code ConcurrentModificationException} since the window of potential * interference is larger.
  • *
  • The mutable source provides a late-binding and non-fail-fast Spliterator. - *
    The source risks arbitrary, non-deterministic behavior after traversal + *
    The source risks arbitrary, non-deterministic behavior after traversal * has commenced since interference is not detected. *
  • *
  • The mutable source provides a non-late-binding and non-fail-fast * Spliterator. - *
    The source increases the risk of arbitrary, non-deterministic behavior + *
    The source increases the risk of arbitrary, non-deterministic behavior * since non-detected interference may occur after construction. *
  • *
@@ -284,6 +284,8 @@ * is set to {@code true} then diagnostic warnings are reported if boxing of * primitive values occur when operating on primitive subtype specializations. * + * @param the type of elements returned by this Spliterator + * * @see Collection * @since 1.8 */ @@ -333,9 +335,8 @@ * Upon non-null return: *
  • Implementing Your Own Script @@ -466,10 +477,10 @@ -Note that the name of the type is always a string for a fully qualified name. You can use any of these types to create new instances, e.g.: +Note that the name of the type is always a string for a fully qualified name. You can use any of these expressions to create new instances, e.g.:
    
    - var anArrayList = new Java.type("java.util.ArrayList")
    + var anArrayList = new (Java.type("java.util.ArrayList"))
     
    or @@ -496,6 +507,37 @@

    You can access both static and non-static inner classes. If you want to create an instance of a non-static inner class, remember to pass an instance of its outer class as the first argument to the constructor.

    +

    +In addition to creating new instances, the type objects returned from Java.type calls can also be used to access the +static fields and methods of the classes: +

    
    + var File = Java.type("java.io.File")
    + File.createTempFile("nashorn", ".tmp")
    +
    +

    +Methods with names of the form isXxx(), getXxx(), and setXxx() can also be used as properties, for both instances and statics. +

    +

    +A type object returned from Java.type is distinct from a java.lang.Class object. You can obtain one from the other using properties class and static on them. +

    
    + var ArrayList = Java.type("java.util.ArrayList")
    + var a = new ArrayList
    +
    + // All of the following print true:
    + print("Type acts as target of instanceof: " + (a instanceof ArrayList))
    + print("Class doesn't act as target of instanceof: " + !(a instanceof a.getClass()))
    + print("Type is not same as instance's getClass(): " + (a.getClass() !== ArrayList))
    + print("Type's `class` property is same as instance getClass(): " + (a.getClass() === ArrayList.class))
    + print("Type is same as instance getClass()'s `static` property: " + (a.getClass().static === ArrayList))
    +
    +

    +You can think of the type object as similar to the class names as used in Java source code: you use them as the +arguments to the new and instanceof operators and as the namespace for the static fields +and methods, but they are different than the runtime Class objects returned by getClass() calls. +Syntactically and semantically, this separation produces code that is most similar to Java code, where a distinction +between compile-time class expressions and runtime class objects also exists. (Also, Java can't have the equivalent of static +property on a Class object since compile-time class expressions are never reified as objects). +


    Importing Java Packages, Classes

    @@ -558,10 +600,7 @@

    Creating, Converting and Using Java Arrays

    -Array element access or length access is -the same as in Java. Also, a script array can be used when a Java -method expects a Java array (auto conversion). So in most cases we -don't have to create Java arrays explicitly.

    +Array element access or length access is the same as in Java.

    
     // javaarray.js
     
    @@ -577,27 +616,31 @@
     

    It is also possible to convert between JavaScript and Java arrays. -Given a JavaScript array and a Java type, Java.toJavaArray returns a Java array with the same initial contents, and with the specified component type. +Given a JavaScript array and a Java type, Java.to returns a Java array with the same initial contents, and with the specified array type.

    
      var anArray = [1, "13", false]
    - var javaIntArray = Java.toJavaArray(anArray, "int")
    + var javaIntArray = Java.to(anArray, "int[]")
      print(javaIntArray[0]) // prints 1
      print(javaIntArray[1]) // prints 13, as string "13" was converted to number 13 as per ECMAScript ToNumber conversion
      print(javaIntArray[2]) // prints 0, as boolean false was converted to number 0 as per ECMAScript ToNumber conversion
     

    -Given a Java array or Collection, Java.toJavaScriptArray returns a JavaScript array with a shallow copy of its contents. Note that in most cases, you can use Java arrays and lists natively in Nashorn; in cases where for some reason you need to have an actual JavaScript native array (e.g. to work with the array comprehensions functions), you will want to use this method.i +You can use either a string or a type object returned from Java.type() to specify the type of the array. +You can also omit the array type, in which case a Object[] will be created. +

    +

    +Given a Java array or Collection, Java.from returns a JavaScript array with a shallow copy of its contents. Note that in most cases, you can use Java arrays and lists natively in Nashorn; in cases where for some reason you need to have an actual JavaScript native array (e.g. to work with the array comprehensions functions), you will want to use this method.

    
     var File = Java.type("java.io.File");
     var listCurDir = new File(".").listFiles();
    -var jsList = Java.toJavaScriptArray(listCurDir);
    +var jsList = Java.from(listCurDir);
     print(jsList);
     

    -

    Implementing Java Interfaces

    +

    Implementing Java interfaces

    A Java interface can be implemented in JavaScript by using a Java anonymous class-like syntax:

    
    @@ -631,8 +674,8 @@
     
     

    - -

    Extending Java classes

    + +

    Extending Abstract Java Classes

    If a Java class is abstract, you can instantiate an anonymous subclass of it using an argument list that is applicable to any of its public or protected constructors, but inserting a JavaScript object with functions properties that provide JavaScript implementations of the abstract methods. If method names are overloaded, the JavaScript function will provide implementation for all overloads. E.g.:

    @@ -671,6 +714,9 @@ Here, Timer.schedule() expects a TimerTask as its argument, so Nashorn creates an instance of a TimerTask subclass and uses the passed function to implement its only abstract method, run(). In this usage though, you can't use non-default constructors; the type must be either an interface, or must have a protected or public no-arg constructor. +
    + +

    Extending Concrete Java Classes

    To extend a concrete Java class, you have to use Java.extend function. Java.extend returns a type object for a subclass of the specified Java class (or implementation of the specified interface) that acts as a script-to-Java adapter for it. @@ -695,26 +741,178 @@ printSizeInvokedArrayList.size(); printAddInvokedArrayList.add(33, 33); +

    +The reason you must use Java.extend() with concrete classes is that with concrete classes, there can be a +syntactic ambiguity if you just invoke their constructor. Consider this example: +

    +
    
    +var t = new java.lang.Thread({ run: function() { print("Hello!") } })
    +
    +

    +If we allowed subclassing of concrete classes with constructor syntax, Nashorn couldn't tell if you're creating a new +Thread and passing it a Runnable at this point, or you are subclassing Thread and +passing it a new implementation for its own run() method. +

    +
    + +

    Implementing Multiple Interfaces

    +

    +Java.extend can in fact take a list of multiple types. At most one of the types can be a class, and the rest must +be interfaces (the class doesn't have to be the first in the list). You will get back an object that extends the class and +implements all the interfaces. (Obviously, if you only specify interfaces and no class, the object will extend java.lang.Object). +


    + +

    Class-Bound Implementations

    +

    +The methods shown so far for extending Java classes and implementing interfaces – passing an implementation JavaScript object +or function to a constructor, or using Java.extend with new – all produce classes that take an +extra JavaScript object parameter in their constructors that specifies the implementation. The implementation is therefore always bound +to the actual instance being created with new, and not to the whole class. This has some advantages, for example in the +memory footprint of the runtime, as Nashorn can just create a single "universal adapter" for every combination of types being implemented. +In reality, the below code shows that different instantiations of, say, Runnable have the same class regardless of them having +different JavaScript implementation objects: +

    +
    
    +var Runnable = java.lang.Runnable;
    +var r1 = new Runnable(function() { print("I'm runnable 1!") })
    +var r2 = new Runnable(function() { print("I'm runnable 2!") })
    +r1.run()
    +r2.run()
    +print("We share the same class: " + (r1.class === r2.class))
    +
    +

    +prints: +

    +
    
    +I'm runnable 1!
    +I'm runnable 2!
    +We share the same class: true
    +
    +

    +Sometimes, however, you'll want to extend a Java class or implement an interface with implementation bound to the class, not to +its instances. Such a need arises, for example, when you need to pass the class for instantiation to an external API; prime example +of this is the JavaFX framework where you need to pass an Application class to the FX API and let it instantiate it. +

    +

    +Fortunately, there's a solution for that: Java.extend() – aside from being able to take any number of type parameters +denoting a class to extend and interfaces to implement – can also take one last argument that has to be a JavaScript object +that serves as the implementation for the methods. In this case, Java.extend() will create a class that has the same +constructors as the original class had, as they don't need to take an an extra implementation object parameter. The example below +shows how you can create class-bound implementations, and shows that in this case, the implementation classes for different invocations +are indeed different: +

    +
    
    +var RunnableImpl1 = Java.extend(java.lang.Runnable, function() { print("I'm runnable 1!") })
    +var RunnableImpl2 = Java.extend(java.lang.Runnable, function() { print("I'm runnable 2!") })
    +var r1 = new RunnableImpl1()
    +var r2 = new RunnableImpl2()
    +r1.run()
    +r2.run()
    +print("We share the same class: " + (r1.class === r2.class))
    +
    +

    +prints: +

    +
    
    +I'm runnable 1!
    +I'm runnable 2!
    +We share the same class: false
    +
    +

    +As you can see, the major difference here is that we moved the implementation object into the invocation of Java.extend +from the constructor invocations – indeed the constructor invocations now don't even need to take an extra parameter! Since +the implementations are bound to a class, the two classes obviously can't be the same, and we indeed see that the two runnables no +longer share the same class – every invocation of Java.extend() with a class-specific implementation object triggers +the creation of a new Java adapter class. +

    +

    +Finally, the adapter classes with class-bound implementations can still take an additional constructor parameter to further +override the behavior on a per-instance basis. Thus, you can even combine the two approaches: you can provide part of the implementation +in a class-based JavaScript implementation object passed to Java.extend, and part in another object passed to the constructor. +Whatever functions are provided by the constructor-passed object will override the functions in the class-bound object. +

    +
    
    +var RunnableImpl = Java.extend(java.lang.Runnable, function() { print("I'm runnable 1!") })
    +var r1 = new RunnableImpl()
    +var r2 = new RunnableImpl(function() { print("I'm runnable 2!") })
    +r1.run()
    +r2.run()
    +print("We share the same class: " + (r1.class === r2.class))
    +
    +

    +prints: +

    +
    
    +I'm runnable 1!
    +I'm runnable 2!
    +We share the same class: true
    +

    Overload Resolution

    Java methods can be overloaded by argument types. In Java, overload resolution occurs at compile time (performed by javac). -When calling Java methods from a script, the script -interpreter/compiler needs to select the appropriate method. With -the JavaScript engine, you do not need to do anything special - the -correct Java method overload variant is selected based on the -argument types. But, sometimes you may want (or have) to explicitly -select a particular overload variant.

    +When calling Java methods from Nashorn, the appropriate method will be +selected based on the argument types at invocation time. You do not need +to do anything special – the correct Java method overload variant +is selected based automatically. You still have the option of explicitly +specifying a particular overload variant. Reasons for this include +either running into a genuine ambiguity with actual argument types, or +rarely reasons of performance – if you specify the actual overload +then the engine doesn't have to perform resolution during invocation. +Individual overloads of a Java methods are exposed as special properties +with the name of the method followed with its signature in parentheses. +You can invoke them like this:

    
     // overload.js
     
     var out = java.lang.System.out;
     
     // select a particular print function 
    -out["println(java.lang.Object)"]("hello");
    +out["println(Object)"]("hello");
     
     
    +

    +Note that you normally don't even have to use qualified class names in +the signatures as long as the unqualified name of the type is sufficient +for uniquely identifying the signature. In practice this means that only +in the extremely unlikely case that two overloads only differ in +parameter types that have identical unqualified names but come from +different packages would you need to use the fully qualified name of the +class. +

    +
    + +

    Mapping of Data Types Between Java and JavaScript

    +

    +We have previously shown some of the data type mappings between Java and JavaScript. +We saw that arrays need to be explicitly converted. We have also shown that JavaScript functions +are automatically converted to SAM types when passed as parameters to Java methods. Most other +conversions work as you would expect. +

    +

    +Every JavaScript object is also a java.util.Map so APIs receiving maps will receive them directly. +

    +

    +When numbers are passed to a Java API, they will be converted to the expected target numeric type, either boxed or +primitive, but if the target type is less specific, say Number or Object, you can only +count on them being a Number, and have to test specifically for whether it's a boxed Double, +Integer, Long, etc. – it can be any of these due to internal optimizations. Also, you +can pass any JavaScript value to a Java API expecting either a boxed or primitive number; the JavaScript specification's +ToNumber conversion algorithm will be applied to the value. +

    +

    +In a similar vein, if a Java method expects a String or a Boolean, the values will be +converted using all conversions allowed by the JavaScript specification's ToString and ToBoolean +conversions. +

    +

    +Finally, a word of caution about strings. Due to internal performance optimizations of string operations, JavaScript strings are +not always necessarily of type java.lang.String, but they will always be of type java.lang.CharSequence. +If you pass them to a Java method that expects a java.lang.String parameter, then you will naturally receive a Java +String, but if the signature of your method is more generic, i.e. it receives a java.lang.Object parameter, you can +end up with an object of private engine implementation class that implements CharSequence but is not a Java String. +


    Implementing Your Own Script Engine

    diff -r a233c04832cf -r a08d0f5b08bc nashorn/docs/source/javaarray.js --- a/nashorn/docs/source/javaarray.js Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/docs/source/javaarray.js Wed Jul 05 18:57:52 2017 +0200 @@ -40,7 +40,7 @@ // convert a script array to Java array var anArray = [1, "13", false]; -var javaIntArray = Java.toJavaArray(anArray, "int"); +var javaIntArray = Java.to(anArray, "int[]"); print(javaIntArray[0]);// prints 1 print(javaIntArray[1]); // prints 13, as string "13" was converted to number 13 as per ECMAScript ToNumber conversion print(javaIntArray[2]);// prints 0, as boolean false was converted to number 0 as per ECMAScript ToNumber conversion @@ -48,5 +48,5 @@ // convert a Java array to a JavaScript array var File = Java.type("java.io.File"); var listCurDir = new File(".").listFiles(); -var jsList = Java.toJavaScriptArray(listCurDir); +var jsList = Java.from(listCurDir); print(jsList); diff -r a233c04832cf -r a08d0f5b08bc nashorn/make/build-benchmark.xml --- a/nashorn/make/build-benchmark.xml Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/make/build-benchmark.xml Wed Jul 05 18:57:52 2017 +0200 @@ -24,258 +24,270 @@ - - - - + + + + + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + + - + - + - + @@ -307,7 +319,7 @@ - + diff -r a233c04832cf -r a08d0f5b08bc nashorn/make/build.xml --- a/nashorn/make/build.xml Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/make/build.xml Wed Jul 05 18:57:52 2017 +0200 @@ -212,7 +212,9 @@ target="${javac.target}" debug="${javac.debug}" encoding="${javac.encoding}" - includeantruntime="false"/> + includeantruntime="false"> + + @@ -305,6 +307,8 @@ + + diff -r a233c04832cf -r a08d0f5b08bc nashorn/make/code_coverage.xml --- a/nashorn/make/code_coverage.xml Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/make/code_coverage.xml Wed Jul 05 18:57:52 2017 +0200 @@ -139,6 +139,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r a233c04832cf -r a08d0f5b08bc nashorn/make/project.properties --- a/nashorn/make/project.properties Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/make/project.properties Wed Jul 05 18:57:52 2017 +0200 @@ -87,6 +87,7 @@ testng.listeners=\ org.testng.reporters.SuiteHTMLReporter, \ + org.testng.reporters.TestHTMLReporter, \ org.testng.reporters.jq.Main, \ org.testng.reporters.FailedReporter, \ org.testng.reporters.XMLReporter \ @@ -214,9 +215,13 @@ run.test.xmx=3G run.test.xms=2G +run.test.user.language=tr +run.test.user.country=TR + # -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods # add '-Dtest.js.outofprocess' to run each test in a new sub-process -run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8 +run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -ea -Dfile.encoding=UTF-8 -Duser.language=${run.test.user.language} -Duser.country=${run.test.user.country} + #-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main} diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/api/scripting/JSObject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/nashorn/api/scripting/JSObject.java Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,87 @@ +/* + * 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; + +/** + * netscape.javascript.JSObject-like interface for nashorn script objects. + */ +public abstract class JSObject { + /** + * Call a JavaScript method + * + * @param methodName name of method + * @param args arguments to method + * @return result of call + */ + public abstract Object call(String methodName, Object args[]); + + /** + * Evaluate a JavaScript expression + * + * @param s JavaScript expression to evaluate + * @return evaluation result + */ + public abstract Object eval(String s); + + /** + * Retrieves a named member of a JavaScript object. + * + * @param name of member + * @return member + */ + public abstract Object getMember(String name); + + /** + * Retrieves an indexed member of a JavaScript object. + * + * @param index index of member slot + * @return member + */ + public abstract Object getSlot(int index); + + /** + * Remove a named member from a JavaScript object + * + * @param name name of member + */ + public abstract void removeMember(String name); + + /** + * Set a named member in a JavaScript object + * + * @param name name of member + * @param value value of member + */ + public abstract void setMember(String name, Object value); + + /** + * Set an indexed member in a JavaScript object + * + * @param index index of member slot + * @param value value of member + */ + public abstract void setSlot(int index, Object value); +} diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java --- a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Wed Jul 05 18:57:52 2017 +0200 @@ -42,7 +42,6 @@ import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; -import netscape.javascript.JSObject; /** * Mirror object that wraps a given ScriptObject instance. User can diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/api/scripting/resources/engine.js --- a/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js Wed Jul 05 18:57:52 2017 +0200 @@ -88,7 +88,7 @@ } } - array = Java.toJavaArray(array); + array = Java.to(array); return Packages.jdk.nashorn.api.scripting.ScriptUtils.format(format, array); } }); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/codegen/Attr.java --- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Wed Jul 05 18:57:52 2017 +0200 @@ -84,8 +84,8 @@ import jdk.nashorn.internal.ir.UnaryNode; import jdk.nashorn.internal.ir.VarNode; import jdk.nashorn.internal.ir.WithNode; +import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; -import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.parser.TokenType; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.Debug; @@ -111,7 +111,7 @@ * computed. */ -final class Attr extends NodeOperatorVisitor { +final class Attr extends NodeOperatorVisitor { /** * Local definitions in current block (to discriminate from function @@ -138,6 +138,7 @@ * Constructor. */ Attr(final TemporarySymbols temporarySymbols) { + super(new LexicalContext()); this.temporarySymbols = temporarySymbols; this.localDefs = new ArrayDeque<>(); this.localUses = new ArrayDeque<>(); @@ -202,7 +203,7 @@ private void acceptDeclarations(final FunctionNode functionNode, final Block body) { // This visitor will assign symbol to all declared variables, except function declarations (which are taken care // in a separate step above) and "var" declarations in for loop initializers. - body.accept(new NodeOperatorVisitor() { + body.accept(new NodeVisitor(new LexicalContext()) { @Override public boolean enterFunctionNode(final FunctionNode nestedFn) { return false; @@ -218,7 +219,7 @@ if (varNode.isFunctionDeclaration()) { newType(symbol, FunctionNode.FUNCTION_TYPE); } - return varNode.setName((IdentNode)ident.setSymbol(getLexicalContext(), symbol)); + return varNode.setName((IdentNode)ident.setSymbol(lc, symbol)); } return varNode; } @@ -227,8 +228,8 @@ private void enterFunctionBody() { - final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); - final Block body = getLexicalContext().getCurrentBlock(); + final FunctionNode functionNode = lc.getCurrentFunction(); + final Block body = lc.getCurrentBlock(); initFunctionWideVariables(functionNode, body); @@ -256,7 +257,7 @@ //the symbols in the block should really be stateless block.clearSymbols(); - if (getLexicalContext().isFunctionBody()) { + if (lc.isFunctionBody()) { enterFunctionBody(); } pushLocalsBlock(); @@ -283,7 +284,7 @@ @Override public boolean enterCatchNode(final CatchNode catchNode) { final IdentNode exception = catchNode.getException(); - final Block block = getLexicalContext().getCurrentBlock(); + final Block block = lc.getCurrentBlock(); start(catchNode); @@ -298,10 +299,10 @@ @Override public Node leaveCatchNode(final CatchNode catchNode) { final IdentNode exception = catchNode.getException(); - final Block block = getLexicalContext().getCurrentBlock(); + final Block block = lc.getCurrentBlock(); final Symbol symbol = findSymbol(block, exception.getName()); assert symbol != null; - return end(catchNode.setException((IdentNode)exception.setSymbol(getLexicalContext(), symbol))); + return end(catchNode.setException((IdentNode)exception.setSymbol(lc, symbol))); } /** @@ -320,7 +321,7 @@ flags |= IS_SCOPE; } - final FunctionNode function = getLexicalContext().getFunction(block); + final FunctionNode function = lc.getFunction(block); if (symbol != null) { // Symbol was already defined. Check if it needs to be redefined. if ((flags & KINDMASK) == IS_PARAM) { @@ -353,12 +354,12 @@ if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) { symbolBlock = block; //internal vars are always defined in the block closest to them } else { - symbolBlock = getLexicalContext().getFunctionBody(function); + symbolBlock = lc.getFunctionBody(function); } // Create and add to appropriate block. symbol = new Symbol(name, flags); - symbolBlock.putSymbol(getLexicalContext(), symbol); + symbolBlock.putSymbol(lc, symbol); if ((flags & Symbol.KINDMASK) != IS_GLOBAL) { symbol.setNeedsSlot(true); @@ -381,7 +382,7 @@ //an outermost function in our lexical context that is not a program (runScript) //is possible - it is a function being compiled lazily if (functionNode.isDeclared()) { - final Iterator blocks = getLexicalContext().getBlocks(); + final Iterator blocks = lc.getBlocks(); if (blocks.hasNext()) { defineSymbol(blocks.next(), functionNode.getIdent().getName(), IS_VAR); } @@ -397,13 +398,11 @@ public Node leaveFunctionNode(final FunctionNode functionNode) { FunctionNode newFunctionNode = functionNode; - final LexicalContext lc = getLexicalContext(); - final Block body = newFunctionNode.getBody(); //look for this function in the parent block if (functionNode.isDeclared()) { - final Iterator blocks = getLexicalContext().getBlocks(); + final Iterator blocks = lc.getBlocks(); if (blocks.hasNext()) { newFunctionNode = (FunctionNode)newFunctionNode.setSymbol(lc, findSymbol(blocks.next(), functionNode.getIdent().getName())); } @@ -411,7 +410,7 @@ final boolean anonymous = functionNode.isAnonymous(); final String name = anonymous ? null : functionNode.getIdent().getName(); if (anonymous || body.getExistingSymbol(name) != null) { - newFunctionNode = (FunctionNode)ensureSymbol(lc, FunctionNode.FUNCTION_TYPE, newFunctionNode); + newFunctionNode = (FunctionNode)ensureSymbol(FunctionNode.FUNCTION_TYPE, newFunctionNode); } else { assert name != null; final Symbol self = body.getExistingSymbol(name); @@ -490,8 +489,6 @@ start(identNode); - final LexicalContext lc = getLexicalContext(); - if (identNode.isPropertyName()) { // assign a pseudo symbol to property name final Symbol pseudoSymbol = pseudoSymbol(name); @@ -549,7 +546,7 @@ */ private void maybeForceScope(final Symbol symbol) { if (!symbol.isScope() && symbolNeedsToBeScope(symbol)) { - Symbol.setSymbolIsScope(getLexicalContext(), symbol); + Symbol.setSymbolIsScope(lc, symbol); } } @@ -558,7 +555,7 @@ return false; } boolean previousWasBlock = false; - for(final Iterator it = getLexicalContext().getAllNodes(); it.hasNext();) { + for(final Iterator it = lc.getAllNodes(); it.hasNext();) { final LexicalContextNode node = it.next(); if(node instanceof FunctionNode) { // We reached the function boundary without seeing a definition for the symbol - it needs to be in @@ -594,10 +591,8 @@ } if (symbol.isScope()) { - final LexicalContext lc = getLexicalContext(); - Block scopeBlock = null; - for (final Iterator contextNodeIter = getLexicalContext().getAllNodes(); contextNodeIter.hasNext(); ) { + for (final Iterator contextNodeIter = lc.getAllNodes(); contextNodeIter.hasNext(); ) { final LexicalContextNode node = contextNodeIter.next(); if (node instanceof Block) { if (((Block)node).getExistingSymbol(name) != null) { @@ -610,7 +605,7 @@ } if (scopeBlock != null) { - assert getLexicalContext().contains(scopeBlock); + assert lc.contains(scopeBlock); lc.setFlag(scopeBlock, Block.NEEDS_SCOPE); } } @@ -622,8 +617,8 @@ * @see #needsParentScope() */ private void setUsesGlobalSymbol() { - for (final Iterator fns = getLexicalContext().getFunctions(); fns.hasNext();) { - getLexicalContext().setFlag(fns.next(), FunctionNode.USES_ANCESTOR_SCOPE); + for (final Iterator fns = lc.getFunctions(); fns.hasNext();) { + lc.setFlag(fns.next(), FunctionNode.USES_ANCESTOR_SCOPE); } } @@ -635,7 +630,7 @@ private Symbol findSymbol(final Block block, final String name) { // Search up block chain to locate symbol. - for (final Iterator blocks = getLexicalContext().getBlocks(block); blocks.hasNext();) { + for (final Iterator blocks = lc.getBlocks(block); blocks.hasNext();) { // Find name. final Symbol symbol = blocks.next().getExistingSymbol(name); // If found then we are good. @@ -656,11 +651,11 @@ public Node leaveLiteralNode(final LiteralNode literalNode) { assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens assert literalNode instanceof ArrayLiteralNode || !(literalNode.getValue() instanceof Node) : "literals with Node values not supported"; - final Symbol symbol = new Symbol(getLexicalContext().getCurrentFunction().uniqueName(LITERAL_PREFIX.symbolName()), IS_CONSTANT, literalNode.getType()); + final Symbol symbol = new Symbol(lc.getCurrentFunction().uniqueName(LITERAL_PREFIX.symbolName()), IS_CONSTANT, literalNode.getType()); if (literalNode instanceof ArrayLiteralNode) { ((ArrayLiteralNode)literalNode).analyze(); } - return end(literalNode.setSymbol(getLexicalContext(), symbol)); + return end(literalNode.setSymbol(lc, symbol)); } @Override @@ -676,7 +671,7 @@ @Override public Node leavePropertyNode(final PropertyNode propertyNode) { // assign a pseudo symbol to property name, see NASHORN-710 - return propertyNode.setSymbol(getLexicalContext(), new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT)); + return propertyNode.setSymbol(lc, new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT)); } @Override @@ -734,11 +729,11 @@ type = Type.OBJECT; } - switchNode.setTag(newInternal(getLexicalContext().getCurrentFunction().uniqueName(SWITCH_TAG_PREFIX.symbolName()), type)); + switchNode.setTag(newInternal(lc.getCurrentFunction().uniqueName(SWITCH_TAG_PREFIX.symbolName()), type)); end(switchNode); - return switchNode.setCases(getLexicalContext(), newCases); + return switchNode.setCases(lc, newCases); } @Override @@ -761,7 +756,7 @@ final IdentNode ident = varNode.getName(); final String name = ident.getName(); - final Symbol symbol = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR); + final Symbol symbol = defineSymbol(lc.getCurrentBlock(), name, IS_VAR); assert symbol != null; // NASHORN-467 - use before definition of vars - conservative @@ -781,7 +776,6 @@ final IdentNode ident = newVarNode.getName(); final String name = ident.getName(); - final LexicalContext lc = getLexicalContext(); final Symbol symbol = findSymbol(lc.getCurrentBlock(), ident.getName()); if (init == null) { @@ -834,7 +828,7 @@ @Override public Node leaveDELETE(final UnaryNode unaryNode) { - final FunctionNode currentFunctionNode = getLexicalContext().getCurrentFunction(); + final FunctionNode currentFunctionNode = lc.getCurrentFunction(); final boolean strictMode = currentFunctionNode.isStrict(); final Node rhs = unaryNode.rhs(); final Node strictFlagNode = LiteralNode.newInstance(unaryNode, strictMode).accept(this); @@ -894,10 +888,10 @@ * @return true if the symbol denoted by the specified name in the current lexical context defined in the program level. */ private boolean isProgramLevelSymbol(final String name) { - for(final Iterator it = getLexicalContext().getBlocks(); it.hasNext();) { + for(final Iterator it = lc.getBlocks(); it.hasNext();) { final Block next = it.next(); if(next.getExistingSymbol(name) != null) { - return next == getLexicalContext().getFunctionBody(getLexicalContext().getOutermostFunction()); + return next == lc.getFunctionBody(lc.getOutermostFunction()); } } throw new AssertionError("Couldn't find symbol " + name + " in the context"); @@ -914,14 +908,14 @@ } private IdentNode compilerConstant(CompilerConstants cc) { - final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); + final FunctionNode functionNode = lc.getCurrentFunction(); return (IdentNode) new IdentNode( functionNode.getToken(), functionNode.getFinish(), cc.symbolName()). setSymbol( - getLexicalContext(), + lc, functionNode.compilerConstant(cc)); } @@ -999,7 +993,7 @@ final Node lhs = binaryNode.lhs(); if (lhs instanceof IdentNode) { - final Block block = getLexicalContext().getCurrentBlock(); + final Block block = lc.getCurrentBlock(); final IdentNode ident = (IdentNode)lhs; final String name = ident.getName(); @@ -1043,7 +1037,7 @@ } private boolean isLocal(FunctionNode function, Symbol symbol) { - final FunctionNode definingFn = getLexicalContext().getDefiningFunction(symbol); + final FunctionNode definingFn = lc.getDefiningFunction(symbol); // Temp symbols are not assigned to a block, so their defining fn is null; those can be assumed local return definingFn == null || definingFn == function; } @@ -1329,7 +1323,7 @@ @Override public Node leaveForNode(final ForNode forNode) { if (forNode.isForIn()) { - forNode.setIterator(newInternal(getLexicalContext().getCurrentFunction().uniqueName(ITERATOR_PREFIX.symbolName()), Type.OBJECT)); //NASHORN-73 + forNode.setIterator(newInternal(lc.getCurrentFunction().uniqueName(ITERATOR_PREFIX.symbolName()), Type.OBJECT)); //NASHORN-73 /* * Iterators return objects, so we need to widen the scope of the * init variable if it, for example, has been assigned double type @@ -1407,7 +1401,7 @@ final Symbol paramSymbol = functionNode.getBody().getExistingSymbol(param.getName()); assert paramSymbol != null; assert paramSymbol.isParam(); - newParams.add((IdentNode)param.setSymbol(getLexicalContext(), paramSymbol)); + newParams.add((IdentNode)param.setSymbol(lc, paramSymbol)); assert paramSymbol != null; Type type = functionNode.getHints().getParameterType(pos); @@ -1439,10 +1433,10 @@ FunctionNode newFunctionNode = functionNode; if (nparams == 0 || (specialize * 2) < nparams) { - newFunctionNode = newFunctionNode.clearSnapshot(getLexicalContext()); + newFunctionNode = newFunctionNode.clearSnapshot(lc); } - return newFunctionNode.setParameters(getLexicalContext(), newParams); + return newFunctionNode.setParameters(lc, newParams); } /** @@ -1506,7 +1500,7 @@ } private Symbol exceptionSymbol() { - return newInternal(getLexicalContext().getCurrentFunction().uniqueName(EXCEPTION_PREFIX.symbolName()), Type.typeFor(ECMAException.class)); + return newInternal(lc.getCurrentFunction().uniqueName(EXCEPTION_PREFIX.symbolName()), Type.typeFor(ECMAException.class)); } /** @@ -1520,8 +1514,8 @@ * @param assignmentDest the destination node of the assignment, e.g. lhs for binary nodes */ private Node ensureAssignmentSlots(final Node assignmentDest) { - final LexicalContext attrLexicalContext = getLexicalContext(); - return assignmentDest.accept(new NodeVisitor() { + final LexicalContext attrLexicalContext = lc; + return assignmentDest.accept(new NodeVisitor(new LexicalContext()) { @Override public Node leaveIndexNode(final IndexNode indexNode) { assert indexNode.getSymbol().isTemp(); @@ -1565,7 +1559,7 @@ FunctionNode currentFunctionNode = functionNode; do { changed.clear(); - final FunctionNode newFunctionNode = (FunctionNode)currentFunctionNode.accept(new NodeVisitor() { + final FunctionNode newFunctionNode = (FunctionNode)currentFunctionNode.accept(new NodeVisitor(new LexicalContext()) { private Node widen(final Node node, final Type to) { if (node instanceof LiteralNode) { @@ -1579,7 +1573,7 @@ symbol = temporarySymbols.getTypedTemporarySymbol(to); } newType(symbol, to); - final Node newNode = node.setSymbol(getLexicalContext(), symbol); + final Node newNode = node.setSymbol(lc, symbol); changed.add(newNode); return newNode; } @@ -1622,7 +1616,7 @@ return newBinaryNode; } }); - getLexicalContext().replace(currentFunctionNode, newFunctionNode); + lc.replace(currentFunctionNode, newFunctionNode); currentFunctionNode = newFunctionNode; } while (!changed.isEmpty()); return currentFunctionNode; @@ -1643,12 +1637,12 @@ } private Node ensureSymbol(final Type type, final Node node) { - LOG.info("New TEMPORARY added to ", getLexicalContext().getCurrentFunction().getName(), " type=", type); - return ensureSymbol(getLexicalContext(), type, node); + LOG.info("New TEMPORARY added to ", lc.getCurrentFunction().getName(), " type=", type); + return temporarySymbols.ensureSymbol(lc, type, node); } private Symbol newInternal(final String name, final Type type) { - final Symbol iter = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR | IS_INTERNAL); + final Symbol iter = defineSymbol(lc.getCurrentBlock(), name, IS_VAR | IS_INTERNAL); iter.setType(type); // NASHORN-73 return iter; } @@ -1705,10 +1699,6 @@ localUses.peek().add(name); } - private Node ensureSymbol(final LexicalContext lc, final Type type, final Node node) { - return temporarySymbols.ensureSymbol(lc, type, node); - } - /** * Pessimistically promote all symbols in current function node to Object types * This is done when the function contains unevaluated black boxes such as @@ -1717,7 +1707,7 @@ * @param body body for the function node we are leaving */ private static void objectifySymbols(final Block body) { - body.accept(new NodeVisitor() { + body.accept(new NodeVisitor(new LexicalContext()) { private void toObject(final Block block) { for (final Symbol symbol : block.getSymbols()) { if (!symbol.isTemp()) { @@ -1761,7 +1751,7 @@ append("] "). append(printNode ? node.toString() : ""). append(" in '"). - append(getLexicalContext().getCurrentFunction().getName()). + append(lc.getCurrentFunction().getName()). append("'"); LOG.info(sb); LOG.indent(); @@ -1787,7 +1777,7 @@ append("] "). append(printNode ? node.toString() : ""). append(" in '"). - append(getLexicalContext().getCurrentFunction().getName()); + append(lc.getCurrentFunction().getName()); if (node.getSymbol() == null) { sb.append(" "); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Jul 05 18:57:52 2017 +0200 @@ -52,16 +52,13 @@ import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT; import java.io.PrintWriter; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; -import java.util.Deque; import java.util.EnumSet; -import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import java.util.Map; +import java.util.Locale; import java.util.TreeMap; import jdk.nashorn.internal.codegen.ClassEmitter.Flag; @@ -83,11 +80,11 @@ import jdk.nashorn.internal.ir.ExecuteNode; import jdk.nashorn.internal.ir.ForNode; import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.ir.IdentNode; import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.IndexNode; -import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LexicalContextNode; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; @@ -150,7 +147,7 @@ * The CodeGenerator visits nodes only once, tags them as resolved and emits * bytecode for them. */ -final class CodeGenerator extends NodeOperatorVisitor { +final class CodeGenerator extends NodeOperatorVisitor { /** Name of the Global object, cannot be referred to as .class, @see CodeGenerator */ private static final String GLOBAL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "Global"; @@ -168,23 +165,12 @@ /** How many regexp fields have been emitted */ private int regexFieldCount; - /** Map of shared scope call sites */ - private final Map scopeCalls = new HashMap<>(); - - /** Compile unit stack - every time we start a sub method (e.g. a split) we push one */ - private final Deque compileUnits = new ArrayDeque<>(); - - /** Method emitter stack - every time we start a sub method (e.g. a split) we push one */ - private final Deque methodEmitters = new ArrayDeque<>(); - - /** The discard stack - whenever we enter a discard node we keep track of its return value status - - * i.e. should we keep it or throw it away */ - private final Deque discard = new ArrayDeque<>(); - - // A stack tracking the next free local variable slot in the blocks. There's one entry for every block - // currently on the lexical context stack. - private int[] nextFreeSlots = new int[16]; - private int nextFreeSlotsSize = 0; + /** Line number for last statement. If we encounter a new line number, line number bytecode information + * needs to be generated */ + private int lastLineNumber = -1; + + /** When should we stop caching regexp expressions in fields to limit bytecode size? */ + private static final int MAX_REGEX_FIELDS = 2 * 1024; /** Current method emitter */ private MethodEmitter method; @@ -192,20 +178,16 @@ /** Current compile unit */ private CompileUnit unit; - private int lastLineNumber = -1; - - /** When should we stop caching regexp expressions in fields to limit bytecode size? */ - private static final int MAX_REGEX_FIELDS = 2 * 1024; - private static final DebugLogger LOG = new DebugLogger("codegen", "nashorn.codegen.debug"); + /** * Constructor. * * @param compiler */ CodeGenerator(final Compiler compiler) { - super(new DynamicScopeTrackingLexicalContext()); + super(new CodeGeneratorLexicalContext()); this.compiler = compiler; this.callSiteFlags = compiler.getEnv()._callsite_flags; } @@ -217,37 +199,7 @@ * @return the correct flags for a call site in the current function */ int getCallSiteFlags() { - return getLexicalContext().getCurrentFunction().isStrict() ? callSiteFlags | CALLSITE_STRICT : callSiteFlags; - } - - private void pushMethodEmitter(final MethodEmitter newMethod) { - methodEmitters.push(newMethod); - this.method = newMethod; - } - - private void popMethodEmitter(final MethodEmitter oldMethod) { - assert methodEmitters.peek() == oldMethod; - methodEmitters.pop(); - if (!methodEmitters.isEmpty()) { - this.method = methodEmitters.peek(); - } else { - this.method = null; - } - } - - private void push(final CompileUnit newUnit) { - compileUnits.push(newUnit); - this.unit = newUnit; - } - - private void pop(final CompileUnit oldUnit) { - assert compileUnits.peek() == oldUnit; - compileUnits.pop(); - if (!compileUnits.isEmpty()) { - this.unit = compileUnits.peek(); - } else { - this.unit = null; - } + return lc.getCurrentFunction().isStrict() ? callSiteFlags | CALLSITE_STRICT : callSiteFlags; } /** @@ -265,7 +217,7 @@ } final String name = symbol.getName(); - final Source source = getLexicalContext().getCurrentFunction().getSource(); + final Source source = lc.getCurrentFunction().getSource(); if (CompilerConstants.__FILE__.name().equals(name)) { return method.load(source.getName()); @@ -291,88 +243,43 @@ } /** - * A lexical context that also tracks if we have any dynamic scopes in the context. Such scopes can have new - * variables introduced into them at run time - a with block or a function directly containing an eval call. - */ - private static class DynamicScopeTrackingLexicalContext extends LexicalContext { - int dynamicScopeCount = 0; - - @Override - public T push(T node) { - if(isDynamicScopeBoundary(node)) { - ++dynamicScopeCount; - } - return super.push(node); - } - - @Override - public T pop(T node) { - final T popped = super.pop(node); - if(isDynamicScopeBoundary(popped)) { - --dynamicScopeCount; - } - return popped; - } - - private boolean isDynamicScopeBoundary(LexicalContextNode node) { - if(node instanceof Block) { - // Block's immediate parent is a with node. Note we aren't testing for a WithNode, as that'd capture - // processing of WithNode.expression too, but it should be unaffected. - return !isEmpty() && peek() instanceof WithNode; - } else if(node instanceof FunctionNode) { - // Function has a direct eval in it (so a top-level "var ..." in the eval code can introduce a new - // variable into the function's scope), and it isn't strict (as evals in strict functions get an - // isolated scope). - return isFunctionDynamicScope((FunctionNode)node); - } - return false; - } - } - - boolean inDynamicScope() { - return ((DynamicScopeTrackingLexicalContext)getLexicalContext()).dynamicScopeCount > 0; - } - - static boolean isFunctionDynamicScope(FunctionNode fn) { - return fn.hasEval() && !fn.isStrict(); - } - - /** * Check if this symbol can be accessed directly with a putfield or getfield or dynamic load * * @param function function to check for fast scope * @return true if fast scope */ private boolean isFastScope(final Symbol symbol) { - if(!symbol.isScope()) { + if (!symbol.isScope()) { return false; } - final LexicalContext lc = getLexicalContext(); - if(!inDynamicScope()) { + + if (!lc.inDynamicScope()) { // If there's no with or eval in context, and the symbol is marked as scoped, it is fast scoped. Such a // symbol must either be global, or its defining block must need scope. assert symbol.isGlobal() || lc.getDefiningBlock(symbol).needsScope() : symbol.getName(); return true; } - if(symbol.isGlobal()) { + + if (symbol.isGlobal()) { // Shortcut: if there's a with or eval in context, globals can't be fast scoped return false; } + // Otherwise, check if there's a dynamic scope between use of the symbol and its definition final String name = symbol.getName(); boolean previousWasBlock = false; for (final Iterator it = lc.getAllNodes(); it.hasNext();) { final LexicalContextNode node = it.next(); - if(node instanceof Block) { + if (node instanceof Block) { // If this block defines the symbol, then we can fast scope the symbol. final Block block = (Block)node; - if(block.getExistingSymbol(name) == symbol) { + if (block.getExistingSymbol(name) == symbol) { assert block.needsScope(); return true; } previousWasBlock = true; } else { - if((node instanceof WithNode && previousWasBlock) || (node instanceof FunctionNode && isFunctionDynamicScope((FunctionNode)node))) { + if ((node instanceof WithNode && previousWasBlock) || (node instanceof FunctionNode && CodeGeneratorLexicalContext.isFunctionDynamicScope((FunctionNode)node))) { // If we hit a scope that can have symbols introduced into it at run time before finding the defining // block, the symbol can't be fast scoped. A WithNode only counts if we've immediately seen a block // before - its block. Otherwise, we are currently processing the WithNode's expression, and that's @@ -387,16 +294,14 @@ } private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) { - method.load(isFastScope(symbol) ? getScopeProtoDepth(getLexicalContext().getCurrentBlock(), symbol) : -1); - final SharedScopeCall scopeCall = getScopeGet(valueType, symbol, flags | CALLSITE_FAST_SCOPE); - scopeCall.generateInvoke(method); - return method; + method.load(isFastScope(symbol) ? getScopeProtoDepth(lc.getCurrentBlock(), symbol) : -1); + final SharedScopeCall scopeCall = lc.getScopeGet(unit, valueType, symbol, flags | CALLSITE_FAST_SCOPE); + return scopeCall.generateInvoke(method); } private MethodEmitter loadFastScopeVar(final Type valueType, final Symbol symbol, final int flags, final boolean isMethod) { loadFastScopeProto(symbol, false); - method.dynamicGet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE, isMethod); - return method; + return method.dynamicGet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE, isMethod); } private MethodEmitter storeFastScopeVar(final Type valueType, final Symbol symbol, final int flags) { @@ -408,7 +313,7 @@ private int getScopeProtoDepth(final Block startingBlock, final Symbol symbol) { int depth = 0; final String name = symbol.getName(); - for(final Iterator blocks = getLexicalContext().getBlocks(startingBlock); blocks.hasNext();) { + for(final Iterator blocks = lc.getBlocks(startingBlock); blocks.hasNext();) { final Block currentBlock = blocks.next(); if (currentBlock.getExistingSymbol(name) == symbol) { return depth; @@ -421,7 +326,7 @@ } private void loadFastScopeProto(final Symbol symbol, final boolean swap) { - final int depth = getScopeProtoDepth(getLexicalContext().getCurrentBlock(), symbol); + final int depth = getScopeProtoDepth(lc.getCurrentBlock(), symbol); assert depth != -1; if (depth > 0) { if (swap) { @@ -464,7 +369,7 @@ */ final CodeGenerator codegen = this; - node.accept(new NodeVisitor() { + node.accept(new NodeVisitor(new LexicalContext()) { @Override public boolean enterIdentNode(final IdentNode identNode) { loadIdent(identNode); @@ -538,7 +443,7 @@ final boolean isInternal = symbol.isParam() || symbol.isInternal() || symbol.isThis() || !symbol.canBeUndefined(); if (symbol.hasSlot() && !isInternal) { - assert symbol.getSymbolType().isNumber() || symbol.getSymbolType().isObject() : "no potentially undefined narrower local vars than doubles are allowed: " + symbol + " in " + getLexicalContext().getCurrentFunction(); + assert symbol.getSymbolType().isNumber() || symbol.getSymbolType().isObject() : "no potentially undefined narrower local vars than doubles are allowed: " + symbol + " in " + lc.getCurrentFunction(); if (symbol.getSymbolType().isNumber()) { numbers.add(symbol); } else if (symbol.getSymbolType().isObject()) { @@ -595,7 +500,6 @@ if (block.needsScope() && !block.isTerminal()) { popBlockScope(block); } - --nextFreeSlotsSize; return block; } @@ -624,11 +528,11 @@ public boolean enterBreakNode(final BreakNode breakNode) { lineNumber(breakNode); - final BreakableNode breakFrom = getLexicalContext().getBreakable(breakNode.getLabel()); - for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(breakFrom); i++) { + final BreakableNode breakFrom = lc.getBreakable(breakNode.getLabel()); + for (int i = 0; i < lc.getScopeNestingLevelTo(breakFrom); i++) { closeWith(); } - method.splitAwareGoto(getLexicalContext(), breakFrom.getBreakLabel()); + method.splitAwareGoto(lc, breakFrom.getBreakLabel()); return false; } @@ -672,11 +576,12 @@ final List args = callNode.getArgs(); final Node function = callNode.getFunction(); - final Block currentBlock = getLexicalContext().getCurrentBlock(); - - function.accept(new NodeVisitor() { - - private void sharedScopeCall(final IdentNode identNode, final int flags) { + final Block currentBlock = lc.getCurrentBlock(); + final CodeGeneratorLexicalContext codegenLexicalContext = lc; + + function.accept(new NodeVisitor(new LexicalContext()) { + + private MethodEmitter sharedScopeCall(final IdentNode identNode, final int flags) { final Symbol symbol = identNode.getSymbol(); int scopeCallFlags = flags; method.loadCompilerConstant(SCOPE); @@ -688,8 +593,8 @@ } loadArgs(args); final Type[] paramTypes = method.getTypesFromStack(args.size()); - final SharedScopeCall scopeCall = getScopeCall(symbol, identNode.getType(), callNode.getType(), paramTypes, scopeCallFlags); - scopeCall.generateInvoke(method); + final SharedScopeCall scopeCall = codegenLexicalContext.getScopeCall(unit, symbol, identNode.getType(), callNode.getType(), paramTypes, scopeCallFlags); + return scopeCall.generateInvoke(method); } private void scopeCall(final IdentNode node, final int flags) { @@ -756,7 +661,7 @@ evalCall(node, flags); } else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD || (!isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD) - || CodeGenerator.this.inDynamicScope()) { + || CodeGenerator.this.lc.inDynamicScope()) { scopeCall(node, flags); } else { sharedScopeCall(node, flags); @@ -845,11 +750,11 @@ public boolean enterContinueNode(final ContinueNode continueNode) { lineNumber(continueNode); - final LoopNode continueTo = getLexicalContext().getContinueTo(continueNode.getLabel()); - for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(continueTo); i++) { + final LoopNode continueTo = lc.getContinueTo(continueNode.getLabel()); + for (int i = 0; i < lc.getScopeNestingLevelTo(continueTo); i++) { closeWith(); } - method.splitAwareGoto(getLexicalContext(), continueTo.getContinueLabel()); + method.splitAwareGoto(lc, continueTo.getContinueLabel()); return false; } @@ -875,90 +780,89 @@ public boolean enterForNode(final ForNode forNode) { lineNumber(forNode); - final Node test = forNode.getTest(); - final Block body = forNode.getBody(); - final Node modify = forNode.getModify(); - - final Label breakLabel = forNode.getBreakLabel(); - final Label continueLabel = forNode.getContinueLabel(); - final Label loopLabel = new Label("loop"); - - Node init = forNode.getInit(); - if (forNode.isForIn()) { - final Symbol iter = forNode.getIterator(); - - // We have to evaluate the optional initializer expression - // of the iterator variable of the for-in statement. - if (init instanceof VarNode) { - init.accept(this); - init = ((VarNode)init).getName(); - } - - load(modify); - assert modify.getType().isObject(); - method.invoke(forNode.isForEach() ? ScriptRuntime.TO_VALUE_ITERATOR : ScriptRuntime.TO_PROPERTY_ITERATOR); - method.store(iter); - method._goto(continueLabel); - method.label(loopLabel); - - new Store(init) { - @Override - protected void storeNonDiscard() { - return; - } - @Override - protected void evaluate() { - method.load(iter); - method.invoke(interfaceCallNoLookup(Iterator.class, "next", Object.class)); - } - }.store(); - - body.accept(this); - - method.label(continueLabel); - method.load(iter); - method.invoke(interfaceCallNoLookup(Iterator.class, "hasNext", boolean.class)); - method.ifne(loopLabel); - method.label(breakLabel); + enterForIn(forNode); } else { - if (init != null) { - init.accept(this); - } - - final Label testLabel = new Label("test"); - - method._goto(testLabel); - method.label(loopLabel); - body.accept(this); - method.label(continueLabel); - - if (!body.isTerminal() && modify != null) { - load(modify); - } - - method.label(testLabel); - if (test != null) { - new BranchOptimizer(this, method).execute(test, loopLabel, true); - } else { - method._goto(loopLabel); - } - - method.label(breakLabel); + enterFor(forNode); } return false; } - private static int assignSlots(final Block block, final int firstSlot) { - int nextSlot = firstSlot; - for (final Symbol symbol : block.getSymbols()) { - if (symbol.hasSlot()) { - symbol.setSlot(nextSlot); - nextSlot += symbol.slotCount(); + private void enterFor(final ForNode forNode) { + final Node init = forNode.getInit(); + final Node test = forNode.getTest(); + final Block body = forNode.getBody(); + final Node modify = forNode.getModify(); + + if (init != null) { + init.accept(this); + } + + final Label loopLabel = new Label("loop"); + final Label testLabel = new Label("test"); + + method._goto(testLabel); + method.label(loopLabel); + body.accept(this); + method.label(forNode.getContinueLabel()); + + if (!body.isTerminal() && modify != null) { + load(modify); + } + + method.label(testLabel); + if (test != null) { + new BranchOptimizer(this, method).execute(test, loopLabel, true); + } else { + method._goto(loopLabel); + } + + method.label(forNode.getBreakLabel()); + } + + private void enterForIn(final ForNode forNode) { + final Block body = forNode.getBody(); + final Node modify = forNode.getModify(); + + final Symbol iter = forNode.getIterator(); + final Label loopLabel = new Label("loop"); + + Node init = forNode.getInit(); + + // We have to evaluate the optional initializer expression + // of the iterator variable of the for-in statement. + if (init instanceof VarNode) { + init.accept(this); + init = ((VarNode)init).getName(); + } + + load(modify); + assert modify.getType().isObject(); + method.invoke(forNode.isForEach() ? ScriptRuntime.TO_VALUE_ITERATOR : ScriptRuntime.TO_PROPERTY_ITERATOR); + method.store(iter); + method._goto(forNode.getContinueLabel()); + method.label(loopLabel); + + new Store(init) { + @Override + protected void storeNonDiscard() { + return; } - } - return nextSlot; + @Override + protected void evaluate() { + method.load(iter); + method.invoke(interfaceCallNoLookup(Iterator.class, "next", Object.class)); + } + }.store(); + + body.accept(this); + + method.label(forNode.getContinueLabel()); + method.load(iter); + method.invoke(interfaceCallNoLookup(Iterator.class, "hasNext", boolean.class)); + method.ifne(loopLabel); + method.label(forNode.getBreakLabel()); } /** @@ -967,24 +871,11 @@ * @param block block with local vars. */ private void initLocals(final Block block) { - final boolean isFunctionBody = getLexicalContext().isFunctionBody(); - - final int nextFreeSlot; - if (isFunctionBody) { - // On entry to function, start with slot 0 - nextFreeSlot = 0; - } else { - // Otherwise, continue from previous block's first free slot - nextFreeSlot = nextFreeSlots[nextFreeSlotsSize - 1]; - } - if(nextFreeSlotsSize == nextFreeSlots.length) { - final int[] newNextFreeSlots = new int[nextFreeSlotsSize * 2]; - System.arraycopy(nextFreeSlots, 0, newNextFreeSlots, 0, nextFreeSlotsSize); - nextFreeSlots = newNextFreeSlots; - } - nextFreeSlots[nextFreeSlotsSize++] = assignSlots(block, nextFreeSlot); - - final FunctionNode function = getLexicalContext().getCurrentFunction(); + lc.nextFreeSlot(block); + + final boolean isFunctionBody = lc.isFunctionBody(); + + final FunctionNode function = lc.getCurrentFunction(); if (isFunctionBody) { /* Fix the predefined slots so they have numbers >= 0, like varargs. */ if (function.needsParentScope()) { @@ -1023,7 +914,7 @@ } if (symbol.isVar()) { - if(varsInScope || symbol.isScope()) { + if (varsInScope || symbol.isScope()) { nameList.add(symbol.getName()); newSymbols.add(symbol); values.add(null); @@ -1062,7 +953,7 @@ @Override protected void loadScope(MethodEmitter m) { - if(function.needsParentScope()) { + if (function.needsParentScope()) { m.loadCompilerConstant(SCOPE); } else { m.loadNull(); @@ -1096,7 +987,7 @@ private void initArguments(final FunctionNode function) { method.loadCompilerConstant(VARARGS); - if(function.needsCallee()) { + if (function.needsCallee()) { method.loadCompilerConstant(CALLEE); } else { // If function is strict mode, "arguments.callee" is not populated, so we don't necessarily need the @@ -1126,10 +1017,10 @@ LOG.info("=== BEGIN ", functionNode.getName()); assert functionNode.getCompileUnit() != null : "no compile unit for " + functionNode.getName() + " " + Debug.id(functionNode); - push(functionNode.getCompileUnit()); - assert !compileUnits.isEmpty(); - - pushMethodEmitter(unit.getClassEmitter().method(functionNode)); + unit = lc.pushCompileUnit(functionNode.getCompileUnit()); + assert lc.hasCompileUnits(); + + method = lc.pushMethodEmitter(unit.getClassEmitter().method(functionNode)); // Mark end for variable tables. method.begin(); @@ -1140,11 +1031,11 @@ public Node leaveFunctionNode(final FunctionNode functionNode) { try { method.end(); // wrap up this method - pop(functionNode.getCompileUnit()); - popMethodEmitter(method); + unit = lc.popCompileUnit(functionNode.getCompileUnit()); + method = lc.popMethodEmitter(method); LOG.info("=== END ", functionNode.getName()); - final FunctionNode newFunctionNode = functionNode.setState(getLexicalContext(), CompilationState.EMITTED); + final FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.EMITTED); newFunctionObject(newFunctionNode, functionNode); return newFunctionNode; @@ -1238,16 +1129,16 @@ final MethodEmitter savedMethod = method; for (final ArrayUnit arrayUnit : units) { - push(arrayUnit.getCompileUnit()); + unit = lc.pushCompileUnit(arrayUnit.getCompileUnit()); final String className = unit.getUnitClassName(); - final String name = getLexicalContext().getCurrentFunction().uniqueName(SPLIT_PREFIX.symbolName()); + final String name = lc.getCurrentFunction().uniqueName(SPLIT_PREFIX.symbolName()); final String signature = methodDescriptor(type, Object.class, ScriptFunction.class, ScriptObject.class, type); final MethodEmitter me = unit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature); - pushMethodEmitter(me); - - method.setFunctionNode(getLexicalContext().getCurrentFunction()); + method = lc.pushMethodEmitter(me); + + method.setFunctionNode(lc.getCurrentFunction()); method.begin(); fixScopeSlot(); @@ -1260,7 +1151,7 @@ method._return(); method.end(); - popMethodEmitter(me); + method = lc.popMethodEmitter(me); assert method == savedMethod; method.loadCompilerConstant(THIS); @@ -1271,7 +1162,7 @@ method.swap(); method.invokestatic(className, name, signature); - pop(unit); + unit = lc.popCompileUnit(unit); } return method; @@ -1407,7 +1298,7 @@ return loadRegexToken(regexToken); } // emit field - final String regexName = getLexicalContext().getCurrentFunction().uniqueName(REGEX_PREFIX.symbolName()); + final String regexName = lc.getCurrentFunction().uniqueName(REGEX_PREFIX.symbolName()); final ClassEmitter classEmitter = unit.getClassEmitter(); classEmitter.field(EnumSet.of(PRIVATE, STATIC), regexName, Object.class); @@ -1545,7 +1436,7 @@ method.registerReturn(); - final Type returnType = getLexicalContext().getCurrentFunction().getReturnType(); + final Type returnType = lc.getCurrentFunction().getReturnType(); final Node expression = returnNode.getExpression(); if (expression != null) { @@ -1756,7 +1647,7 @@ final CompileUnit splitCompileUnit = splitNode.getCompileUnit(); - final FunctionNode fn = getLexicalContext().getCurrentFunction(); + final FunctionNode fn = lc.getCurrentFunction(); final String className = splitCompileUnit.getUnitClassName(); final String name = splitNode.getName(); @@ -1767,7 +1658,7 @@ new Class[] {ScriptFunction.class, Object.class, ScriptObject.class}; final MethodEmitter caller = method; - push(splitCompileUnit); + unit = lc.pushCompileUnit(splitCompileUnit); final Call splitCall = staticCallNoLookup( className, @@ -1781,8 +1672,7 @@ rtype, ptypes); - pushMethodEmitter(splitEmitter); - + method = lc.pushMethodEmitter(splitEmitter); method.setFunctionNode(fn); if (fn.needsCallee()) { @@ -1809,7 +1699,7 @@ } private void fixScopeSlot() { - if (getLexicalContext().getCurrentFunction().compilerConstant(SCOPE).getSlot() != SCOPE.slot()) { + if (lc.getCurrentFunction().compilerConstant(SCOPE).getSlot() != SCOPE.slot()) { // TODO hack to move the scope to the expected slot (that's needed because split methods reuse the same slots as the root method) method.load(Type.typeFor(ScriptObject.class), SCOPE.slot()); method.storeCompilerConstant(SCOPE); @@ -1826,15 +1716,15 @@ // Wrap up this method. method.loadCompilerConstant(RETURN); - method._return(getLexicalContext().getCurrentFunction().getReturnType()); + method._return(lc.getCurrentFunction().getReturnType()); method.end(); - pop(splitNode.getCompileUnit()); - popMethodEmitter(method); + unit = lc.popCompileUnit(splitNode.getCompileUnit()); + method = lc.popMethodEmitter(method); } catch (final Throwable t) { Context.printStackTrace(t); - final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + getLexicalContext().getCurrentFunction().getSource().getName()); + final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + lc.getCurrentFunction().getSource().getName()); e.initCause(t); throw e; } @@ -1862,7 +1752,7 @@ //has to be zero caller.label(new Label("split_return")); method.loadCompilerConstant(RETURN); - caller._return(getLexicalContext().getCurrentFunction().getReturnType()); + caller._return(lc.getCurrentFunction().getReturnType()); caller.label(breakLabel); } else { assert !targets.isEmpty(); @@ -1879,14 +1769,14 @@ caller.label(labels[i - low]); if (i == 0) { caller.loadCompilerConstant(RETURN); - caller._return(getLexicalContext().getCurrentFunction().getReturnType()); + caller._return(lc.getCurrentFunction().getReturnType()); } else { // Clear split state. caller.loadCompilerConstant(SCOPE); caller.checkcast(Scope.class); caller.load(-1); caller.invoke(Scope.SET_SPLIT_STATE); - caller.splitAwareGoto(getLexicalContext(), targets.get(i - 1)); + caller.splitAwareGoto(lc, targets.get(i - 1)); } } caller.label(breakLabel); @@ -2028,9 +1918,16 @@ public boolean enterThrowNode(final ThrowNode throwNode) { lineNumber(throwNode); + if (throwNode.isSyntheticRethrow()) { + //do not wrap whatever this is in an ecma exception, just rethrow it + load(throwNode.getExpression()); + method.athrow(); + return false; + } + method._new(ECMAException.class).dup(); - final Source source = getLexicalContext().getCurrentFunction().getSource(); + final Source source = lc.getCurrentFunction().getSource(); final Node expression = throwNode.getExpression(); final int position = throwNode.position(); @@ -2081,7 +1978,7 @@ //TODO this is very ugly - try not to call enter/leave methods directly //better to use the implicit lexical context scoping given by the visitor's //accept method. - getLexicalContext().push(catchBlock); + lc.push(catchBlock); enterBlock(catchBlock); final CatchNode catchNode = (CatchNode)catchBlocks.get(i).getStatements().get(0); @@ -2094,15 +1991,19 @@ protected void storeNonDiscard() { return; } + @Override protected void evaluate() { + if (catchNode.isSyntheticRethrow()) { + method.load(symbol); + return; + } /* * If caught object is an instance of ECMAException, then * bind obj.thrown to the script catch var. Or else bind the * caught object itself to the script catch var. */ final Label notEcmaException = new Label("no_ecma_exception"); - method.load(symbol).dup()._instanceof(ECMAException.class).ifeq(notEcmaException); method.checkcast(ECMAException.class); //TODO is this necessary? method.getField(ECMAException.THROWN); @@ -2137,7 +2038,7 @@ } leaveBlock(catchBlock); - getLexicalContext().pop(catchBlock); + lc.pop(catchBlock); } method.label(skip); @@ -2234,7 +2135,7 @@ final boolean hasScope = method.hasScope(); final Label tryLabel; - if(hasScope) { + if (hasScope) { tryLabel = new Label("with_try"); method.label(tryLabel); method.loadCompilerConstant(SCOPE); @@ -2245,7 +2146,7 @@ load(expression); assert expression.getType().isObject() : "with expression needs to be object: " + expression; - if(hasScope) { + if (hasScope) { // Construct a WithObject if we have a scope method.invoke(ScriptRuntime.OPEN_WITH); method.storeCompilerConstant(SCOPE); @@ -2285,7 +2186,7 @@ @Override public boolean enterADD(final UnaryNode unaryNode) { load(unaryNode.rhs()); - assert unaryNode.rhs().getType().isNumber(); + assert unaryNode.rhs().getType().isNumber() : unaryNode.rhs().getType() + " "+ unaryNode.getSymbol(); method.store(unaryNode.getSymbol()); return false; @@ -2320,7 +2221,7 @@ } method.convert(Type.OBJECT); } else if (value instanceof Boolean) { - method.getField(staticField(Boolean.class, value.toString().toUpperCase(), Boolean.class)); + method.getField(staticField(Boolean.class, value.toString().toUpperCase(Locale.ENGLISH), Boolean.class)); } else { load(rhs); method.convert(unaryNode.getType()); @@ -2387,13 +2288,13 @@ public boolean enterDISCARD(final UnaryNode unaryNode) { final Node rhs = unaryNode.rhs(); - discard.push(rhs); + lc.pushDiscard(rhs); load(rhs); - if (discard.peek() == rhs) { + if (lc.getCurrentDiscard() == rhs) { assert !rhs.isAssignment(); method.pop(); - discard.pop(); + lc.popDiscard(); } return false; @@ -2445,7 +2346,7 @@ assert lhs.getType().equals(rhs.getType()) && lhs.getType().equals(type) : lhs.getType() + " != " + rhs.getType() + " != " + type + " " + new ASTWriter(lhs) + " " + new ASTWriter(rhs); load(lhs); load(rhs); - method.add(); + method.add(); //if the symbol is optimistic, it always needs to be written, not on the stack? method.store(symbol); return null; } @@ -2989,53 +2890,12 @@ * Generate all shared scope calls generated during codegen. */ protected void generateScopeCalls() { - for (final SharedScopeCall scopeAccess : scopeCalls.values()) { + for (final SharedScopeCall scopeAccess : lc.getScopeCalls()) { scopeAccess.generateScopeCall(); } } /** - * Get a shared static method representing a dynamic scope callsite. - * - * @param symbol the symbol - * @param valueType the value type of the symbol - * @param returnType the return type - * @param paramTypes the parameter types - * @param flags the callsite flags - * @return an object representing a shared scope call - */ - private SharedScopeCall getScopeCall(final Symbol symbol, final Type valueType, final Type returnType, - final Type[] paramTypes, final int flags) { - - final SharedScopeCall scopeCall = new SharedScopeCall(symbol, valueType, returnType, paramTypes, flags); - if (scopeCalls.containsKey(scopeCall)) { - return scopeCalls.get(scopeCall); - } - scopeCall.setClassAndName(unit, getLexicalContext().getCurrentFunction().uniqueName("scopeCall")); - scopeCalls.put(scopeCall, scopeCall); - return scopeCall; - } - - /** - * Get a shared static method representing a dynamic scope get access. - * - * @param type the type of the variable - * @param symbol the symbol - * @param flags the callsite flags - * @return an object representing a shared scope call - */ - private SharedScopeCall getScopeGet(final Type type, final Symbol symbol, final int flags) { - - final SharedScopeCall scopeCall = new SharedScopeCall(symbol, type, type, null, flags); - if (scopeCalls.containsKey(scopeCall)) { - return scopeCalls.get(scopeCall); - } - scopeCall.setClassAndName(unit, getLexicalContext().getCurrentFunction().uniqueName("scopeCall")); - scopeCalls.put(scopeCall, scopeCall); - return scopeCall; - } - - /** * Debug code used to print symbols * * @param block the block we are in @@ -3129,14 +2989,14 @@ private void prologue() { final Symbol targetSymbol = target.getSymbol(); - final Symbol scopeSymbol = getLexicalContext().getCurrentFunction().compilerConstant(SCOPE); + final Symbol scopeSymbol = lc.getCurrentFunction().compilerConstant(SCOPE); /** * This loads the parts of the target, e.g base and index. they are kept * on the stack throughout the store and used at the end to execute it */ - target.accept(new NodeVisitor() { + target.accept(new NodeVisitor(new LexicalContext()) { @Override public boolean enterIdentNode(final IdentNode node) { if (targetSymbol.isScope()) { @@ -3203,22 +3063,21 @@ * @return the quick symbol */ private Symbol quickSymbol(final Type type, final String prefix) { - final String name = getLexicalContext().getCurrentFunction().uniqueName(prefix); + final String name = lc.getCurrentFunction().uniqueName(prefix); final Symbol symbol = new Symbol(name, IS_TEMP | IS_INTERNAL); symbol.setType(type); - final int quickSlot = nextFreeSlots[nextFreeSlotsSize - 1]; - nextFreeSlots[nextFreeSlotsSize - 1] = quickSlot + symbol.slotCount(); - symbol.setSlot(quickSlot); + + symbol.setSlot(lc.quickSlot(symbol)); return symbol; } // store the result that "lives on" after the op, e.g. "i" in i++ postfix. protected void storeNonDiscard() { - if (discard.peek() == assignNode) { + if (lc.getCurrentDiscard() == assignNode) { assert assignNode.isAssignment(); - discard.pop(); + lc.popDiscard(); return; } @@ -3246,7 +3105,7 @@ */ method.convert(target.getType()); - target.accept(new NodeVisitor() { + target.accept(new NodeVisitor(new LexicalContext()) { @Override protected boolean enterDefault(Node node) { throw new AssertionError("Unexpected node " + node + " in store epilogue"); @@ -3308,7 +3167,6 @@ } private void newFunctionObject(final FunctionNode functionNode, final FunctionNode originalFunctionNode) { - final LexicalContext lc = getLexicalContext(); assert lc.peek() == functionNode; // We don't emit a ScriptFunction on stack for: // 1. the outermost compiled function (as there's no code being generated in its outer context that'd need it diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,235 @@ +/* + * 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.codegen; + +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.Map; + +import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.Block; +import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.LexicalContext; +import jdk.nashorn.internal.ir.LexicalContextNode; +import jdk.nashorn.internal.ir.Node; +import jdk.nashorn.internal.ir.Symbol; +import jdk.nashorn.internal.ir.WithNode; + +/** + * A lexical context that also tracks if we have any dynamic scopes in the context. Such scopes can have new + * variables introduced into them at run time - a with block or a function directly containing an eval call. + * Furthermore, this class keeps track of current discard state, which the current method emitter being used is, + * the current compile unit, and local variable indexes + */ +final class CodeGeneratorLexicalContext extends LexicalContext { + private int dynamicScopeCount; + + /** Map of shared scope call sites */ + private final Map scopeCalls = new HashMap<>(); + + /** Compile unit stack - every time we start a sub method (e.g. a split) we push one */ + private final Deque compileUnits = new ArrayDeque<>(); + + /** Method emitter stack - every time we start a sub method (e.g. a split) we push one */ + private final Deque methodEmitters = new ArrayDeque<>(); + + /** The discard stack - whenever we enter a discard node we keep track of its return value status - + * i.e. should we keep it or throw it away */ + private final Deque discard = new ArrayDeque<>(); + + /** A stack tracking the next free local variable slot in the blocks. There's one entry for every block + * currently on the lexical context stack. */ + private int[] nextFreeSlots = new int[16]; + + /** size of next free slot vector */ + private int nextFreeSlotsSize; + + @Override + public T push(final T node) { + if (isDynamicScopeBoundary(node)) { + ++dynamicScopeCount; + } + return super.push(node); + } + + @Override + public T pop(final T node) { + final T popped = super.pop(node); + if (isDynamicScopeBoundary(popped)) { + --dynamicScopeCount; + } + if (node instanceof Block) { + --nextFreeSlotsSize; + } + return popped; + } + + private boolean isDynamicScopeBoundary(final LexicalContextNode node) { + if (node instanceof Block) { + // Block's immediate parent is a with node. Note we aren't testing for a WithNode, as that'd capture + // processing of WithNode.expression too, but it should be unaffected. + return !isEmpty() && peek() instanceof WithNode; + } else if (node instanceof FunctionNode) { + // Function has a direct eval in it (so a top-level "var ..." in the eval code can introduce a new + // variable into the function's scope), and it isn't strict (as evals in strict functions get an + // isolated scope). + return isFunctionDynamicScope((FunctionNode)node); + } + return false; + } + + boolean inDynamicScope() { + return dynamicScopeCount > 0; + } + + static boolean isFunctionDynamicScope(FunctionNode fn) { + return fn.hasEval() && !fn.isStrict(); + } + + MethodEmitter pushMethodEmitter(final MethodEmitter newMethod) { + methodEmitters.push(newMethod); + return newMethod; + } + + MethodEmitter popMethodEmitter(final MethodEmitter oldMethod) { + assert methodEmitters.peek() == oldMethod; + methodEmitters.pop(); + return methodEmitters.isEmpty() ? null : methodEmitters.peek(); + } + + CompileUnit pushCompileUnit(final CompileUnit newUnit) { + compileUnits.push(newUnit); + return newUnit; + } + + CompileUnit popCompileUnit(final CompileUnit oldUnit) { + assert compileUnits.peek() == oldUnit; + compileUnits.pop(); + return compileUnits.isEmpty() ? null : compileUnits.peek(); + } + + boolean hasCompileUnits() { + return !compileUnits.isEmpty(); + } + + Collection getScopeCalls() { + return Collections.unmodifiableCollection(scopeCalls.values()); + } + + /** + * Get a shared static method representing a dynamic scope callsite. + * + * @param unit current compile unit + * @param symbol the symbol + * @param valueType the value type of the symbol + * @param returnType the return type + * @param paramTypes the parameter types + * @param flags the callsite flags + * @return an object representing a shared scope call + */ + SharedScopeCall getScopeCall(final CompileUnit unit, final Symbol symbol, final Type valueType, final Type returnType, final Type[] paramTypes, final int flags) { + final SharedScopeCall scopeCall = new SharedScopeCall(symbol, valueType, returnType, paramTypes, flags); + if (scopeCalls.containsKey(scopeCall)) { + return scopeCalls.get(scopeCall); + } + scopeCall.setClassAndName(unit, getCurrentFunction().uniqueName("scopeCall")); + scopeCalls.put(scopeCall, scopeCall); + return scopeCall; + } + + /** + * Get a shared static method representing a dynamic scope get access. + * + * @param unit current compile unit + * @param type the type of the variable + * @param symbol the symbol + * @param flags the callsite flags + * @return an object representing a shared scope call + */ + SharedScopeCall getScopeGet(final CompileUnit unit, final Type type, final Symbol symbol, final int flags) { + final SharedScopeCall scopeCall = new SharedScopeCall(symbol, type, type, null, flags); + if (scopeCalls.containsKey(scopeCall)) { + return scopeCalls.get(scopeCall); + } + scopeCall.setClassAndName(unit, getCurrentFunction().uniqueName("scopeCall")); + scopeCalls.put(scopeCall, scopeCall); + return scopeCall; + } + + + void nextFreeSlot(final Block block) { + final boolean isFunctionBody = isFunctionBody(); + + final int nextFreeSlot; + if (isFunctionBody) { + // On entry to function, start with slot 0 + nextFreeSlot = 0; + } else { + // Otherwise, continue from previous block's first free slot + nextFreeSlot = nextFreeSlots[nextFreeSlotsSize - 1]; + } + if (nextFreeSlotsSize == nextFreeSlots.length) { + final int[] newNextFreeSlots = new int[nextFreeSlotsSize * 2]; + System.arraycopy(nextFreeSlots, 0, newNextFreeSlots, 0, nextFreeSlotsSize); + nextFreeSlots = newNextFreeSlots; + } + nextFreeSlots[nextFreeSlotsSize++] = assignSlots(block, nextFreeSlot); + } + + private static int assignSlots(final Block block, final int firstSlot) { + int nextSlot = firstSlot; + for (final Symbol symbol : block.getSymbols()) { + if (symbol.hasSlot()) { + symbol.setSlot(nextSlot); + nextSlot += symbol.slotCount(); + } + } + return nextSlot; + } + + void pushDiscard(final Node node) { + discard.push(node); + } + + Node popDiscard() { + return discard.pop(); + } + + Node getCurrentDiscard() { + return discard.peek(); + } + + int quickSlot(final Symbol symbol) { + final int quickSlot = nextFreeSlots[nextFreeSlotsSize - 1]; + nextFreeSlots[nextFreeSlotsSize - 1] = quickSlot + symbol.slotCount(); + return quickSlot; + } + +} + diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java --- a/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java Wed Jul 05 18:57:52 2017 +0200 @@ -11,20 +11,27 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; import java.util.EnumSet; import java.util.HashSet; +import java.util.List; import java.util.Set; + +import jdk.nashorn.internal.codegen.types.Range; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.Block; import jdk.nashorn.internal.ir.CallNode; import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.LexicalContext; +import jdk.nashorn.internal.ir.ReturnNode; +import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; -import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.TemporarySymbols; import jdk.nashorn.internal.ir.debug.ASTWriter; import jdk.nashorn.internal.ir.debug.PrintVisitor; -import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.runtime.ECMAErrors; import jdk.nashorn.internal.runtime.ScriptEnvironment; @@ -66,7 +73,7 @@ FunctionNode newFunctionNode = outermostFunctionNode; - newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeVisitor() { + newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeVisitor(new LexicalContext()) { // self references are done with invokestatic and thus cannot // have trampolines - never lazy @Override @@ -99,10 +106,9 @@ lazy.remove(node); } - newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeOperatorVisitor() { + newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeVisitor(new LexicalContext()) { @Override public Node leaveFunctionNode(final FunctionNode functionNode) { - final LexicalContext lc = getLexicalContext(); if (lazy.contains(functionNode)) { Compiler.LOG.fine( "Marking ", @@ -174,7 +180,7 @@ FunctionNode transform(final Compiler compiler, final FunctionNode fn) { final TemporarySymbols ts = compiler.getTemporarySymbols(); final FunctionNode newFunctionNode = (FunctionNode)enterAttr(fn, ts).accept(new Attr(ts)); - if(compiler.getEnv()._print_mem_usage) { + if (compiler.getEnv()._print_mem_usage) { Compiler.LOG.info("Attr temporary symbol count: " + ts.getTotalSymbolCount()); } return newFunctionNode; @@ -186,12 +192,11 @@ * @param functionNode node where to start iterating */ private FunctionNode enterAttr(final FunctionNode functionNode, final TemporarySymbols ts) { - return (FunctionNode)functionNode.accept(new NodeVisitor() { + return (FunctionNode)functionNode.accept(new NodeVisitor(new LexicalContext()) { @Override public Node leaveFunctionNode(final FunctionNode node) { - final LexicalContext lc = getLexicalContext(); if (node.isLazy()) { - FunctionNode newNode = node.setReturnType(getLexicalContext(), Type.OBJECT); + FunctionNode newNode = node.setReturnType(lc, Type.OBJECT); return ts.ensureSymbol(lc, Type.OBJECT, newNode); } //node may have a reference here that needs to be nulled if it was referred to by @@ -208,6 +213,89 @@ }, /* + * Range analysis + * Conservatively prove that certain variables can be narrower than + * the most generic number type + */ + RANGE_ANALYSIS_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR)) { + @Override + FunctionNode transform(final Compiler compiler, final FunctionNode fn) { + if (!compiler.getEnv()._range_analysis) { + return fn; + } + + FunctionNode newFunctionNode = (FunctionNode)fn.accept(new RangeAnalyzer()); + final List returns = new ArrayList<>(); + + newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeVisitor(new LexicalContext()) { + private final Deque> returnStack = new ArrayDeque<>(); + + @Override + public boolean enterFunctionNode(final FunctionNode functionNode) { + returnStack.push(new ArrayList()); + return true; + } + + @Override + public Node leaveFunctionNode(final FunctionNode functionNode) { + Type returnType = Type.UNKNOWN; + for (final ReturnNode ret : returnStack.pop()) { + if (ret.getExpression() == null) { + returnType = Type.OBJECT; + break; + } + returnType = Type.widest(returnType, ret.getExpression().getType()); + } + return functionNode.setReturnType(lc, returnType); + } + + @Override + public Node leaveReturnNode(final ReturnNode returnNode) { + final ReturnNode result = (ReturnNode)leaveDefault(returnNode); + returns.add(result); + return result; + } + + @Override + public Node leaveDefault(final Node node) { + final Symbol symbol = node.getSymbol(); + if (symbol != null) { + final Range range = symbol.getRange(); + final Type symbolType = symbol.getSymbolType(); + if (!symbolType.isNumeric()) { + return node; + } + final Type rangeType = range.getType(); + if (!Type.areEquivalent(symbolType, rangeType) && Type.widest(symbolType, rangeType) == symbolType) { //we can narrow range + RangeAnalyzer.LOG.info("[", lc.getCurrentFunction().getName(), "] ", symbol, " can be ", range.getType(), " ", symbol.getRange()); + return node.setSymbol(lc, symbol.setTypeOverrideShared(range.getType(), compiler.getTemporarySymbols())); + } + } + return node; + } + }); + + Type returnType = Type.UNKNOWN; + for (final ReturnNode node : returns) { + if (node.getExpression() != null) { + returnType = Type.widest(returnType, node.getExpression().getType()); + } else { + returnType = Type.OBJECT; + break; + } + } + + return newFunctionNode.setReturnType(null, returnType); + } + + @Override + public String toString() { + return "[Range Analysis]"; + } + }, + + + /* * Splitter Split the AST into several compile units based on a size * heuristic Splitter needs attributed AST for weight calculations (e.g. is * a + b a ScriptRuntime.ADD with call overhead or a dadd with much less). @@ -218,7 +306,6 @@ FunctionNode transform(final Compiler compiler, final FunctionNode fn) { final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName()); -// assert fn.isProgram() ; final FunctionNode newFunctionNode = new Splitter(compiler, fn, outermostCompileUnit).split(fn); assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit; diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/codegen/Compiler.java --- a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java Wed Jul 05 18:57:52 2017 +0200 @@ -99,7 +99,7 @@ private boolean strict; - private CodeInstaller installer; + private final CodeInstaller installer; private final TemporarySymbols temporarySymbols = new TemporarySymbols(); @@ -219,6 +219,7 @@ CompilationPhase.CONSTANT_FOLDING_PHASE, CompilationPhase.LOWERING_PHASE, CompilationPhase.ATTRIBUTION_PHASE, + CompilationPhase.RANGE_ANALYSIS_PHASE, CompilationPhase.SPLITTING_PHASE, CompilationPhase.TYPE_FINALIZATION_PHASE, CompilationPhase.BYTECODE_GENERATION_PHASE); @@ -384,6 +385,8 @@ if (info) { final StringBuilder sb = new StringBuilder(); sb.append("Compile job for '"). + append(newFunctionNode.getSource()). + append(':'). append(newFunctionNode.getName()). append("' finished"); @@ -487,7 +490,7 @@ } if (sb != null) { - LOG.info(sb); + LOG.fine(sb); } return rootClass; diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java --- a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java Wed Jul 05 18:57:52 2017 +0200 @@ -262,7 +262,7 @@ * @return the internal descriptor for this type */ public static String typeDescriptor(final Class clazz) { - return Type.getDescriptor(clazz); + return Type.typeFor(clazz).getDescriptor(); } /** diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java --- a/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Wed Jul 05 18:57:52 2017 +0200 @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; + import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.AccessNode; import jdk.nashorn.internal.ir.Assignment; @@ -84,13 +85,14 @@ * and frame optimizations */ -final class FinalizeTypes extends NodeOperatorVisitor { +final class FinalizeTypes extends NodeOperatorVisitor { private static final DebugLogger LOG = new DebugLogger("finalize"); private final TemporarySymbols temporarySymbols; FinalizeTypes(final TemporarySymbols temporarySymbols) { + super(new LexicalContext()); this.temporarySymbols = temporarySymbols; } @@ -233,7 +235,7 @@ private boolean symbolIsInteger(Node node) { final Symbol symbol = node.getSymbol(); - assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + getLexicalContext().getCurrentFunction().getSource(); + assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + lc.getCurrentFunction().getSource(); return true; } @@ -382,12 +384,10 @@ final Node test = forNode.getTest(); final Node modify = forNode.getModify(); - final LexicalContext lc = getLexicalContext(); - if (forNode.isForIn()) { return forNode.setModify(lc, convert(forNode.getModify(), Type.OBJECT)); // NASHORN-400 } - assert test != null || forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + getLexicalContext().getCurrentFunction(); + assert test != null || forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + lc.getCurrentFunction(); return forNode. setInit(lc, init == null ? null : discard(init)). @@ -419,7 +419,7 @@ @Override public Node leaveFunctionNode(final FunctionNode functionNode) { - return functionNode.setState(getLexicalContext(), CompilationState.FINALIZED); + return functionNode.setState(lc, CompilationState.FINALIZED); } @Override @@ -450,7 +450,7 @@ public Node leaveReturnNode(final ReturnNode returnNode) { final Node expr = returnNode.getExpression(); if (expr != null) { - return returnNode.setExpression(convert(expr, getLexicalContext().getCurrentFunction().getReturnType())); + return returnNode.setExpression(convert(expr, lc.getCurrentFunction().getReturnType())); } return returnNode; } @@ -482,8 +482,8 @@ } return switchNode. - setExpression(getLexicalContext(), convert(expression, Type.OBJECT)). - setCases(getLexicalContext(), newCases); + setExpression(lc, convert(expression, Type.OBJECT)). + setCases(lc, newCases); } @Override @@ -519,14 +519,14 @@ public Node leaveWhileNode(final WhileNode whileNode) { final Node test = whileNode.getTest(); if (test != null) { - return whileNode.setTest(getLexicalContext(), convert(test, Type.BOOLEAN)); + return whileNode.setTest(lc, convert(test, Type.BOOLEAN)); } return whileNode; } @Override public Node leaveWithNode(final WithNode withNode) { - return withNode.setExpression(getLexicalContext(), convert(withNode.getExpression(), Type.OBJECT)); + return withNode.setExpression(lc, convert(withNode.getExpression(), Type.OBJECT)); } private static void updateSymbolsLog(final FunctionNode functionNode, final Symbol symbol, final boolean loseSlot) { @@ -550,7 +550,6 @@ return; // nothing to do } - final LexicalContext lc = getLexicalContext(); final FunctionNode functionNode = lc.getFunction(block); final boolean allVarsInScope = functionNode.allVarsInScope(); final boolean isVarArg = functionNode.isVarArg(); @@ -652,7 +651,7 @@ private static void setCanBePrimitive(final Node node, final Type to) { final HashSet exclude = new HashSet<>(); - node.accept(new NodeVisitor() { + node.accept(new NodeVisitor(new LexicalContext()) { private void setCanBePrimitive(final Symbol symbol) { LOG.info("*** can be primitive symbol ", symbol, " ", Debug.id(symbol)); symbol.setCanBePrimitive(to); @@ -762,7 +761,7 @@ } } LOG.info("Type override for lhs in '", node, "' => ", to); - return ((TypeOverride)node).setType(temporarySymbols, getLexicalContext(), to); + return ((TypeOverride)node).setType(temporarySymbols, lc, to); } /** @@ -785,8 +784,8 @@ private Node convert(final Node node, final Type to) { assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass(); assert node != null : "node is null"; - assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + getLexicalContext().getCurrentFunction(); - assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + getLexicalContext().getCurrentFunction(); + assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + lc.getCurrentFunction(); + assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + lc.getCurrentFunction(); final Type from = node.getType(); @@ -800,7 +799,7 @@ Node resultNode = node; - if (node instanceof LiteralNode && !to.isObject()) { + if (node instanceof LiteralNode && !(node instanceof ArrayLiteralNode) && !to.isObject()) { final LiteralNode newNode = new LiteralNodeConstantEvaluator((LiteralNode)node, to).eval(); if (newNode != null) { resultNode = newNode; @@ -817,7 +816,6 @@ assert !node.isTerminal(); - final LexicalContext lc = getLexicalContext(); //This is the only place in this file that can create new temporaries //FinalizeTypes may not introduce ANY node that is not a conversion. return temporarySymbols.ensureSymbol(lc, to, resultNode); @@ -854,7 +852,7 @@ symbol = symbol.setTypeOverrideShared(to, temporarySymbols); LOG.info("Type override for temporary in '", node, "' => ", to); } - return node.setSymbol(getLexicalContext(), symbol); + return node.setSymbol(lc, symbol); } /** @@ -907,7 +905,7 @@ if (literalNode != null) { //inherit literal symbol for attr. - literalNode = (LiteralNode)literalNode.setSymbol(getLexicalContext(), parent.getSymbol()); + literalNode = (LiteralNode)literalNode.setSymbol(lc, parent.getSymbol()); } return literalNode; diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java --- a/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java Wed Jul 05 18:57:52 2017 +0200 @@ -33,7 +33,9 @@ import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.ir.IfNode; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LiteralNode; +import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.TernaryNode; import jdk.nashorn.internal.ir.UnaryNode; @@ -45,11 +47,12 @@ /** * Simple constant folding pass, executed before IR is starting to be lowered. */ -final class FoldConstants extends NodeVisitor { +final class FoldConstants extends NodeVisitor { private static final DebugLogger LOG = new DebugLogger("fold"); FoldConstants() { + super(new LexicalContext()); } @Override @@ -79,7 +82,7 @@ @Override public Node leaveFunctionNode(final FunctionNode functionNode) { - return functionNode.setState(getLexicalContext(), CompilationState.CONSTANT_FOLDED); + return functionNode.setState(lc, CompilationState.CONSTANT_FOLDED); } @Override @@ -141,6 +144,10 @@ return null; } + if (rhsNode instanceof ArrayLiteralNode) { + return null; + } + final LiteralNode rhs = (LiteralNode)rhsNode; final boolean rhsInteger = rhs.getType().isInteger(); @@ -212,6 +219,10 @@ final LiteralNode lhs = (LiteralNode)parent.lhs(); final LiteralNode rhs = (LiteralNode)parent.rhs(); + if (lhs instanceof ArrayLiteralNode || rhs instanceof ArrayLiteralNode) { + return null; + } + final Type widest = Type.widest(lhs.getType(), rhs.getType()); boolean isInteger = widest.isInteger(); @@ -279,9 +290,9 @@ isLong &= value != 0.0 && JSType.isRepresentableAsLong(value); if (isInteger) { - return LiteralNode.newInstance(token, finish, JSType.toInt32(value)); + return LiteralNode.newInstance(token, finish, (int)value); } else if (isLong) { - return LiteralNode.newInstance(token, finish, JSType.toLong(value)); + return LiteralNode.newInstance(token, finish, (long)value); } return LiteralNode.newInstance(token, finish, value); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/codegen/Lower.java --- a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java Wed Jul 05 18:57:52 2017 +0200 @@ -80,7 +80,7 @@ * finalized. */ -final class Lower extends NodeOperatorVisitor { +final class Lower extends NodeOperatorVisitor { private static final DebugLogger LOG = new DebugLogger("lower"); @@ -105,7 +105,7 @@ terminated = true; } } else { - statement.accept(new NodeVisitor() { + statement.accept(new NodeVisitor(new LexicalContext()) { @Override public boolean enterVarNode(final VarNode varNode) { newStatements.add(varNode.setInit(null)); @@ -121,7 +121,6 @@ @Override public boolean enterBlock(final Block block) { - final LexicalContext lc = getLexicalContext(); final FunctionNode function = lc.getCurrentFunction(); if (lc.isFunctionBody() && function.isProgram() && !function.hasDeclaredFunctions()) { new ExecuteNode(block.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this); @@ -134,12 +133,10 @@ //now we have committed the entire statement list to the block, but we need to truncate //whatever is after the last terminal. block append won't append past it - final BlockLexicalContext lc = (BlockLexicalContext)getLexicalContext(); - Statement last = lc.getLastStatement(); if (lc.isFunctionBody()) { - final FunctionNode currentFunction = getLexicalContext().getCurrentFunction(); + final FunctionNode currentFunction = lc.getCurrentFunction(); final boolean isProgram = currentFunction.isProgram(); final ReturnNode returnNode = new ReturnNode( last == null ? block.getLineNumber() : last.getLineNumber(), //TODO? @@ -191,7 +188,7 @@ final Node expr = executeNode.getExpression(); ExecuteNode node = executeNode; - final FunctionNode currentFunction = getLexicalContext().getCurrentFunction(); + final FunctionNode currentFunction = lc.getCurrentFunction(); if (currentFunction.isProgram()) { if (!(expr instanceof Block) || expr instanceof FunctionNode) { // it's not a block, but can be a function @@ -216,7 +213,7 @@ final Node test = forNode.getTest(); if (!forNode.isForIn() && conservativeAlwaysTrue(test)) { - newForNode = forNode.setTest(getLexicalContext(), null); + newForNode = forNode.setTest(lc, null); } return addStatement(checkEscape(newForNode)); @@ -230,7 +227,7 @@ @Override public Node leaveFunctionNode(final FunctionNode functionNode) { LOG.info("END FunctionNode: ", functionNode.getName()); - return functionNode.setState(getLexicalContext(), CompilationState.LOWERED); + return functionNode.setState(lc, CompilationState.LOWERED); } @Override @@ -261,19 +258,25 @@ return throwNode; } - private static Node ensureUniqueLabelsIn(final Node node) { - return node.accept(new NodeVisitor() { - @Override - public Node leaveDefault(final Node labelledNode) { - return labelledNode.ensureUniqueLabels(getLexicalContext()); - } + private static Node ensureUniqueNamesIn(final LexicalContext lc, final Node node) { + return node.accept(new NodeVisitor(new LexicalContext()) { + @Override + public Node leaveFunctionNode(final FunctionNode functionNode) { + final String name = functionNode.getName(); + return functionNode.setName(lc, lc.getCurrentFunction().uniqueName(name)); + } + + @Override + public Node leaveDefault(final Node labelledNode) { + return labelledNode.ensureUniqueLabels(lc); + } }); } - private static List copyFinally(final Block finallyBody) { + private static List copyFinally(final LexicalContext lc, final Block finallyBody) { final List newStatements = new ArrayList<>(); for (final Statement statement : finallyBody.getStatements()) { - newStatements.add((Statement)ensureUniqueLabelsIn(statement)); + newStatements.add((Statement)ensureUniqueNamesIn(lc, statement)); if (statement.hasTerminalFlags()) { return newStatements; } @@ -286,12 +289,12 @@ final long token = tryNode.getToken(); final int finish = tryNode.getFinish(); - final IdentNode exception = new IdentNode(token, finish, getLexicalContext().getCurrentFunction().uniqueName("catch_all")); + final IdentNode exception = new IdentNode(token, finish, lc.getCurrentFunction().uniqueName("catch_all")); - final Block catchBody = new Block(lineNumber, token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception))). - setIsTerminal(getLexicalContext(), true); //ends with throw, so terminal + final Block catchBody = new Block(lineNumber, token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception), ThrowNode.IS_SYNTHETIC_RETHROW)). + setIsTerminal(lc, true); //ends with throw, so terminal - final CatchNode catchAllNode = new CatchNode(lineNumber, token, finish, new IdentNode(exception), null, catchBody); + final CatchNode catchAllNode = new CatchNode(lineNumber, token, finish, new IdentNode(exception), null, catchBody, CatchNode.IS_SYNTHETIC_RETHROW); final Block catchAllBlock = new Block(lineNumber, token, finish, catchAllNode); //catchallblock -> catchallnode (catchnode) -> exception -> throw @@ -300,7 +303,7 @@ } private IdentNode compilerConstant(final CompilerConstants cc) { - final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); + final FunctionNode functionNode = lc.getCurrentFunction(); return new IdentNode(functionNode.getToken(), functionNode.getFinish(), cc.symbolName()); } @@ -316,11 +319,10 @@ * @return new try node after splicing finally code (same if nop) */ private Node spliceFinally(final TryNode tryNode, final List rethrows, final Block finallyBody) { - final int finish = tryNode.getFinish(); + assert tryNode.getFinallyBody() == null; + final int finish = tryNode.getFinish(); - assert tryNode.getFinallyBody() == null; - - final TryNode newTryNode = (TryNode)tryNode.accept(new NodeVisitor() { + final TryNode newTryNode = (TryNode)tryNode.accept(new NodeVisitor(new LexicalContext()) { final List insideTry = new ArrayList<>(); @Override @@ -338,7 +340,7 @@ @Override public Node leaveThrowNode(final ThrowNode throwNode) { if (rethrows.contains(throwNode)) { - final List newStatements = copyFinally(finallyBody); + final List newStatements = copyFinally(lc, finallyBody); if (!isTerminal(newStatements)) { newStatements.add(throwNode); } @@ -349,12 +351,12 @@ @Override public Node leaveBreakNode(final BreakNode breakNode) { - return copy(breakNode, Lower.this.getLexicalContext().getBreakable(breakNode.getLabel())); + return copy(breakNode, Lower.this.lc.getBreakable(breakNode.getLabel())); } @Override public Node leaveContinueNode(final ContinueNode continueNode) { - return copy(continueNode, Lower.this.getLexicalContext().getContinueTo(continueNode.getLabel())); + return copy(continueNode, Lower.this.lc.getContinueTo(continueNode.getLabel())); } @Override @@ -372,17 +374,17 @@ resultNode = null; } - newStatements.addAll(copyFinally(finallyBody)); + newStatements.addAll(copyFinally(lc, finallyBody)); if (!isTerminal(newStatements)) { newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode)); } - return new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new Block(returnNode.getLineNumber(), returnNode.getToken(), getLexicalContext().getCurrentBlock().getFinish(), newStatements)); + return new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new Block(returnNode.getLineNumber(), returnNode.getToken(), lc.getCurrentBlock().getFinish(), newStatements)); } private Node copy(final Statement endpoint, final Node targetNode) { if (!insideTry.contains(targetNode)) { - final List newStatements = copyFinally(finallyBody); + final List newStatements = copyFinally(lc, finallyBody); if (!isTerminal(newStatements)) { newStatements.add(endpoint); } @@ -436,7 +438,7 @@ final Block catchAll = catchAllBlock(tryNode); final List rethrows = new ArrayList<>(); - catchAll.accept(new NodeVisitor() { + catchAll.accept(new NodeVisitor(new LexicalContext()) { @Override public boolean enterThrowNode(final ThrowNode throwNode) { rethrows.add(throwNode); @@ -464,7 +466,7 @@ @Override public Node leaveVarNode(final VarNode varNode) { addStatement(varNode); - if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && getLexicalContext().getCurrentFunction().isProgram()) { + if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && lc.getCurrentFunction().isProgram()) { new ExecuteNode(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this); } return varNode; @@ -478,7 +480,7 @@ if (conservativeAlwaysTrue(test)) { //turn it into a for node without a test. final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), null, null, body, null, ForNode.IS_FOR).accept(this); - getLexicalContext().replace(whileNode, forNode); + lc.replace(whileNode, forNode); return forNode; } @@ -513,7 +515,7 @@ * @return eval location */ private String evalLocation(final IdentNode node) { - final Source source = getLexicalContext().getCurrentFunction().getSource(); + final Source source = lc.getCurrentFunction().getSource(); return new StringBuilder(). append(source.getName()). append('#'). @@ -545,10 +547,10 @@ // 'eval' call with at least one argument if (args.size() >= 1 && EVAL.symbolName().equals(callee.getName())) { - final FunctionNode currentFunction = getLexicalContext().getCurrentFunction(); + final FunctionNode currentFunction = lc.getCurrentFunction(); return callNode.setEvalArgs( new CallNode.EvalArgs( - ensureUniqueLabelsIn(args.get(0)).accept(this), + ensureUniqueNamesIn(lc, args.get(0)).accept(this), compilerConstant(THIS), evalLocation(callee), currentFunction.isStrict())); @@ -574,7 +576,7 @@ private static boolean controlFlowEscapes(final LexicalContext lex, final Block loopBody) { final List escapes = new ArrayList<>(); - loopBody.accept(new NodeVisitor() { + loopBody.accept(new NodeVisitor(new LexicalContext()) { @Override public Node leaveBreakNode(final BreakNode node) { escapes.add(node); @@ -595,7 +597,6 @@ } private LoopNode checkEscape(final LoopNode loopNode) { - final LexicalContext lc = getLexicalContext(); final boolean escapes = controlFlowEscapes(lc, loopNode.getBody()); if (escapes) { return loopNode. @@ -607,7 +608,7 @@ private Node addStatement(final Statement statement) { - ((BlockLexicalContext)getLexicalContext()).appendStatement(statement); + lc.appendStatement(statement); return statement; } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java --- a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java Wed Jul 05 18:57:52 2017 +0200 @@ -2081,7 +2081,9 @@ * @param args debug information to print */ private void debug(final Object... args) { - debug(30, args); + if (DEBUG) { + debug(30, args); + } } /** @@ -2091,7 +2093,9 @@ * @param args debug information to print */ private void debug_label(final Object... args) { - debug(26, args); + if (DEBUG) { + debug(22, args); + } } private void debug(final int padConstant, final Object... args) { @@ -2164,7 +2168,6 @@ new Throwable().printStackTrace(LOG.getOutputStream()); } } - } } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,476 @@ +/* + * 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.codegen; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +import jdk.nashorn.internal.codegen.types.Range; +import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.Assignment; +import jdk.nashorn.internal.ir.BinaryNode; +import jdk.nashorn.internal.ir.ForNode; +import jdk.nashorn.internal.ir.IdentNode; +import jdk.nashorn.internal.ir.LexicalContext; +import jdk.nashorn.internal.ir.LiteralNode; +import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; +import jdk.nashorn.internal.ir.LoopNode; +import jdk.nashorn.internal.ir.Node; +import jdk.nashorn.internal.ir.RuntimeNode; +import jdk.nashorn.internal.ir.Symbol; +import jdk.nashorn.internal.ir.UnaryNode; +import jdk.nashorn.internal.ir.VarNode; +import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; +import jdk.nashorn.internal.ir.visitor.NodeVisitor; +import jdk.nashorn.internal.parser.TokenType; +import jdk.nashorn.internal.runtime.DebugLogger; + +/** + * Range analysis and narrowing of type where it can be proven + * that there is no spillover, e.g. + * + * function func(c) { + * var v = c & 0xfff; + * var w = c & 0xeee; + * var x = v * w; + * return x; + * } + * + * Proves that the multiplication never exceeds 24 bits and can thus be an int + */ +final class RangeAnalyzer extends NodeOperatorVisitor { + static final DebugLogger LOG = new DebugLogger("ranges"); + + private static final Range.Functionality RANGE = new Range.Functionality(LOG); + + private final Map loopCounters = new HashMap<>(); + + RangeAnalyzer() { + super(new LexicalContext()); + } + + @Override + public boolean enterForNode(final ForNode forNode) { + //conservatively attempt to identify the loop counter. Null means that it wasn't + //properly identified and that no optimizations can be made with it - its range is + //simply unknown in that case, if it is assigned in the loop + final Symbol counter = findLoopCounter(forNode); + LOG.fine("Entering forNode " + forNode + " counter = " + counter); + if (counter != null && !assignedInLoop(forNode, counter)) { + loopCounters.put(forNode, counter); + } + return true; + } + + //destination visited + private Symbol setRange(final Node dest, final Range range) { + if (range.isUnknown()) { + return null; + } + + final Symbol symbol = dest.getSymbol(); + assert symbol != null : dest + " " + dest.getClass() + " has no symbol"; + assert symbol.getRange() != null : symbol + " has no range"; + final Range symRange = RANGE.join(symbol.getRange(), range); + + //anything assigned in the loop, not being the safe loop counter(s) invalidates its entire range + if (lc.inLoop() && !isLoopCounter(lc.getCurrentLoop(), symbol)) { + symbol.setRange(Range.createGenericRange()); + return symbol; + } + + if (!symRange.equals(symbol.getRange())) { + LOG.fine("Modify range for " + dest + " " + symbol + " from " + symbol.getRange() + " to " + symRange + " (in node = " + dest + ")" ); + symbol.setRange(symRange); + } + + return null; + } + + @Override + public Node leaveADD(final BinaryNode node) { + setRange(node, RANGE.add(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveSUB(final BinaryNode node) { + setRange(node, RANGE.sub(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveMUL(final BinaryNode node) { + setRange(node, RANGE.mul(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveDIV(final BinaryNode node) { + setRange(node, RANGE.div(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveMOD(final BinaryNode node) { + setRange(node, RANGE.mod(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveBIT_AND(final BinaryNode node) { + setRange(node, RANGE.and(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveBIT_OR(final BinaryNode node) { + setRange(node, RANGE.or(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveBIT_XOR(final BinaryNode node) { + setRange(node, RANGE.xor(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveSAR(final BinaryNode node) { + setRange(node, RANGE.sar(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveSHL(final BinaryNode node) { + setRange(node, RANGE.shl(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveSHR(final BinaryNode node) { + setRange(node, RANGE.shr(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + return node; + } + + private Node leaveCmp(final BinaryNode node) { + setRange(node, Range.createTypeRange(Type.BOOLEAN)); + return node; + } + + @Override + public Node leaveEQ(final BinaryNode node) { + return leaveCmp(node); + } + + @Override + public Node leaveEQ_STRICT(final BinaryNode node) { + return leaveCmp(node); + } + + @Override + public Node leaveNE(final BinaryNode node) { + return leaveCmp(node); + } + + @Override + public Node leaveNE_STRICT(final BinaryNode node) { + return leaveCmp(node); + } + + @Override + public Node leaveLT(final BinaryNode node) { + return leaveCmp(node); + } + + @Override + public Node leaveLE(final BinaryNode node) { + return leaveCmp(node); + } + + @Override + public Node leaveGT(final BinaryNode node) { + return leaveCmp(node); + } + + @Override + public Node leaveGE(final BinaryNode node) { + return leaveCmp(node); + } + + @Override + public Node leaveASSIGN(final BinaryNode node) { + Range range = node.rhs().getSymbol().getRange(); + if (range.isUnknown()) { + range = Range.createGenericRange(); + } + + setRange(node.lhs(), range); + setRange(node, range); + + return node; + } + + private Node leaveSelfModifyingAssign(final BinaryNode node, final Range range) { + setRange(node.lhs(), range); + setRange(node, range); + return node; + } + + private Node leaveSelfModifyingAssign(final UnaryNode node, final Range range) { + setRange(node.rhs(), range); + setRange(node, range); + return node; + } + + @Override + public Node leaveASSIGN_ADD(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.add(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveASSIGN_SUB(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.sub(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveASSIGN_MUL(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.mul(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveASSIGN_DIV(final BinaryNode node) { + return leaveSelfModifyingAssign(node, Range.createTypeRange(Type.NUMBER)); + } + + @Override + public Node leaveASSIGN_MOD(final BinaryNode node) { + return leaveSelfModifyingAssign(node, Range.createTypeRange(Type.NUMBER)); + } + + @Override + public Node leaveASSIGN_BIT_AND(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.and(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveASSIGN_BIT_OR(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.or(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveASSIGN_BIT_XOR(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.xor(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveASSIGN_SAR(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.sar(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveASSIGN_SHR(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.shr(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveASSIGN_SHL(final BinaryNode node) { + return leaveSelfModifyingAssign(node, RANGE.shl(node.lhs().getSymbol().getRange(), node.rhs().getSymbol().getRange())); + } + + @Override + public Node leaveDECINC(final UnaryNode node) { + switch (node.tokenType()) { + case DECPREFIX: + case DECPOSTFIX: + return leaveSelfModifyingAssign(node, RANGE.sub(node.rhs().getSymbol().getRange(), Range.createRange(1))); + case INCPREFIX: + case INCPOSTFIX: + return leaveSelfModifyingAssign(node, RANGE.add(node.rhs().getSymbol().getRange(), Range.createRange(1))); + default: + assert false; + return node; + } + } + + @Override + public Node leaveADD(final UnaryNode node) { + Range range = node.rhs().getSymbol().getRange(); + if (!range.getType().isNumeric()) { + range = Range.createTypeRange(Type.NUMBER); + } + setRange(node, range); + return node; + } + + @Override + public Node leaveBIT_NOT(final UnaryNode node) { + setRange(node, Range.createTypeRange(Type.INT)); + return node; + } + + @Override + public Node leaveNOT(final UnaryNode node) { + setRange(node, Range.createTypeRange(Type.BOOLEAN)); + return node; + } + + @Override + public Node leaveSUB(final UnaryNode node) { + setRange(node, RANGE.neg(node.rhs().getSymbol().getRange())); + return node; + } + + @Override + public Node leaveVarNode(final VarNode node) { + if (node.isAssignment()) { + Range range = node.getInit().getSymbol().getRange(); + range = range.isUnknown() ? Range.createGenericRange() : range; + + setRange(node.getName(), range); + setRange(node, range); + } + + return node; + } + + @SuppressWarnings("rawtypes") + @Override + public boolean enterLiteralNode(final LiteralNode node) { + // ignore array literals + return !(node instanceof ArrayLiteralNode); + } + + @Override + public Node leaveLiteralNode(@SuppressWarnings("rawtypes") final LiteralNode node) { + if (node.getType().isInteger()) { + setRange(node, Range.createRange(node.getInt32())); + } else if (node.getType().isNumber()) { + setRange(node, Range.createRange(node.getNumber())); + } else if (node.getType().isLong()) { + setRange(node, Range.createRange(node.getLong())); + } else if (node.getType().isBoolean()) { + setRange(node, Range.createTypeRange(Type.BOOLEAN)); + } else { + setRange(node, Range.createGenericRange()); + } + return node; + } + + @Override + public boolean enterRuntimeNode(final RuntimeNode node) { + // a runtime node that cannot be specialized is no point entering + return node.getRequest().canSpecialize(); + } + + /** + * Check whether a symbol is unsafely assigned in a loop - i.e. repeteadly assigned and + * not being identified as the loop counter. That means we don't really know anything + * about its range. + * @param loopNode loop node + * @param symbol symbol + * @return true if assigned in loop + */ + // TODO - this currently checks for nodes only - needs to be augmented for while nodes + // assignment analysis is also very conservative + private static boolean assignedInLoop(final LoopNode loopNode, final Symbol symbol) { + final HashSet skip = new HashSet<>(); + final HashSet assignmentsInLoop = new HashSet<>(); + + loopNode.accept(new NodeVisitor(new LexicalContext()) { + private boolean assigns(final Node node, final Symbol s) { + return node.isAssignment() && ((Assignment)node).getAssignmentDest().getSymbol() == s; + } + + @Override + public boolean enterForNode(final ForNode forNode) { + if (forNode.getInit() != null) { + skip.add(forNode.getInit()); + } + if (forNode.getModify() != null) { + skip.add(forNode.getModify()); + } + return true; + } + + @Override + public Node leaveDefault(final Node node) { + //if this is an assignment to symbol + if (!skip.contains(node) && assigns(node, symbol)) { + assignmentsInLoop.add(node); + } + return node; + } + }); + + return !assignmentsInLoop.isEmpty(); + } + + /** + * Check for a loop counter. This is currently quite conservative, in that it only handles + * x <= counter and x < counter. + * + * @param node loop node to check + * @return + */ + private static Symbol findLoopCounter(final LoopNode node) { + final Node test = node.getTest(); + + if (test != null && test.isComparison()) { + final BinaryNode binaryNode = (BinaryNode)test; + final Node lhs = binaryNode.lhs(); + final Node rhs = binaryNode.rhs(); + + //detect ident cmp int_literal + if (lhs instanceof IdentNode && rhs instanceof LiteralNode && ((LiteralNode)rhs).getType().isInteger()) { + final Symbol symbol = lhs.getSymbol(); + final int margin = ((LiteralNode)rhs).getInt32(); + final TokenType op = test.tokenType(); + + switch (op) { + case LT: + case LE: + symbol.setRange(RANGE.join(symbol.getRange(), Range.createRange(op == TokenType.LT ? margin - 1 : margin))); + return symbol; + case GT: + case GE: + //setRange(lhs, Range.createRange(op == TokenType.GT ? margin + 1 : margin)); + //return symbol; + default: + break; + } + } + } + + return null; + } + + private boolean isLoopCounter(final LoopNode loopNode, final Symbol symbol) { + //this only works if loop nodes aren't replaced by other ones during this transform, but they are not + return loopCounters.get(loopNode) == symbol; + } +} diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java --- a/nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java Wed Jul 05 18:57:52 2017 +0200 @@ -116,9 +116,10 @@ /** * Generate the invoke instruction for this shared scope call. * @param method the method emitter + * @return the method emitter */ - public void generateInvoke(final MethodEmitter method) { - method.invokestatic(compileUnit.getUnitClassName(), methodName, getStaticSignature()); + public MethodEmitter generateInvoke(final MethodEmitter method) { + return method.invokestatic(compileUnit.getUnitClassName(), methodName, getStaticSignature()); } /** diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/codegen/Splitter.java --- a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java Wed Jul 05 18:57:52 2017 +0200 @@ -49,12 +49,12 @@ /** * Split the IR into smaller compile units. */ -final class Splitter extends NodeVisitor { +final class Splitter extends NodeVisitor { /** Current compiler. */ private final Compiler compiler; /** IR to be broken down. */ - private FunctionNode outermost; + private final FunctionNode outermost; /** Compile unit for the main script. */ private final CompileUnit outermostCompileUnit; @@ -75,6 +75,7 @@ * @param outermostCompileUnit compile unit for outermost function, if non-lazy this is the script's compile unit */ public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) { + super(new LexicalContext()); this.compiler = compiler; this.outermost = functionNode; this.outermostCompileUnit = outermostCompileUnit; @@ -93,8 +94,6 @@ LOG.finest("Initiating split of '", functionNode.getName(), "'"); - final LexicalContext lc = getLexicalContext(); - long weight = WeighNodes.weigh(functionNode); final boolean top = fn.isProgram(); //compiler.getFunctionNode() == outermost; @@ -127,7 +126,7 @@ final Block body = functionNode.getBody(); final List dc = directChildren(functionNode); - final Block newBody = (Block)body.accept(new NodeVisitor() { + final Block newBody = (Block)body.accept(new NodeVisitor(new LexicalContext()) { @Override public boolean enterFunctionNode(final FunctionNode nestedFunction) { return dc.contains(nestedFunction); @@ -136,7 +135,7 @@ @Override public Node leaveFunctionNode(final FunctionNode nestedFunction) { FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction); - getLexicalContext().replace(nestedFunction, split); + lc.replace(nestedFunction, split); return split; } }); @@ -149,13 +148,13 @@ private static List directChildren(final FunctionNode functionNode) { final List dc = new ArrayList<>(); - functionNode.accept(new NodeVisitor() { + functionNode.accept(new NodeVisitor(new LexicalContext()) { @Override public boolean enterFunctionNode(final FunctionNode child) { if (child == functionNode) { return true; } - if (getLexicalContext().getParentFunction(child) == functionNode) { + if (lc.getParentFunction(child) == functionNode) { dc.add(child); } return false; @@ -181,7 +180,7 @@ * @return new weight for the resulting block. */ private Block splitBlock(final Block block, final FunctionNode function) { - getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT); + lc.setFlag(lc.getCurrentFunction(), FunctionNode.IS_SPLIT); final List splits = new ArrayList<>(); List statements = new ArrayList<>(); @@ -210,7 +209,7 @@ splits.add(createBlockSplitNode(block, function, statements, statementsWeight)); } - return block.setStatements(getLexicalContext(), splits); + return block.setStatements(lc, splits); } /** @@ -258,7 +257,7 @@ // been split already, so weigh again before splitting. long weight = WeighNodes.weigh(block, weightCache); if (weight >= SPLIT_THRESHOLD) { - newBlock = splitBlock(block, getLexicalContext().getFunction(block)); + newBlock = splitBlock(block, lc.getFunction(block)); weight = WeighNodes.weigh(newBlock, weightCache); } weightCache.put(newBlock, weight); @@ -274,9 +273,9 @@ return literal; } - final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); + final FunctionNode functionNode = lc.getCurrentFunction(); - getLexicalContext().setFlag(functionNode, FunctionNode.IS_SPLIT); + lc.setFlag(functionNode, FunctionNode.IS_SPLIT); if (literal instanceof ArrayLiteralNode) { final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal; diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java --- a/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java Wed Jul 05 18:57:52 2017 +0200 @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map; + import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.AccessNode; import jdk.nashorn.internal.ir.BinaryNode; @@ -41,6 +42,7 @@ import jdk.nashorn.internal.ir.IdentNode; import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.IndexNode; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit; @@ -63,7 +65,7 @@ * Computes the "byte code" weight of an AST segment. This is used * for Splitting too large class files */ -final class WeighNodes extends NodeOperatorVisitor { +final class WeighNodes extends NodeOperatorVisitor { /* * Weight constants. */ @@ -100,7 +102,7 @@ * @param weightCache cache of already calculated block weights */ private WeighNodes(FunctionNode topFunction, final Map weightCache) { - super(); + super(new LexicalContext()); this.topFunction = topFunction; this.weightCache = weightCache; } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/codegen/types/Range.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/nashorn/internal/codegen/types/Range.java Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,705 @@ +/* + * 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.codegen.types; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import jdk.nashorn.internal.runtime.DebugLogger; +import jdk.nashorn.internal.runtime.JSType; + +/** + * Represents the value range of a symbol. + */ +public abstract class Range { + + private static final Range GENERIC_RANGE = new Range() { + @Override + public Type getType() { + return Type.OBJECT; + } + }; + + private static final Range NUMBER_RANGE = new Range() { + @Override + public Type getType() { + return Type.NUMBER; + } + }; + + private static final Range UNKNOWN_RANGE = new Range() { + @Override + public Type getType() { + return Type.UNKNOWN; + } + + @Override + public boolean isUnknown() { + return true; + } + }; + + private static class IntegerRange extends Range { + private final long min; + private final long max; + private final Type type; + + private IntegerRange(final long min, final long max) { + assert min <= max; + this.min = min; + this.max = max; + this.type = typeFromRange(min, max); + } + + private static Type typeFromRange(final long from, final long to) { + if (from >= Integer.MIN_VALUE && to <= Integer.MAX_VALUE) { + return Type.INT; + } + return Type.LONG; + } + + @Override + public Type getType() { + return type; + } + + public long getMin() { + return min; + } + + public long getMax() { + return max; + } + + @Override + public boolean isIntegerConst() { + return getMin() == getMax(); + } + + private long getBitMask() { + if (min == max) { + return min; + } + + if (min < 0) { + return ~0L; + } + + long mask = 1; + while (mask < max) { + mask = (mask << 1) | 1; + } + return mask; + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof IntegerRange) { + final IntegerRange other = (IntegerRange)obj; + return this.type == other.type && this.min == other.min && this.max == other.max; + } + return false; + } + + @Override + public int hashCode() { + return Long.hashCode(min) ^ Long.hashCode(max); + } + + @Override + public String toString() { + return super.toString() + "[" + min +", " + max + "]"; + } + } + + /** + * Get narrowest type for this range + * @return type + */ + public abstract Type getType(); + + /** + * Is this range unknown + * @return true if unknown + */ + public boolean isUnknown() { + return false; + } + + /** + * Check if an integer is enough to span this range + * @return true if integer is enough + */ + public boolean isIntegerType() { + return this instanceof IntegerRange; + } + + /** + * Check if an integer is enough to span this range + * @return true if integer is enough + */ + public boolean isIntegerConst() { + return false; + } + + /** + * Create an unknown range - this is most likely a singleton object + * and it represents "we have no known range information" + * @return the range + */ + public static Range createUnknownRange() { + return UNKNOWN_RANGE; + } + + /** + * Create a constant range: [value, value] + * @param value value + * @return the range + */ + public static Range createRange(final int value) { + return createIntegerRange(value, value); + } + + /** + * Create a constant range: [value, value] + * @param value value + * @return the range + */ + public static Range createRange(final long value) { + return createIntegerRange(value, value); + } + + /** + * Create a constant range: [value, value] + * @param value value + * @return the range + */ + public static Range createRange(final double value) { + if (isRepresentableAsLong(value)) { + return createIntegerRange((long) value, (long) value); + } + return createNumberRange(); + } + + /** + * Create a constant range: [value, value] + * @param value value + * @return the range + */ + public static Range createRange(final Object value) { + if (value instanceof Integer) { + return createRange((int)value); + } else if (value instanceof Long) { + return createRange((long)value); + } else if (value instanceof Double) { + return createRange((double)value); + } + + return createGenericRange(); + } + + /** + * Create a generic range - object symbol that carries no range + * information + * @return the range + */ + public static Range createGenericRange() { + return GENERIC_RANGE; + } + + /** + * Create a number range - number symbol that carries no range + * information + * @return the range + */ + public static Range createNumberRange() { + return NUMBER_RANGE; + } + + /** + * Create an integer range [min, max] + * @param min minimum value, inclusive + * @param max maximum value, inclusive + * @return the range + */ + public static IntegerRange createIntegerRange(final long min, final long max) { + return new IntegerRange(min, max); + } + + /** + * Create an integer range of maximum type width for the given type + * @param type the type + * @return the range + */ + public static IntegerRange createIntegerRange(final Type type) { + assert type.isNumeric() && !type.isNumber(); + final long min; + final long max; + if (type.isInteger()) { + min = Integer.MIN_VALUE; + max = Integer.MAX_VALUE; + } else if (type.isLong()) { + min = Long.MIN_VALUE; + max = Long.MAX_VALUE; + } else { + throw new AssertionError(); //type incompatible with integer range + } + return new IntegerRange(min, max); + } + + /** + * Create an range of maximum type width for the given type + * @param type the type + * @return the range + */ + public static Range createTypeRange(final Type type) { + if (type.isNumber()) { + return createNumberRange(); + } else if (type.isNumeric()) { + return createIntegerRange(type); + } else { + return createGenericRange(); + } + } + + // check that add doesn't overflow + private static boolean checkAdd(final long a, final long b) { + final long result = a + b; + return ((a ^ result) & (b ^ result)) >= 0; + } + + // check that sub doesn't overflow + private static boolean checkSub(final long a, final long b) { + final long result = a - b; + return ((a ^ result) & (b ^ result)) >= 0; + } + + private static boolean checkMul(final long a, final long b) { + // TODO correct overflow check + return a >= Integer.MIN_VALUE && a <= Integer.MAX_VALUE && b >= Integer.MIN_VALUE && b <= Integer.MAX_VALUE; + } + + /** + * The range functionality class responsible for merging ranges and drawing + * range conclusions from operations executed + */ + public static class Functionality { + /** logger */ + protected final DebugLogger log; + + /** + * Constructor + * @param log logger + */ + public Functionality(final DebugLogger log) { + this.log = log; + } + + /** + * Join two ranges + * @param a first range + * @param b second range + * @return the joined range + */ + public Range join(final Range a, final Range b) { + if (a.equals(b)) { + return a; + } + + Type joinedType = a.getType(); + if (a.getType() != b.getType()) { + if (a.isUnknown()) { + return b; + } + if (b.isUnknown()) { + return a; + } + + joinedType = Type.widest(a.getType(), b.getType()); + } + + if (joinedType.isInteger() || joinedType.isLong()) { + return createIntegerRange( + Math.min(((IntegerRange) a).getMin(), ((IntegerRange) b).getMin()), + Math.max(((IntegerRange) a).getMax(), ((IntegerRange) b).getMax())); + } + + return createTypeRange(joinedType); + } + + /** + * Add operation + * @param a range of first symbol to be added + * @param b range of second symbol to be added + * @return resulting range representing the value range after add + */ + public Range add(final Range a, final Range b) { + if (a.isIntegerType() && b.isIntegerType()) { + final IntegerRange lhs = (IntegerRange)a; + final IntegerRange rhs = (IntegerRange)b; + if (checkAdd(lhs.getMin(), rhs.getMin()) && checkAdd(lhs.getMax(), rhs.getMax())) { + return createIntegerRange(lhs.getMin() + rhs.getMin(), lhs.getMax() + rhs.getMax()); + } + } + + if (a.getType().isNumeric() && b.getType().isNumeric()) { + return createNumberRange(); + } + + return createGenericRange(); + } + + /** + * Sub operation + * @param a range of first symbol to be subtracted + * @param b range of second symbol to be subtracted + * @return resulting range representing the value range after subtraction + */ + public Range sub(final Range a, final Range b) { + if (a.isIntegerType() && b.isIntegerType()) { + final IntegerRange lhs = (IntegerRange)a; + final IntegerRange rhs = (IntegerRange)b; + if (checkSub(lhs.getMin(), rhs.getMax()) && checkSub(lhs.getMax(), rhs.getMin())) { + return createIntegerRange(lhs.getMin() - rhs.getMax(), lhs.getMax() - rhs.getMin()); + } + } + + if (a.getType().isNumeric() && b.getType().isNumeric()) { + return createNumberRange(); + } + + return createGenericRange(); + } + + /** + * Mul operation + * @param a range of first symbol to be multiplied + * @param b range of second symbol to be multiplied + * @return resulting range representing the value range after multiplication + */ + public Range mul(final Range a, final Range b) { + if (a.isIntegerType() && b.isIntegerType()) { + final IntegerRange lhs = (IntegerRange)a; + final IntegerRange rhs = (IntegerRange)b; + + //ensure that nothing ever overflows or underflows + if (checkMul(lhs.getMin(), rhs.getMin()) && + checkMul(lhs.getMax(), rhs.getMax()) && + checkMul(lhs.getMin(), rhs.getMax()) && + checkMul(lhs.getMax(), rhs.getMin())) { + + final List results = + Arrays.asList( + lhs.getMin() * rhs.getMin(), + lhs.getMin() * rhs.getMax(), + lhs.getMax() * rhs.getMin(), + lhs.getMax() * rhs.getMax()); + return createIntegerRange(Collections.min(results), Collections.max(results)); + } + } + + if (a.getType().isNumeric() && b.getType().isNumeric()) { + return createNumberRange(); + } + + return createGenericRange(); + } + + /** + * Neg operation + * @param a range of value symbol to be negated + * @return resulting range representing the value range after neg + */ + public Range neg(final Range a) { + if (a.isIntegerType()) { + final IntegerRange rhs = (IntegerRange)a; + if (rhs.getMin() != Long.MIN_VALUE && rhs.getMax() != Long.MIN_VALUE) { + return createIntegerRange(-rhs.getMax(), -rhs.getMin()); + } + } + + if (a.getType().isNumeric()) { + return createNumberRange(); + } + + return createGenericRange(); + } + + /** + * Bitwise and operation + * @param a range of first symbol to be and:ed + * @param b range of second symbol to be and:ed + * @return resulting range representing the value range after and + */ + public Range and(final Range a, final Range b) { + if (a.isIntegerType() && b.isIntegerType()) { + final int resultMask = (int) (((IntegerRange)a).getBitMask() & ((IntegerRange)b).getBitMask()); + if (resultMask >= 0) { + return createIntegerRange(0, resultMask); + } + } else if (a.isUnknown() && b.isIntegerType()) { + final long operandMask = ((IntegerRange)b).getBitMask(); + if (operandMask >= 0) { + return createIntegerRange(0, operandMask); + } + } else if (a.isIntegerType() && b.isUnknown()) { + final long operandMask = ((IntegerRange)a).getBitMask(); + if (operandMask >= 0) { + return createIntegerRange(0, operandMask); + } + } + + return createTypeRange(Type.INT); + } + + /** + * Bitwise or operation + * @param a range of first symbol to be or:ed + * @param b range of second symbol to be or:ed + * @return resulting range representing the value range after or + */ + public Range or(final Range a, final Range b) { + if (a.isIntegerType() && b.isIntegerType()) { + final int resultMask = (int)(((IntegerRange)a).getBitMask() | ((IntegerRange)b).getBitMask()); + if (resultMask >= 0) { + return createIntegerRange(0, resultMask); + } + } + + return createTypeRange(Type.INT); + } + + /** + * Bitwise xor operation + * @param a range of first symbol to be xor:ed + * @param b range of second symbol to be xor:ed + * @return resulting range representing the value range after and + */ + public Range xor(final Range a, final Range b) { + if (a.isIntegerConst() && b.isIntegerConst()) { + return createRange(((IntegerRange)a).getMin() ^ ((IntegerRange)b).getMin()); + } + + if (a.isIntegerType() && b.isIntegerType()) { + final int resultMask = (int)(((IntegerRange)a).getBitMask() | ((IntegerRange)b).getBitMask()); + if (resultMask >= 0) { + return createIntegerRange(0, createIntegerRange(0, resultMask).getBitMask()); + } + } + return createTypeRange(Type.INT); + } + + /** + * Bitwise shl operation + * @param a range of first symbol to be shl:ed + * @param b range of second symbol to be shl:ed + * @return resulting range representing the value range after shl + */ + public Range shl(final Range a, final Range b) { + if (b.isIntegerType() && b.isIntegerConst()) { + final IntegerRange left = (IntegerRange)(a.isIntegerType() ? a : createTypeRange(Type.INT)); + final int shift = (int)((IntegerRange) b).getMin() & 0x1f; + final int min = (int)left.getMin() << shift; + final int max = (int)left.getMax() << shift; + if (min >> shift == left.getMin() && max >> shift == left.getMax()) { + return createIntegerRange(min, max); + } + } + + return createTypeRange(Type.INT); + } + + /** + * Bitwise shr operation + * @param a range of first symbol to be shr:ed + * @param b range of second symbol to be shr:ed + * @return resulting range representing the value range after shr + */ + public Range shr(final Range a, final Range b) { + if (b.isIntegerType() && b.isIntegerConst()) { + final long shift = ((IntegerRange) b).getMin() & 0x1f; + final IntegerRange left = (IntegerRange)(a.isIntegerType() ? a : createTypeRange(Type.INT)); + if (left.getMin() >= 0) { + long min = left.getMin() >>> shift; + long max = left.getMax() >>> shift; + return createIntegerRange(min, max); + } else if (shift >= 1) { + return createIntegerRange(0, JSType.MAX_UINT >>> shift); + } + } + + return createTypeRange(Type.INT); + } + + /** + * Bitwise sar operation + * @param a range of first symbol to be sar:ed + * @param b range of second symbol to be sar:ed + * @return resulting range representing the value range after sar + */ + public Range sar(final Range a, final Range b) { + if (b.isIntegerType() && b.isIntegerConst()) { + final IntegerRange left = (IntegerRange)(a.isIntegerType() ? a : createTypeRange(Type.INT)); + final long shift = ((IntegerRange) b).getMin() & 0x1f; + final long min = left.getMin() >> shift; + final long max = left.getMax() >> shift; + return createIntegerRange(min, max); + } + + return createTypeRange(Type.INT); + } + + /** + * Modulo operation + * @param a range of first symbol to the mod operation + * @param b range of second symbol to be mod operation + * @return resulting range representing the value range after mod + */ + public Range mod(final Range a, final Range b) { + if (a.isIntegerType() && b.isIntegerType()) { + final IntegerRange rhs = (IntegerRange) b; + if (rhs.getMin() > 0 || rhs.getMax() < 0) { // divisor range must not include 0 + final long absmax = Math.max(Math.abs(rhs.getMin()), Math.abs(rhs.getMax())) - 1; + return createIntegerRange(rhs.getMin() > 0 ? 0 : -absmax, rhs.getMax() < 0 ? 0 : +absmax); + } + } + return createTypeRange(Type.NUMBER); + } + + /** + * Division operation + * @param a range of first symbol to the division + * @param b range of second symbol to be division + * @return resulting range representing the value range after division + */ + public Range div(final Range a, final Range b) { + // TODO + return createTypeRange(Type.NUMBER); + } + } + + /** + * Simple trace functionality that will log range creation + */ + public static class TraceFunctionality extends Functionality { + TraceFunctionality(final DebugLogger log) { + super(log); + } + + private Range trace(final Range result, final String operation, final Range... operands) { + log.fine("range::" + operation + Arrays.toString(operands) + " => " + result); + return result; + } + + @Override + public Range join(final Range a, final Range b) { + final Range result = super.join(a, b); + if (!a.equals(b)) { + trace(result, "join", a, b); + } + return result; + } + + @Override + public Range add(final Range a, final Range b) { + return trace(super.add(a, b), "add", a, b); + } + + @Override + public Range sub(final Range a, final Range b) { + return trace(super.sub(a, b), "sub", a, b); + } + + @Override + public Range mul(final Range a, final Range b) { + return trace(super.mul(a, b), "mul", a, b); + } + + @Override + public Range neg(final Range a) { + return trace(super.neg(a), "neg", a); + } + + @Override + public Range and(final Range a, final Range b) { + return trace(super.and(a, b), "and", a, b); + } + + @Override + public Range or(final Range a, final Range b) { + return trace(super.or(a, b), "or", a, b); + } + + @Override + public Range xor(final Range a, final Range b) { + return trace(super.xor(a, b), "xor", a, b); + } + + @Override + public Range shl(final Range a, final Range b) { + return trace(super.shl(a, b), "shl", a, b); + } + + @Override + public Range shr(final Range a, final Range b) { + return trace(super.shr(a, b), "shr", a, b); + } + + @Override + public Range sar(final Range a, final Range b) { + return trace(super.sar(a, b), "sar", a, b); + } + + @Override + public Range mod(final Range a, final Range b) { + return trace(super.mod(a, b), "mod", a, b); + } + + @Override + public Range div(final Range a, final Range b) { + return trace(super.div(a, b), "div", a, b); + } + } + + @Override + public String toString() { + return String.valueOf(getType()); + } + + @SuppressWarnings("unused") + private static boolean isRepresentableAsInt(final double number) { + return (int)number == number && !isNegativeZero(number); + } + + private static boolean isRepresentableAsLong(final double number) { + return (long)number == number && !isNegativeZero(number); + } + + private static boolean isNegativeZero(final double number) { + return Double.doubleToLongBits(number) == Double.doubleToLongBits(-0.0); + } +} diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/codegen/types/Type.java --- a/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java Wed Jul 05 18:57:52 2017 +0200 @@ -106,23 +106,13 @@ Type(final String name, final Class clazz, final int weight, final int slots) { this.name = name; this.clazz = clazz; - this.descriptor = Type.getDescriptor(clazz); + this.descriptor = jdk.internal.org.objectweb.asm.Type.getDescriptor(clazz); this.weight = weight; assert weight >= MIN_WEIGHT && weight <= MAX_WEIGHT : "illegal type weight: " + weight; this.slots = slots; } /** - * Return an internal descriptor for a type - * - * @param type the type - * @return descriptor string - */ - public static String getDescriptor(final Class type) { - return jdk.internal.org.objectweb.asm.Type.getDescriptor(type); - } - - /** * Get the weight of this type - use this e.g. for sorting method descriptors * @return the weight */ diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/AccessNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -60,7 +60,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterAccessNode(this)) { return visitor.leaveAccessNode( setBase(base.accept(visitor)). @@ -110,7 +110,6 @@ return new AccessNode(this, base, property, isFunction(), hasCallSiteType()); } - private AccessNode setProperty(final IdentNode property) { if (this.property == property) { return this; diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -59,6 +59,23 @@ this.rhs = rhs; } + @Override + public boolean isComparison() { + switch (tokenType()) { + case EQ: + case EQ_STRICT: + case NE: + case NE_STRICT: + case LE: + case LT: + case GE: + case GT: + return true; + default: + return false; + } + } + /** * Return the widest possible type for this operation. This is used for compile time * static type inference @@ -143,7 +160,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterBinaryNode(this)) { return visitor.leaveBinaryNode(setLHS(lhs.accept(visitor)).setRHS(rhs.accept(visitor))); } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/Block.java --- a/nashorn/src/jdk/nashorn/internal/ir/Block.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/Block.java Wed Jul 05 18:57:52 2017 +0200 @@ -131,7 +131,7 @@ * @return new or same node */ @Override - public Node accept(final LexicalContext lc, final NodeVisitor visitor) { + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterBlock(this)) { return visitor.leaveBlock(setStatements(lc, Node.accept(visitor, Statement.class, statements))); } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/BreakNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/BreakNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/BreakNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -59,7 +59,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterBreakNode(this)) { return visitor.leaveBreakNode(this); } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/CallNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/CallNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/CallNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.List; + import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.annotations.Ignore; import jdk.nashorn.internal.ir.annotations.Immutable; @@ -194,7 +195,7 @@ * @return node or replacement */ @Override - public Node accept(final LexicalContext lc, final NodeVisitor visitor) { + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterCallNode(this)) { final CallNode newCallNode = (CallNode)visitor.leaveCallNode( setFunction(function.accept(visitor)). diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/CaseNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/CaseNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/CaseNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -78,7 +78,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterCaseNode(this)) { final Node newTest = test == null ? null : test.accept(visitor); final Block newBody = body == null ? null : (Block)body.accept(visitor); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/CatchNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/CatchNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/CatchNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -42,6 +42,11 @@ /** Catch body. */ private final Block body; + private final int flags; + + /** Is this block a synthethic rethrow created by finally inlining? */ + public static final int IS_SYNTHETIC_RETHROW = 1; + /** * Constructors * @@ -51,19 +56,22 @@ * @param exception variable name of exception * @param exceptionCondition exception condition * @param body catch body + * @param flags flags */ - public CatchNode(final int lineNumber, final long token, final int finish, final IdentNode exception, final Node exceptionCondition, final Block body) { + public CatchNode(final int lineNumber, final long token, final int finish, final IdentNode exception, final Node exceptionCondition, final Block body, final int flags) { super(lineNumber, token, finish); this.exception = exception; this.exceptionCondition = exceptionCondition; this.body = body; + this.flags = flags; } - private CatchNode(final CatchNode catchNode, final IdentNode exception, final Node exceptionCondition, final Block body) { + private CatchNode(final CatchNode catchNode, final IdentNode exception, final Node exceptionCondition, final Block body, final int flags) { super(catchNode); this.exception = exception; this.exceptionCondition = exceptionCondition; this.body = body; + this.flags = flags; } /** @@ -71,7 +79,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterCatchNode(this)) { return visitor.leaveCatchNode( setException((IdentNode)exception.accept(visitor)). @@ -124,7 +132,7 @@ if (this.exceptionCondition == exceptionCondition) { return this; } - return new CatchNode(this, exception, exceptionCondition, body); + return new CatchNode(this, exception, exceptionCondition, body, flags); } /** @@ -144,13 +152,25 @@ if (this.exception == exception) { return this; } - return new CatchNode(this, exception, exceptionCondition, body); + return new CatchNode(this, exception, exceptionCondition, body, flags); } private CatchNode setBody(final Block body) { if (this.body == body) { return this; } - return new CatchNode(this, exception, exceptionCondition, body); + return new CatchNode(this, exception, exceptionCondition, body, flags); } + + /** + * Is this catch block a non-JavaScript constructor, for example created as + * part of the rethrow mechanism of a finally block in Lower? Then we just + * pass the exception on and need not unwrap whatever is in the ECMAException + * object catch symbol + * @return true if a finally synthetic rethrow + */ + public boolean isSyntheticRethrow() { + return (flags & IS_SYNTHETIC_RETHROW) == IS_SYNTHETIC_RETHROW; + } + } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/ContinueNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/ContinueNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/ContinueNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -55,7 +55,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterContinueNode(this)) { return visitor.leaveContinueNode(this); } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/EmptyNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/EmptyNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/EmptyNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -56,7 +56,7 @@ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterEmptyNode(this)) { return visitor.leaveEmptyNode(this); } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/ExecuteNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/ExecuteNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/ExecuteNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -62,7 +62,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterExecuteNode(this)) { return visitor.leaveExecuteNode(setExpression(expression.accept(visitor))); } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/ForNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/ForNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/ForNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -86,7 +86,7 @@ } @Override - protected Node accept(final LexicalContext lc, final NodeVisitor visitor) { + protected Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterForNode(this)) { return visitor.leaveForNode( setInit(lc, init == null ? null : init.accept(visitor)). diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -250,6 +250,7 @@ final FunctionNode functionNode, final long lastToken, final int flags, + final String name, final Type returnType, final CompileUnit compileUnit, final EnumSet compilationState, @@ -260,6 +261,7 @@ super(functionNode); this.flags = flags; + this.name = name; this.returnType = returnType; this.compileUnit = compileUnit; this.lastToken = lastToken; @@ -271,7 +273,6 @@ // the fields below never change - they are final and assigned in constructor this.source = functionNode.source; - this.name = functionNode.name; this.ident = functionNode.ident; this.namespace = functionNode.namespace; this.declaredSymbols = functionNode.declaredSymbols; @@ -280,7 +281,7 @@ } @Override - public Node accept(final LexicalContext lc, final NodeVisitor visitor) { + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterFunctionNode(this)) { return visitor.leaveFunctionNode(setBody(lc, (Block)body.accept(visitor))); } @@ -315,7 +316,7 @@ if (this.snapshot == null) { return this; } - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, null, hints)); + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, null, hints)); } /** @@ -331,7 +332,7 @@ if (isProgram() || parameters.isEmpty()) { return this; //never specialize anything that won't be recompiled } - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, this, hints)); + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, this, hints)); } /** @@ -339,7 +340,7 @@ * @return true if specialization is possible */ public boolean canSpecialize() { - return getFlag(CAN_SPECIALIZE); + return snapshot != null && getFlag(CAN_SPECIALIZE); } /** @@ -389,7 +390,7 @@ } final EnumSet newState = EnumSet.copyOf(this.compilationState); newState.add(state); - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, newState, body, parameters, snapshot, hints)); + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, newState, body, parameters, snapshot, hints)); } /** @@ -410,7 +411,7 @@ if (this.hints == hints) { return this; } - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); } /** @@ -463,7 +464,7 @@ if (this.flags == flags) { return this; } - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); } @Override @@ -529,7 +530,7 @@ } /** - * Get the identifier for this function + * Get the identifier for this function, this is its symbol. * @return the identifier as an IdentityNode */ public IdentNode getIdent() { @@ -572,7 +573,7 @@ if(this.body == body) { return this; } - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); } /** @@ -640,7 +641,7 @@ if (this.lastToken == lastToken) { return this; } - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); } /** @@ -651,6 +652,20 @@ return name; } + + /** + * Set the internal name for this function + * @param lc lexical context + * @param name new name + * @return new function node if changed, otherwise the same + */ + public FunctionNode setName(final LexicalContext lc, final String name) { + if (this.name.equals(name)) { + return this; + } + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); + } + /** * Check if this function should have all its variables in its own scope. Scripts, split sub-functions, and * functions having with and/or eval blocks are such. @@ -698,7 +713,7 @@ if (this.parameters == parameters) { return this; } - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); } /** @@ -762,6 +777,7 @@ this, lastToken, flags, + name, Type.widest(this.returnType, returnType.isObject() ? Type.OBJECT : returnType), @@ -801,7 +817,7 @@ if (this.compileUnit == compileUnit) { return this; } - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); } /** diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/IdentNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -29,7 +29,6 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.__FILE__; import static jdk.nashorn.internal.codegen.CompilerConstants.__LINE__; import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS; - import jdk.nashorn.internal.codegen.ObjectClassGenerator; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.annotations.Immutable; @@ -119,7 +118,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterIdentNode(this)) { return visitor.leaveIdentNode(this); } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/IfNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/IfNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/IfNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -72,7 +72,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterIfNode(this)) { return visitor.leaveIfNode( setTest(test.accept(visitor)). diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/IndexNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/IndexNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/IndexNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -56,19 +56,12 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterIndexNode(this)) { - final Node newBase = base.accept(visitor); - final Node newIndex = index.accept(visitor); - final IndexNode newNode; - if (newBase != base || newIndex != index) { - newNode = new IndexNode(this, newBase, newIndex, isFunction(), hasCallSiteType()); - } else { - newNode = this; - } - return visitor.leaveIndexNode(newNode); + return visitor.leaveIndexNode( + setBase(base.accept(visitor)). + setIndex(index.accept(visitor))); } - return this; } @@ -106,6 +99,13 @@ return index; } + private IndexNode setBase(final Node base) { + if (this.base == base) { + return this; + } + return new IndexNode(this, base, index, isFunction(), hasCallSiteType()); + } + /** * Set the index expression for this node * @param index new index expression diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/LabelNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/LabelNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/LabelNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -67,11 +67,11 @@ } @Override - public Node accept(final LexicalContext lc, final NodeVisitor visitor) { + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterLabelNode(this)) { return visitor.leaveLabelNode( - setLabel(visitor.getLexicalContext(), (IdentNode)label.accept(visitor)). - setBody(visitor.getLexicalContext(), (Block)body.accept(visitor))); + setLabel(lc, (IdentNode)label.accept(visitor)). + setBody(lc, (Block)body.accept(visitor))); } return this; diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java --- a/nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java Wed Jul 05 18:57:52 2017 +0200 @@ -440,6 +440,23 @@ } /** + * Check whether the lexical context is currently inside a loop + * @return true if inside a loop + */ + public boolean inLoop() { + return getCurrentLoop() != null; + } + + /** + * Returns the loop header of the current loop, or null if not inside a loop + * @return loop header + */ + public LoopNode getCurrentLoop() { + final Iterator iter = new NodeIterator<>(LoopNode.class, getCurrentFunction()); + return iter.hasNext() ? iter.next() : null; + } + + /** * Find the breakable node corresponding to this label. * @param label label to search for, if null the closest breakable node will be returned unconditionally, e.g. a while loop with no label * @return closest breakable node @@ -461,8 +478,7 @@ } private LoopNode getContinueTo() { - final Iterator iter = new NodeIterator<>(LoopNode.class, getCurrentFunction()); - return iter.hasNext() ? iter.next() : null; + return getCurrentLoop(); } /** diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/LexicalContextNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/LexicalContextNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/LexicalContextNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -60,10 +60,10 @@ * * @return new node or same node depending on state change */ - protected abstract Node accept(final LexicalContext lc, final NodeVisitor visitor); + protected abstract Node accept(final LexicalContext lc, final NodeVisitor visitor); @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { final LexicalContext lc = visitor.getLexicalContext(); lc.push(this); final LexicalContextNode newNode = (LexicalContextNode)accept(lc, visitor); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -28,6 +28,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; + import jdk.nashorn.internal.codegen.CompileUnit; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.annotations.Immutable; @@ -208,7 +209,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterLiteralNode(this)) { return visitor.leaveLiteralNode(this); } @@ -514,7 +515,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterLiteralNode(this)) { if (value != null) { final Node newValue = value.accept(visitor); @@ -840,7 +841,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterLiteralNode(this)) { final List oldValue = Arrays.asList(value); final List newValue = Node.accept(visitor, Node.class, oldValue); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/Node.java --- a/nashorn/src/jdk/nashorn/internal/ir/Node.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/Node.java Wed Jul 05 18:57:52 2017 +0200 @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.List; + import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.parser.Token; @@ -153,6 +154,14 @@ } /** + * Returns true if this node represents a comparison operator + * @return true if comparison + */ + public boolean isComparison() { + return false; + } + + /** * For reference copies - ensure that labels in the copy node are unique * using an appropriate copy constructor * @param lc lexical context @@ -167,7 +176,7 @@ * @param visitor Node visitor. * @return node the node or its replacement after visitation, null if no further visitations are required */ - public abstract Node accept(NodeVisitor visitor); + public abstract Node accept(NodeVisitor visitor); @Override public String toString() { @@ -329,7 +338,7 @@ } //on change, we have to replace the entire list, that's we can't simple do ListIterator.set - static List accept(final NodeVisitor visitor, final Class clazz, final List list) { + static List accept(final NodeVisitor visitor, final Class clazz, final List list) { boolean changed = false; final List newList = new ArrayList<>(); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/ObjectNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/ObjectNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/ObjectNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -58,7 +58,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterObjectNode(this)) { return visitor.leaveObjectNode(setElements(Node.accept(visitor, Node.class, elements))); } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/PropertyNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/PropertyNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/PropertyNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -81,7 +81,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterPropertyNode(this)) { return visitor.leavePropertyNode( setKey((PropertyKey)((Node)key).accept(visitor)). diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/ReturnNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/ReturnNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/ReturnNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -86,7 +86,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterReturnNode(this)) { if (expression != null) { return visitor.leaveReturnNode(setExpression(expression.accept(visitor))); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -29,6 +29,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; + import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.visitor.NodeVisitor; @@ -407,7 +408,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterRuntimeNode(this)) { final List newArgs = new ArrayList<>(); for (final Node arg : args) { diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/SplitNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/SplitNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/SplitNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -81,7 +81,7 @@ } @Override - public Node accept(final LexicalContext lc, final NodeVisitor visitor) { + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterSplitNode(this)) { return visitor.leaveSplitNode(setBody(lc, body.accept(visitor))); } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -100,11 +100,11 @@ } @Override - public Node accept(final LexicalContext lc, final NodeVisitor visitor) { + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterSwitchNode(this)) { return visitor.leaveSwitchNode( - setExpression(visitor.getLexicalContext(), expression.accept(visitor)). - setCases(visitor.getLexicalContext(), Node.accept(visitor, CaseNode.class, cases), defaultCaseIndex)); + setExpression(lc, expression.accept(visitor)). + setCases(lc, Node.accept(visitor, CaseNode.class, cases), defaultCaseIndex)); } return this; diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/Symbol.java --- a/nashorn/src/jdk/nashorn/internal/ir/Symbol.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/Symbol.java Wed Jul 05 18:57:52 2017 +0200 @@ -29,6 +29,8 @@ import java.util.HashSet; import java.util.Set; import java.util.StringTokenizer; + +import jdk.nashorn.internal.codegen.types.Range; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.Debug; @@ -89,6 +91,9 @@ /** Number of times this symbol is used in code */ private int useCount; + /** Range for symbol */ + private Range range; + /** Debugging option - dump info and stack trace when symbols with given names are manipulated */ private static final Set TRACE_SYMBOLS; private static final Set TRACE_SYMBOLS_STACKTRACE; @@ -131,6 +136,7 @@ this.type = type; this.slot = slot; this.fieldIndex = -1; + this.range = Range.createUnknownRange(); trace("CREATE SYMBOL"); } @@ -157,12 +163,13 @@ private Symbol(final Symbol base, final String name, final int flags) { this.flags = flags; - this.name = name; + this.name = name; this.fieldIndex = base.fieldIndex; - this.slot = base.slot; - this.type = base.type; - this.useCount = base.useCount; + this.slot = base.slot; + this.type = base.type; + this.useCount = base.useCount; + this.range = base.range; } private static String align(final String string, final int max) { @@ -276,7 +283,7 @@ @Override public String toString() { - final StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(); sb.append(name). append(' '). @@ -410,6 +417,22 @@ } /** + * Get the range for this symbol + * @return range for symbol + */ + public Range getRange() { + return range; + } + + /** + * Set the range for this symbol + * @param range range + */ + public void setRange(final Range range) { + this.range = range; + } + + /** * Check if this symbol is a function parameter of known * narrowest type * @return true if parameter diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/TernaryNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/TernaryNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/TernaryNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -63,7 +63,7 @@ } @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterTernaryNode(this)) { final Node newLhs = lhs().accept(visitor); final Node newRhs = rhs().accept(visitor); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/ThrowNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/ThrowNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/ThrowNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -36,6 +36,11 @@ /** Exception expression. */ private final Node expression; + private final int flags; + + /** Is this block a synthethic rethrow created by finally inlining? */ + public static final int IS_SYNTHETIC_RETHROW = 1; + /** * Constructor * @@ -43,15 +48,18 @@ * @param token token * @param finish finish * @param expression expression to throw + * @param flags flags */ - public ThrowNode(final int lineNumber, final long token, final int finish, final Node expression) { + public ThrowNode(final int lineNumber, final long token, final int finish, final Node expression, final int flags) { super(lineNumber, token, finish); this.expression = expression; + this.flags = flags; } - private ThrowNode(final ThrowNode node, final Node expression) { + private ThrowNode(final ThrowNode node, final Node expression, final int flags) { super(node); this.expression = expression; + this.flags = flags; } @Override @@ -64,7 +72,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterThrowNode(this)) { return visitor.leaveThrowNode(setExpression(expression.accept(visitor))); } @@ -98,7 +106,17 @@ if (this.expression == expression) { return this; } - return new ThrowNode(this, expression); + return new ThrowNode(this, expression, flags); + } + + /** + * Is this a throw a synthetic rethrow in a synthetic catch-all block + * created when inlining finally statements? In that case we never + * wrap whatever is thrown into an ECMAException, just rethrow it. + * @return true if synthetic throw node + */ + public boolean isSyntheticRethrow() { + return (flags & IS_SYNTHETIC_RETHROW) == IS_SYNTHETIC_RETHROW; } } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/TryNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/TryNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/TryNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -106,7 +106,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterTryNode(this)) { // Need to do finallybody first for termination analysis. TODO still necessary? final Block newFinallyBody = finallyBody == null ? null : (Block)finallyBody.accept(visitor); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/UnaryNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/UnaryNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/UnaryNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -29,7 +29,6 @@ import static jdk.nashorn.internal.parser.TokenType.CONVERT; import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX; import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX; - import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.visitor.NodeVisitor; @@ -121,7 +120,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterUnaryNode(this)) { return visitor.leaveUnaryNode(setRHS(rhs.accept(visitor))); } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/VarNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/VarNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/VarNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -121,7 +121,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final NodeVisitor visitor) { if (visitor.enterVarNode(this)) { final IdentNode newName = (IdentNode)name.accept(visitor); final Node newInit = init == null ? null : init.accept(visitor); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/WhileNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/WhileNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/WhileNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -75,7 +75,7 @@ } @Override - protected Node accept(final LexicalContext lc, final NodeVisitor visitor) { + protected Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterWhileNode(this)) { if (isDoWhile()) { return visitor.leaveWhileNode( diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/WithNode.java --- a/nashorn/src/jdk/nashorn/internal/ir/WithNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/WithNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -64,7 +64,7 @@ * @param visitor IR navigating visitor. */ @Override - public Node accept(final LexicalContext lc, final NodeVisitor visitor) { + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { if (visitor.enterWithNode(this)) { return visitor.leaveWithNode( setExpression(lc, expression.accept(visitor)). diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java --- a/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java Wed Jul 05 18:57:52 2017 +0200 @@ -45,6 +45,7 @@ import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.IndexNode; import jdk.nashorn.internal.ir.LabelNode; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.ObjectNode; @@ -74,7 +75,8 @@ /** * This IR writer produces a JSON string that represents AST as a JSON string. */ -public final class JSONWriter extends NodeVisitor { +public final class JSONWriter extends NodeVisitor { + /** * Returns AST as JSON compatible string. * @@ -867,7 +869,8 @@ // Internals below private JSONWriter(final boolean includeLocation) { - this.buf = new StringBuilder(); + super(new LexicalContext()); + this.buf = new StringBuilder(); this.includeLocation = includeLocation; } @@ -963,7 +966,7 @@ objectStart("loc"); // source name - final Source src = getLexicalContext().getCurrentFunction().getSource(); + final Source src = lc.getCurrentFunction().getSource(); property("source", src.getName()); comma(); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java --- a/nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java Wed Jul 05 18:57:52 2017 +0200 @@ -36,6 +36,7 @@ import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.LabelNode; +import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.SplitNode; import jdk.nashorn.internal.ir.Statement; @@ -53,7 +54,7 @@ * * see the flags --print-parse and --print-lower-parse */ -public final class PrintVisitor extends NodeVisitor { +public final class PrintVisitor extends NodeVisitor { /** Tab width */ private static final int TABWIDTH = 4; @@ -84,6 +85,7 @@ * @param printLineNumbers should line number nodes be included in the output? */ public PrintVisitor(final boolean printLineNumbers) { + super(new LexicalContext()); this.EOLN = System.lineSeparator(); this.sb = new StringBuilder(); this.printLineNumbers = printLineNumbers; diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java --- a/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Wed Jul 05 18:57:52 2017 +0200 @@ -32,21 +32,15 @@ /** * Like NodeVisitor but navigating further into operators. + * @param Lexical context class for this NodeOperatorVisitor */ -public class NodeOperatorVisitor extends NodeVisitor { - /** - * Constructor - */ - public NodeOperatorVisitor() { - super(); - } - +public class NodeOperatorVisitor extends NodeVisitor { /** * Constructor * * @param lc a custom lexical context */ - public NodeOperatorVisitor(final LexicalContext lc) { + public NodeOperatorVisitor(final T lc) { super(lc); } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java --- a/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java Wed Jul 05 18:57:52 2017 +0200 @@ -60,23 +60,18 @@ /** * Visitor used to navigate the IR. + * @param lexical context class used by this visitor */ -public abstract class NodeVisitor { - private final LexicalContext lc; - - /** - * Constructor - */ - public NodeVisitor() { - this(new LexicalContext()); - } +public abstract class NodeVisitor { + /** lexical context in use */ + protected final T lc; /** * Constructor * * @param lc a custom lexical context */ - public NodeVisitor(final LexicalContext lc) { + public NodeVisitor(final T lc) { this.lc = lc; } @@ -84,7 +79,7 @@ * Get the lexical context of this node visitor * @return lexical context */ - public LexicalContext getLexicalContext() { + public T getLexicalContext() { return lc; } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java --- a/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java Wed Jul 05 18:57:52 2017 +0200 @@ -59,11 +59,6 @@ } @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE) - public static Object BYTES_PER_ELEMENT(final Object self) { - return ((ArrayBufferView)self).bytesPerElement(); - } - - @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE) public static Object buffer(final Object self) { return ((ArrayDataImpl)((ArrayBufferView)self).getArray()).buffer; } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/DateParser.java --- a/nashorn/src/jdk/nashorn/internal/objects/DateParser.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/objects/DateParser.java Wed Jul 05 18:57:52 2017 +0200 @@ -32,6 +32,7 @@ import static java.lang.Character.UPPERCASE_LETTER; import java.util.HashMap; +import java.util.Locale; /** * JavaScript date parser. This class first tries to parse a date string @@ -486,7 +487,7 @@ while (pos < limit && isAsciiLetter(string.charAt(pos))) { pos++; } - final String key = string.substring(start, pos).toLowerCase(); + final String key = string.substring(start, pos).toLowerCase(Locale.ENGLISH); final Name name = names.get(key); // then advance to end of name while (pos < length && isAsciiLetter(string.charAt(pos))) { @@ -683,7 +684,7 @@ Name(final String name, final int type, final int value) { assert name != null; - assert name.equals(name.toLowerCase()); + assert name.equals(name.toLowerCase(Locale.ENGLISH)); this.name = name; // use first three characters as lookup key diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/NativeArguments.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArguments.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArguments.java Wed Jul 05 18:57:52 2017 +0200 @@ -603,6 +603,11 @@ } } + @Override + public Object getLength() { + return length; + } + private Object getArgumentsLength() { return length; } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/NativeArray.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java Wed Jul 05 18:57:52 2017 +0200 @@ -754,25 +754,11 @@ final Object obj = Global.toObject(self); final ScriptObject sobj = (ScriptObject)obj; final long len = JSType.toUint32(sobj.getLength()); - final double startNum = JSType.toNumber(start); - final long relativeStartUint32 = JSType.toUint32(startNum); - final long relativeStart = JSType.toInteger(startNum); - - long k = relativeStart < 0 ? - Math.max(len + relativeStart, 0) : - Math.min( - Math.max(relativeStartUint32, relativeStart), - len); + final long relativeStart = JSType.toLong(start); + final long relativeEnd = (end == ScriptRuntime.UNDEFINED) ? len : JSType.toLong(end); - final double endNum = (end == ScriptRuntime.UNDEFINED)? Double.NaN : JSType.toNumber(end); - final long relativeEndUint32 = (end == ScriptRuntime.UNDEFINED)? len : JSType.toUint32(endNum); - final long relativeEnd = (end == ScriptRuntime.UNDEFINED)? len : JSType.toInteger(endNum); - - final long finale = relativeEnd < 0 ? - Math.max(len + relativeEnd, 0) : - Math.min( - Math.max(relativeEndUint32, relativeEnd), - len); + long k = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len); + final long finale = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len); if (k >= finale) { return new NativeArray(0); @@ -909,21 +895,10 @@ final ScriptObject sobj = (ScriptObject)obj; final boolean strict = Global.isStrict(); final long len = JSType.toUint32(sobj.getLength()); - final double startNum = JSType.toNumber(start); - final long relativeStartUint32 = JSType.toUint32(startNum); - final long relativeStart = JSType.toInteger(startNum); + final long relativeStart = JSType.toLong(start); - //TODO: workaround overflow of relativeStart for start > Integer.MAX_VALUE - final long actualStart = relativeStart < 0 ? - Math.max(len + relativeStart, 0) : - Math.min( - Math.max(relativeStartUint32, relativeStart), - len); - - final long actualDeleteCount = - Math.min( - Math.max(JSType.toInteger(deleteCount), 0), - len - actualStart); + final long actualStart = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len); + final long actualDeleteCount = Math.min(Math.max(JSType.toLong(deleteCount), 0), len - actualStart); final NativeArray array = new NativeArray(actualDeleteCount); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/NativeDate.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java Wed Jul 05 18:57:52 2017 +0200 @@ -770,7 +770,7 @@ nd.setTime(NaN); return nd.getTime(); } - int yearInt = JSType.toInteger(yearNum); + int yearInt = (int)yearNum; if (0 <= yearInt && yearInt <= 99) { yearInt += 1900; } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java Wed Jul 05 18:57:52 2017 +0200 @@ -28,7 +28,9 @@ import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; +import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; +import jdk.nashorn.internal.objects.annotations.Where; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.arrays.ArrayData; @@ -38,7 +40,12 @@ */ @ScriptClass("Float32Array") public final class NativeFloat32Array extends ArrayBufferView { - private static final int BYTES_PER_ELEMENT = 4; + /** + * The size in bytes of each element in the array. + */ + @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR) + public static final int BYTES_PER_ELEMENT = 4; + private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) { diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java Wed Jul 05 18:57:52 2017 +0200 @@ -28,7 +28,9 @@ import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; +import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; +import jdk.nashorn.internal.objects.annotations.Where; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.arrays.ArrayData; @@ -38,7 +40,12 @@ */ @ScriptClass("Float64Array") public final class NativeFloat64Array extends ArrayBufferView { - private static final int BYTES_PER_ELEMENT = 8; + /** + * The size in bytes of each element in the array. + */ + @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR) + public static final int BYTES_PER_ELEMENT = 8; + private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) { diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java Wed Jul 05 18:57:52 2017 +0200 @@ -28,7 +28,9 @@ import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; +import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; +import jdk.nashorn.internal.objects.annotations.Where; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.arrays.ArrayData; @@ -37,7 +39,12 @@ */ @ScriptClass("Int16Array") public final class NativeInt16Array extends ArrayBufferView { - private static final int BYTES_PER_ELEMENT = 2; + /** + * The size in bytes of each element in the array. + */ + @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR) + public static final int BYTES_PER_ELEMENT = 2; + private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) { diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java Wed Jul 05 18:57:52 2017 +0200 @@ -28,7 +28,9 @@ import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; +import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; +import jdk.nashorn.internal.objects.annotations.Where; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.arrays.ArrayData; @@ -37,7 +39,12 @@ */ @ScriptClass("Int32Array") public final class NativeInt32Array extends ArrayBufferView { - private static final int BYTES_PER_ELEMENT = 4; + /** + * The size in bytes of each element in the array. + */ + @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR) + public static final int BYTES_PER_ELEMENT = 4; + private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) { diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java Wed Jul 05 18:57:52 2017 +0200 @@ -28,7 +28,9 @@ import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; +import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; +import jdk.nashorn.internal.objects.annotations.Where; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.arrays.ArrayData; @@ -37,7 +39,12 @@ */ @ScriptClass("Int8Array") public final class NativeInt8Array extends ArrayBufferView { - private static final int BYTES_PER_ELEMENT = 1; + /** + * The size in bytes of each element in the array. + */ + @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR) + public static final int BYTES_PER_ELEMENT = 1; + private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) { @Override public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) { diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/NativeJava.java --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java Wed Jul 05 18:57:52 2017 +0200 @@ -30,6 +30,8 @@ import java.lang.reflect.Array; import java.util.Collection; +import java.util.Deque; +import java.util.List; import jdk.internal.dynalink.beans.StaticClass; import jdk.internal.dynalink.support.TypeUtilities; import jdk.nashorn.internal.objects.annotations.Attribute; @@ -37,6 +39,7 @@ import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.objects.annotations.Where; import jdk.nashorn.internal.runtime.JSType; +import jdk.nashorn.internal.runtime.ListAdapter; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; @@ -240,39 +243,56 @@ } /** - * Given a JavaScript array and a Java type, returns a Java array with the same initial contents, and with the - * specified component type. Example: + * Given a script object and a Java type, converts the script object into the desired Java type. Currently it + * performs shallow creation of Java arrays, as well as wrapping of objects in Lists and Dequeues. Example: *
          * var anArray = [1, "13", false]
    -     * var javaIntArray = Java.toJavaArray(anArray, "int")
    +     * var javaIntArray = Java.to(anArray, "int[]")
          * print(javaIntArray[0]) // prints 1
          * print(javaIntArray[1]) // prints 13, as string "13" was converted to number 13 as per ECMAScript ToNumber conversion
          * print(javaIntArray[2]) // prints 0, as boolean false was converted to number 0 as per ECMAScript ToNumber conversion
          * 
    * @param self not used - * @param objArray the JavaScript array. Can be null. - * @param objType either a {@link #type(Object, Object) type object} or a String describing the component type of - * the Java array to create. Can not be null. If undefined, Object is assumed (allowing the argument to be omitted). - * @return a Java array with the copy of JavaScript array's contents, converted to the appropriate Java component - * type. Returns null if objArray is null. + * @param obj the script object. Can be null. + * @param objType either a {@link #type(Object, Object) type object} or a String describing the type of the Java + * object to create. Can not be null. If undefined, a "default" conversion is presumed (allowing the argument to be + * omitted). + * @return a Java object whose value corresponds to the original script object's value. Specifically, for array + * target types, returns a Java array of the same type with contents converted to the array's component type. Does + * not recursively convert for multidimensional arrays. For {@link List} or {@link Deque}, returns a live wrapper + * around the object, see {@link ListAdapter} for details. Returns null if obj is null. * @throws ClassNotFoundException if the class described by objType is not found */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object toJavaArray(final Object self, final Object objArray, final Object objType) throws ClassNotFoundException { - final StaticClass componentType = - objType instanceof StaticClass ? - (StaticClass)objType : - objType == UNDEFINED ? - StaticClass.forClass(Object.class) : - type(objType); - - if (objArray == null) { + public static Object to(final Object self, final Object obj, final Object objType) throws ClassNotFoundException { + if (obj == null) { return null; } - Global.checkObject(objArray); + Global.checkObject(obj); - return ((ScriptObject)objArray).getArray().asArrayOfType(componentType.getRepresentedClass()); + final Class targetClass; + if(objType == UNDEFINED) { + targetClass = Object[].class; + } else { + final StaticClass targetType; + if(objType instanceof StaticClass) { + targetType = (StaticClass)objType; + } else { + targetType = type(objType); + } + targetClass = targetType.getRepresentedClass(); + } + + if(targetClass.isArray()) { + return ((ScriptObject)obj).getArray().asArrayOfType(targetClass.getComponentType()); + } + + if(targetClass == List.class || targetClass == Deque.class) { + return new ListAdapter((ScriptObject)obj); + } + + throw typeError("unsupported.java.to.type", targetClass.getName()); } /** @@ -283,7 +303,7 @@ *
          * var File = Java.type("java.io.File")
          * var listHomeDir = new File("~").listFiles()
    -     * var jsListHome = Java.toJavaScriptArray(listHomeDir)
    +     * var jsListHome = Java.from(listHomeDir)
          * var jpegModifiedDates = jsListHome
          *     .filter(function(val) { return val.getName().endsWith(".jpg") })
          *     .map(function(val) { return val.lastModified() })
    @@ -294,7 +314,7 @@
          * null.
          */
         @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    -    public static Object toJavaScriptArray(final Object self, final Object objArray) {
    +    public static Object from(final Object self, final Object objArray) {
             if (objArray == null) {
                 return null;
             } else if (objArray instanceof Collection) {
    diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/NativeMath.java
    --- a/nashorn/src/jdk/nashorn/internal/objects/NativeMath.java	Thu May 30 10:58:13 2013 -0700
    +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeMath.java	Wed Jul 05 18:57:52 2017 +0200
    @@ -611,13 +611,11 @@
          */
         @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
         public static Object round(final Object self, final Object x) {
    -        if (GlobalFunctions.isNaN(self, x)) {
    -            return Double.NaN;
    -        } else if (!GlobalFunctions.isFinite(self, x)) {
    -            return x;
    +        final double d = JSType.toNumber(x);
    +        if (Math.getExponent(d) >= 52) {
    +            return d;
             }
    -
    -        return Math.round(JSType.toNumber(x));
    +        return Math.copySign(Math.floor(d + 0.5), d);
         }
     
         /**
    diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/NativeString.java
    --- a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java	Thu May 30 10:58:13 2013 -0700
    +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java	Wed Jul 05 18:57:52 2017 +0200
    @@ -38,6 +38,7 @@
     import java.util.Arrays;
     import java.util.LinkedList;
     import java.util.List;
    +import java.util.Locale;
     import jdk.internal.dynalink.CallSiteDescriptor;
     import jdk.internal.dynalink.linker.GuardedInvocation;
     import jdk.internal.dynalink.linker.LinkRequest;
    @@ -630,17 +631,24 @@
     
             final String str       = checkObjectToString(self);
             final String searchStr = JSType.toString(search);
    +        final int length       = str.length();
     
    -        int from;
    +        int end;
     
             if (pos == UNDEFINED) {
    -            from = str.length();
    +            end = length;
             } else {
                 final double numPos = JSType.toNumber(pos);
    -            from = !Double.isNaN(numPos) ? (int)numPos : (int)Double.POSITIVE_INFINITY;
    +            end = Double.isNaN(numPos) ? length : (int)numPos;
    +            if (end < 0) {
    +                end = 0;
    +            } else if (end > length) {
    +                end = length;
    +            }
             }
     
    -        return str.lastIndexOf(searchStr, from);
    +
    +        return str.lastIndexOf(searchStr, end);
         }
     
         /**
    @@ -997,7 +1005,7 @@
          */
         @Function(attributes = Attribute.NOT_ENUMERABLE)
         public static Object toLowerCase(final Object self) {
    -        return checkObjectToString(self).toLowerCase();
    +        return checkObjectToString(self).toLowerCase(Locale.ROOT);
         }
     
         /**
    @@ -1017,7 +1025,7 @@
          */
         @Function(attributes = Attribute.NOT_ENUMERABLE)
         public static Object toUpperCase(final Object self) {
    -        return checkObjectToString(self).toUpperCase();
    +        return checkObjectToString(self).toUpperCase(Locale.ROOT);
         }
     
         /**
    diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java
    --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java	Thu May 30 10:58:13 2013 -0700
    +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java	Wed Jul 05 18:57:52 2017 +0200
    @@ -28,7 +28,9 @@
     import jdk.nashorn.internal.objects.annotations.Attribute;
     import jdk.nashorn.internal.objects.annotations.Constructor;
     import jdk.nashorn.internal.objects.annotations.Function;
    +import jdk.nashorn.internal.objects.annotations.Property;
     import jdk.nashorn.internal.objects.annotations.ScriptClass;
    +import jdk.nashorn.internal.objects.annotations.Where;
     import jdk.nashorn.internal.runtime.ScriptObject;
     import jdk.nashorn.internal.runtime.arrays.ArrayData;
     
    @@ -37,7 +39,12 @@
      */
     @ScriptClass("Uint16Array")
     public final class NativeUint16Array extends ArrayBufferView {
    -    private static final int BYTES_PER_ELEMENT = 2;
    +    /**
    +     * The size in bytes of each element in the array.
    +     */
    +    @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
    +    public static final int BYTES_PER_ELEMENT = 2;
    +
         private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
             @Override
             public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
    diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java
    --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java	Thu May 30 10:58:13 2013 -0700
    +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java	Wed Jul 05 18:57:52 2017 +0200
    @@ -28,7 +28,9 @@
     import jdk.nashorn.internal.objects.annotations.Attribute;
     import jdk.nashorn.internal.objects.annotations.Constructor;
     import jdk.nashorn.internal.objects.annotations.Function;
    +import jdk.nashorn.internal.objects.annotations.Property;
     import jdk.nashorn.internal.objects.annotations.ScriptClass;
    +import jdk.nashorn.internal.objects.annotations.Where;
     import jdk.nashorn.internal.runtime.JSType;
     import jdk.nashorn.internal.runtime.ScriptObject;
     import jdk.nashorn.internal.runtime.arrays.ArrayData;
    @@ -38,7 +40,12 @@
      */
     @ScriptClass("Uint32Array")
     public final class NativeUint32Array extends ArrayBufferView {
    -    private static final int BYTES_PER_ELEMENT = 4;
    +    /**
    +     * The size in bytes of each element in the array.
    +     */
    +    @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
    +    public static final int BYTES_PER_ELEMENT = 4;
    +
         private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
             @Override
             public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteBegin, final int length) {
    diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java
    --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java	Thu May 30 10:58:13 2013 -0700
    +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java	Wed Jul 05 18:57:52 2017 +0200
    @@ -28,7 +28,9 @@
     import jdk.nashorn.internal.objects.annotations.Attribute;
     import jdk.nashorn.internal.objects.annotations.Constructor;
     import jdk.nashorn.internal.objects.annotations.Function;
    +import jdk.nashorn.internal.objects.annotations.Property;
     import jdk.nashorn.internal.objects.annotations.ScriptClass;
    +import jdk.nashorn.internal.objects.annotations.Where;
     import jdk.nashorn.internal.runtime.ScriptObject;
     import jdk.nashorn.internal.runtime.arrays.ArrayData;
     
    @@ -37,7 +39,12 @@
      */
     @ScriptClass("Uint8Array")
     public final class NativeUint8Array extends ArrayBufferView {
    -    private static final int BYTES_PER_ELEMENT = 1;
    +    /**
    +     * The size in bytes of each element in the array.
    +     */
    +    @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
    +    public static final int BYTES_PER_ELEMENT = 1;
    +
         private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
             @Override
             public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
    diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
    --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Thu May 30 10:58:13 2013 -0700
    +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Wed Jul 05 18:57:52 2017 +0200
    @@ -28,7 +28,9 @@
     import jdk.nashorn.internal.objects.annotations.Attribute;
     import jdk.nashorn.internal.objects.annotations.Constructor;
     import jdk.nashorn.internal.objects.annotations.Function;
    +import jdk.nashorn.internal.objects.annotations.Property;
     import jdk.nashorn.internal.objects.annotations.ScriptClass;
    +import jdk.nashorn.internal.objects.annotations.Where;
     import jdk.nashorn.internal.runtime.JSType;
     import jdk.nashorn.internal.runtime.ScriptObject;
     import jdk.nashorn.internal.runtime.arrays.ArrayData;
    @@ -38,7 +40,12 @@
      */
     @ScriptClass("Uint8ClampedArray")
     public final class NativeUint8ClampedArray extends ArrayBufferView {
    -    private static final int BYTES_PER_ELEMENT = 1;
    +    /**
    +     * The size in bytes of each element in the array.
    +     */
    +    @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE, where = Where.CONSTRUCTOR)
    +    public static final int BYTES_PER_ELEMENT = 1;
    +
         private static final Factory FACTORY = new Factory(BYTES_PER_ELEMENT) {
             @Override
             public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
    diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/parser/Parser.java
    --- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java	Thu May 30 10:58:13 2013 -0700
    +++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java	Wed Jul 05 18:57:52 2017 +0200
    @@ -1537,7 +1537,7 @@
     
             endOfLine();
     
    -        appendStatement(new ThrowNode(throwLine, throwToken, finish, expression));
    +        appendStatement(new ThrowNode(throwLine, throwToken, finish, expression, 0));
         }
     
         /**
    @@ -1597,7 +1597,7 @@
                     try {
                         // Get CATCH body.
                         final Block catchBody = getBlock(true);
    -                    final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody);
    +                    final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody, 0);
                         appendStatement(catchNode);
                     } finally {
                         catchBlock = restoreBlock(catchBlock);
    diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/parser/TokenType.java
    --- a/nashorn/src/jdk/nashorn/internal/parser/TokenType.java	Thu May 30 10:58:13 2013 -0700
    +++ b/nashorn/src/jdk/nashorn/internal/parser/TokenType.java	Wed Jul 05 18:57:52 2017 +0200
    @@ -25,6 +25,7 @@
     
     package jdk.nashorn.internal.parser;
     
    +import java.util.Locale;
     import static jdk.nashorn.internal.parser.TokenKind.BINARY;
     import static jdk.nashorn.internal.parser.TokenKind.BRACKET;
     import static jdk.nashorn.internal.parser.TokenKind.FUTURE;
    @@ -249,7 +250,7 @@
         }
     
         public String getNameOrType() {
    -        return name == null ? super.name().toLowerCase() : name;
    +        return name == null ? super.name().toLowerCase(Locale.ENGLISH) : name;
         }
     
         public TokenType getNext() {
    diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Thu May 30 10:58:13 2013 -0700
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Wed Jul 05 18:57:52 2017 +0200
    @@ -75,7 +75,23 @@
     
         private static final MethodType[] ACCESSOR_GETTER_TYPES = new MethodType[NOOF_TYPES];
         private static final MethodType[] ACCESSOR_SETTER_TYPES = new MethodType[NOOF_TYPES];
    -    private static final MethodHandle SPILLGETTER = MH.asType(MH.getter(MethodHandles.lookup(), ScriptObject.class, "spill", Object[].class), Lookup.GET_OBJECT_TYPE);
    +    private static final MethodHandle SPILL_ELEMENT_GETTER;
    +    private static final MethodHandle SPILL_ELEMENT_SETTER;
    +
    +    private static final int SPILL_CACHE_SIZE = 8;
    +    private static final MethodHandle[] SPILL_ACCESSORS = new MethodHandle[SPILL_CACHE_SIZE * 2];
    +
    +    static {
    +        for (int i = 0; i < NOOF_TYPES; i++) {
    +            final Type type = ACCESSOR_TYPES.get(i);
    +            ACCESSOR_GETTER_TYPES[i] = MH.type(type.getTypeClass(), Object.class);
    +            ACCESSOR_SETTER_TYPES[i] = MH.type(void.class, Object.class, type.getTypeClass());
    +        }
    +
    +        final MethodHandle spillGetter = MH.getter(MethodHandles.lookup(), ScriptObject.class, "spill", Object[].class);
    +        SPILL_ELEMENT_GETTER = MH.filterArguments(MH.arrayElementGetter(Object[].class), 0, spillGetter);
    +        SPILL_ELEMENT_SETTER = MH.filterArguments(MH.arrayElementSetter(Object[].class), 0, spillGetter);
    +    }
     
         /** Seed getter for the primitive version of this field (in -Dnashorn.fields.dual=true mode) */
         private MethodHandle primitiveGetter;
    @@ -96,14 +112,6 @@
          */
         private Class currentType;
     
    -    static {
    -        for (int i = 0; i < NOOF_TYPES; i++) {
    -            final Type type = ACCESSOR_TYPES.get(i);
    -            ACCESSOR_GETTER_TYPES[i] = MH.type(type.getTypeClass(), Object.class);
    -            ACCESSOR_SETTER_TYPES[i] = MH.type(void.class, Object.class, type.getTypeClass());
    -        }
    -    }
    -
         /**
          * Delegate constructor. This is used when adding properties to the Global scope, which
          * is necessary for outermost levels in a script (the ScriptObject is represented by
    @@ -114,19 +122,31 @@
          * @param delegate  delegate script object to rebind receiver to
          */
         public AccessorProperty(final AccessorProperty property, final ScriptObject delegate) {
    -        this(property);
    -
    -        this.getters = new MethodHandle[NOOF_TYPES];
    +        super(property);
     
    -        this.primitiveGetter = bindTo(primitiveGetter, delegate);
    -        this.primitiveSetter = bindTo(primitiveSetter, delegate);
    -        this.objectGetter    = bindTo(objectGetter, delegate);
    -        this.objectSetter    = bindTo(objectSetter, delegate);
    +        this.primitiveGetter = bindTo(property.primitiveGetter, delegate);
    +        this.primitiveSetter = bindTo(property.primitiveSetter, delegate);
    +        this.objectGetter    = bindTo(property.objectGetter, delegate);
    +        this.objectSetter    = bindTo(property.objectSetter, delegate);
     
             setCurrentType(property.getCurrentType());
         }
     
         /**
    +     * Constructor for spill properties. Array getters and setters will be created on demand.
    +     *
    +     * @param key    the property key
    +     * @param flags  the property flags
    +     * @param slot   spill slot
    +     */
    +    public AccessorProperty(final String key, final int flags, final int slot) {
    +        super(key, flags, slot);
    +        assert (flags & IS_SPILL) == IS_SPILL;
    +
    +        setCurrentType(Object.class);
    +    }
    +
    +    /**
          * Constructor. Similar to the constructor with both primitive getters and setters, the difference
          * here being that only one getter and setter (setter is optional for non writable fields) is given
          * to the constructor, and the rest are created from those. Used e.g. by Nasgen classes
    @@ -268,7 +288,40 @@
         }
     
         @Override
    +    protected void setObjectValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict)  {
    +        if (isSpill()) {
    +            self.spill[getSlot()] = value;
    +        } else {
    +            try {
    +                getSetter(Object.class, self.getMap()).invokeExact((Object)self, value);
    +            } catch (final Error|RuntimeException e) {
    +                throw e;
    +            } catch (final Throwable e) {
    +                throw new RuntimeException(e);
    +            }
    +        }
    +    }
    +
    +    @Override
    +    protected Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
    +        if (isSpill()) {
    +            return self.spill[getSlot()];
    +        }
    +
    +        try {
    +            return getGetter(Object.class).invokeExact((Object)self);
    +        } catch (final Error|RuntimeException e) {
    +            throw e;
    +        } catch (final Throwable e) {
    +            throw new RuntimeException(e);
    +        }
    +    }
    +
    +    @Override
         public MethodHandle getGetter(final Class type) {
    +        if (isSpill() && objectGetter == null) {
    +            objectGetter = getSpillGetter();
    +        }
             final int i = getAccessorTypeIndex(type);
             if (getters[i] == null) {
                 getters[i] = debug(
    @@ -284,7 +337,7 @@
                     "get");
             }
     
    -        return isSpill() ? MH.filterArguments(getters[i], 0, SPILLGETTER) : getters[i];
    +        return getters[i];
         }
     
         private Property getWiderProperty(final Class type) {
    @@ -313,6 +366,9 @@
         }
     
         private MethodHandle generateSetter(final Class forType, final Class type) {
    +        if (isSpill() && objectSetter == null) {
    +            objectSetter = getSpillSetter();
    +        }
             MethodHandle mh = createSetter(forType, type, primitiveSetter, objectSetter);
             mh = MH.asType(mh, ACCESSOR_SETTER_TYPES[getAccessorTypeIndex(type)]); //has to be the case for invokeexact to work in ScriptObject
             mh = debug(mh, currentType, type, "set");
    @@ -343,7 +399,7 @@
                 mh = generateSetter(forType, type);
             }
     
    -        return isSpill() ? MH.filterArguments(mh, 0, SPILLGETTER) : mh;
    +        return mh;
         }
     
         @Override
    @@ -363,6 +419,30 @@
             setCurrentType(newType);
         }
     
    +    private MethodHandle getSpillGetter() {
    +        final int slot = getSlot();
    +        MethodHandle getter = slot < SPILL_CACHE_SIZE ? SPILL_ACCESSORS[slot * 2] : null;
    +        if (getter == null) {
    +            getter = MH.asType(MH.insertArguments(SPILL_ELEMENT_GETTER, 1, slot), Lookup.GET_OBJECT_TYPE);
    +            if (slot < SPILL_CACHE_SIZE) {
    +                SPILL_ACCESSORS[slot * 2] = getter;
    +            }
    +        }
    +        return getter;
    +    }
    +
    +    private MethodHandle getSpillSetter() {
    +        final int slot = getSlot();
    +        MethodHandle setter = slot < SPILL_CACHE_SIZE ? SPILL_ACCESSORS[slot * 2 + 1] : null;
    +        if (setter == null) {
    +            setter = MH.asType(MH.insertArguments(SPILL_ELEMENT_SETTER, 1, slot), Lookup.SET_OBJECT_TYPE);
    +            if (slot < SPILL_CACHE_SIZE) {
    +                SPILL_ACCESSORS[slot * 2 + 1] = setter;
    +            }
    +        }
    +        return setter;
    +    }
    +
         private static void finest(final String str) {
             if (DEBUG_FIELDS) {
                 LOG.finest(str);
    diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Thu May 30 10:58:13 2013 -0700
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Wed Jul 05 18:57:52 2017 +0200
    @@ -35,21 +35,27 @@
      */
     final class CompiledFunction implements Comparable {
     
    +    /** The method type may be more specific than the invoker, if. e.g.
    +     *  the invoker is guarded, and a guard with a generic object only
    +     *  fallback, while the target is more specific, we still need the
    +     *  more specific type for sorting */
    +    private final MethodType   type;
         private final MethodHandle invoker;
         private MethodHandle constructor;
     
    -    CompiledFunction(final MethodHandle invoker) {
    -        this(invoker, null);
    +    CompiledFunction(final MethodType type, final MethodHandle invoker) {
    +        this(type, invoker, null);
         }
     
    -    CompiledFunction(final MethodHandle invoker, final MethodHandle constructor) {
    -        this.invoker = invoker;
    -        this.constructor = constructor; //isConstructor
    +    CompiledFunction(final MethodType type, final MethodHandle invoker, final MethodHandle constructor) {
    +        this.type        = type;
    +        this.invoker     = invoker;
    +        this.constructor = constructor;
         }
     
         @Override
         public String toString() {
    -        return "";
    +        return "";
         }
     
         MethodHandle getInvoker() {
    @@ -69,7 +75,7 @@
         }
     
         MethodType type() {
    -        return invoker.type();
    +        return type;
         }
     
         @Override
    @@ -103,8 +109,8 @@
             return weight() > o.weight();
         }
     
    -    boolean moreGenericThan(final MethodType type) {
    -        return weight() > weight(type);
    +    boolean moreGenericThan(final MethodType mt) {
    +        return weight() > weight(mt);
         }
     
         /**
    @@ -112,15 +118,15 @@
          * It is compatible if the types are narrower than the invocation type so that
          * a semantically equivalent linkage can be performed.
          *
    -     * @param typesc
    +     * @param mt type to check against
          * @return
          */
    -    boolean typeCompatible(final MethodType type) {
    -        final Class[] wantedParams   = type.parameterArray();
    +    boolean typeCompatible(final MethodType mt) {
    +        final Class[] wantedParams   = mt.parameterArray();
             final Class[] existingParams = type().parameterArray();
     
             //if we are not examining a varargs type, the number of parameters must be the same
    -        if (wantedParams.length != existingParams.length && !isVarArgsType(type)) {
    +        if (wantedParams.length != existingParams.length && !isVarArgsType(mt)) {
                 return false;
             }
     
    diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java	Thu May 30 10:58:13 2013 -0700
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java	Wed Jul 05 18:57:52 2017 +0200
    @@ -35,7 +35,6 @@
      */
     
     public final class DebugLogger {
    -    @SuppressWarnings("NonConstantLogger")
         private final Logger  logger;
         private final boolean isEnabled;
     
    diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java	Thu May 30 10:58:13 2013 -0700
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java	Wed Jul 05 18:57:52 2017 +0200
    @@ -78,9 +78,9 @@
                 //only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor
                 //is too conservative a check. However, isConstructor(mh) always implies isConstructor param
                 assert isConstructor();
    -            code.add(new CompiledFunction(MH.insertArguments(mh, 0, false), composeConstructor(MH.insertArguments(mh, 0, true), needsCallee))); //make sure callee state can be determined when we reach constructor
    +            code.add(new CompiledFunction(mh.type(), MH.insertArguments(mh, 0, false), composeConstructor(MH.insertArguments(mh, 0, true), needsCallee))); //make sure callee state can be determined when we reach constructor
             } else {
    -            code.add(new CompiledFunction(mh));
    +            code.add(new CompiledFunction(mh.type(), mh));
             }
         }
     
    diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java	Thu May 30 10:58:13 2013 -0700
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java	Wed Jul 05 18:57:52 2017 +0200
    @@ -153,5 +153,24 @@
             return prototype.isScope();
         }
     
    +    /**
    +     * Get the property value from self as object.
    +     *
    +     * @return the property value
    +     */
    +    public Object getObjectValue() {
    +        return property.getObjectValue(getGetterReceiver(), getOwner());
    +    }
    +
    +    /**
    +     * Set the property value in self.
    +     *
    +     * @param value the new value
    +     * @param strict strict flag
    +     */
    +    public void setObjectValue(final Object value, final boolean strict) {
    +        property.setObjectValue(getSetterReceiver(), getOwner(), value, strict);
    +    }
    +
     }
     
    diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java	Thu May 30 10:58:13 2013 -0700
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java	Wed Jul 05 18:57:52 2017 +0200
    @@ -30,6 +30,7 @@
     
     import java.lang.invoke.MethodHandle;
     import java.lang.invoke.MethodHandles;
    +import java.util.Locale;
     
     /**
      * Utilities used by Global class.
    @@ -373,10 +374,10 @@
                 } else if (ch < 256) {
                     sb.append('%');
                     final byte b = (byte)ch;
    -                sb.append(Integer.toHexString(b & 0xFF).toUpperCase());
    +                sb.append(Integer.toHexString(b & 0xFF).toUpperCase(Locale.ENGLISH));
                 } else {
                     sb.append("%u");
    -                sb.append(Integer.toHexString(ch & 0xFFFF).toUpperCase());
    +                sb.append(Integer.toHexString(ch & 0xFFFF).toUpperCase(Locale.ENGLISH));
                 }
             }
     
    diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java	Thu May 30 10:58:13 2013 -0700
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java	Wed Jul 05 18:57:52 2017 +0200
    @@ -36,6 +36,8 @@
     import jdk.nashorn.internal.parser.JSONParser;
     import jdk.nashorn.internal.parser.TokenType;
     import jdk.nashorn.internal.runtime.linker.Bootstrap;
    +import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndexNoThrow;
    +import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
     
     /**
      * Utilities used by "JSON" object implementation.
    @@ -94,7 +96,7 @@
             if (reviver instanceof ScriptFunction) {
                 assert global instanceof GlobalObject;
                 final ScriptObject root = ((GlobalObject)global).newObject();
    -            root.set("", unfiltered, root.isStrictContext());
    +            root.addOwnProperty("", Property.WRITABLE_ENUMERABLE_CONFIGURABLE, unfiltered);
                 return walk(root, "", (ScriptFunction)reviver);
             }
             return unfiltered;
    @@ -115,7 +117,7 @@
                     if (newElement == ScriptRuntime.UNDEFINED) {
                         valueObj.delete(key, strict);
                     } else {
    -                    valueObj.set(key, newElement, strict);
    +                    setPropertyValue(valueObj, key, newElement, strict);
                     }
                 }
             }
    @@ -175,7 +177,9 @@
                     final PropertyNode pNode     = (PropertyNode) elem;
                     final Node         valueNode = pNode.getValue();
     
    -                object.set(pNode.getKeyName(), convertNode(global, valueNode), strict);
    +                final String name = pNode.getKeyName();
    +                final Object value = convertNode(global, valueNode);
    +                setPropertyValue(object, name, value, strict);
                 }
     
                 return object;
    @@ -188,6 +192,21 @@
             }
         }
     
    +    // add a new property if does not exist already, or else set old property
    +    private static void setPropertyValue(final ScriptObject sobj, final String name, final Object value, final boolean strict) {
    +        final int index = getArrayIndexNoThrow(name);
    +        if (isValidArrayIndex(index)) {
    +            // array index key
    +            sobj.defineOwnProperty(index, value);
    +        } else if (sobj.getMap().findProperty(name) != null) {
    +            // pre-existing non-inherited property, call set
    +            sobj.set(name, value, strict);
    +        } else {
    +            // add new property
    +            sobj.addOwnProperty(name, Property.WRITABLE_ENUMERABLE_CONFIGURABLE, value);
    +        }
    +    }
    +
         // does the given IR node represent a numeric array?
         private static boolean isNumericArray(final Node[] values) {
             for (final Node node : values) {
    diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/JSType.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java	Thu May 30 10:58:13 2013 -0700
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java	Wed Jul 05 18:57:52 2017 +0200
    @@ -28,6 +28,7 @@
     import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
     import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
     
    +import java.util.Locale;
     import jdk.internal.dynalink.beans.StaticClass;
     import jdk.nashorn.internal.codegen.CompilerConstants.Call;
     import jdk.nashorn.internal.parser.Lexer;
    @@ -111,7 +112,7 @@
          */
         public final String typeName() {
             // For NULL, "object" has to be returned!
    -        return ((this == NULL) ? OBJECT : this).name().toLowerCase();
    +        return ((this == NULL) ? OBJECT : this).name().toLowerCase(Locale.ENGLISH);
         }
     
         /**
    @@ -565,8 +566,11 @@
         }
     
         /**
    -     * JavaScript compliant Object to integer conversion
    -     * See ECMA 9.4 ToInteger
    +     * JavaScript compliant Object to integer conversion. See ECMA 9.4 ToInteger
    +     *
    +     * 

    Note that this returns {@link java.lang.Integer#MAX_VALUE} or {@link java.lang.Integer#MIN_VALUE} + * for double values that exceed the int range, including positive and negative Infinity. It is the + * caller's responsibility to handle such values correctly.

    * * @param obj an object * @return an integer @@ -576,8 +580,11 @@ } /** - * JavaScript compliant Object to long conversion - * See ECMA 9.4 ToInteger + * JavaScript compliant Object to long conversion. See ECMA 9.4 ToInteger + * + *

    Note that this returns {@link java.lang.Long#MAX_VALUE} or {@link java.lang.Long#MIN_VALUE} + * for double values that exceed the long range, including positive and negative Infinity. It is the + * caller's responsibility to handle such values correctly.

    * * @param obj an object * @return a long diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,337 @@ +package jdk.nashorn.internal.runtime; + +import java.util.AbstractList; +import java.util.Deque; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.NoSuchElementException; +import java.util.RandomAccess; +import jdk.nashorn.internal.runtime.linker.InvokeByName; + +/** + * An adapter that can wrap any ECMAScript Array-like object (that adheres to the array rules for the property + * {@code length} and having conforming {@code push}, {@code pop}, {@code shift}, {@code unshift}, and {@code splice} + * methods) and expose it as both a Java list and double-ended queue. While script arrays aren't necessarily efficient + * as dequeues, it's still slightly more efficient to be able to translate dequeue operations into pushes, pops, shifts, + * and unshifts, than to blindly translate all list's add/remove operations into splices. Also, it is conceivable that a + * custom script object that implements an Array-like API can have a background data representation that is optimized + * for dequeue-like access. Note that with ECMAScript arrays, {@code push} and {@pop} operate at the end of the array, + * while in Java {@code Deque} they operate on the front of the queue and as such the Java dequeue {@link #push(Object)} + * and {@link #pop()} operations will translate to {@code unshift} and {@code shift} script operations respectively, + * while {@link #addLast(Object)} and {@link #removeLast()} will translate to {@code push} and {@code pop}. + */ +public class ListAdapter extends AbstractList implements RandomAccess, Deque { + // These add to the back and front of the list + private static final InvokeByName PUSH = new InvokeByName("push", ScriptObject.class, void.class, Object.class); + private static final InvokeByName UNSHIFT = new InvokeByName("unshift", ScriptObject.class, void.class, Object.class); + + // These remove from the back and front of the list + private static final InvokeByName POP = new InvokeByName("pop", ScriptObject.class, Object.class); + private static final InvokeByName SHIFT = new InvokeByName("shift", ScriptObject.class, Object.class); + + // These insert and remove in the middle of the list + private static final InvokeByName SPLICE_ADD = new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class, Object.class); + private static final InvokeByName SPLICE_REMOVE = new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class); + + private final ScriptObject obj; + + /** + * Creates a new list wrapper for the specified script object. + * @param obj script the object to wrap + */ + public ListAdapter(ScriptObject obj) { + this.obj = obj; + } + + @Override + public int size() { + return JSType.toInt32(obj.getLength()); + } + + @Override + public Object get(int index) { + checkRange(index); + return obj.get(index); + } + + @Override + public Object set(int index, Object element) { + checkRange(index); + final Object prevValue = get(index); + obj.set(index, element, false); + return prevValue; + } + + private void checkRange(int index) { + if(index < 0 || index >= size()) { + throw invalidIndex(index); + } + } + + @Override + public void push(Object e) { + addFirst(e); + } + + @Override + public boolean add(Object e) { + addLast(e); + return true; + } + + @Override + public void addFirst(Object e) { + try { + final Object fn = UNSHIFT.getGetter().invokeExact(obj); + checkFunction(fn, UNSHIFT); + UNSHIFT.getInvoker().invokeExact(fn, obj, e); + } catch(RuntimeException | Error ex) { + throw ex; + } catch(Throwable t) { + throw new RuntimeException(t); + } + } + + @Override + public void addLast(Object e) { + try { + final Object fn = PUSH.getGetter().invokeExact(obj); + checkFunction(fn, PUSH); + PUSH.getInvoker().invokeExact(fn, obj, e); + } catch(RuntimeException | Error ex) { + throw ex; + } catch(Throwable t) { + throw new RuntimeException(t); + } + } + + @Override + public void add(int index, Object e) { + try { + if(index < 0) { + throw invalidIndex(index); + } else if(index == 0) { + addFirst(e); + } else { + final int size = size(); + if(index < size) { + final Object fn = SPLICE_ADD.getGetter().invokeExact(obj); + checkFunction(fn, SPLICE_ADD); + SPLICE_ADD.getInvoker().invokeExact(fn, obj, index, 0, e); + } else if(index == size) { + addLast(e); + } else { + throw invalidIndex(index); + } + } + } catch(RuntimeException | Error ex) { + throw ex; + } catch(Throwable t) { + throw new RuntimeException(t); + } + } + private static void checkFunction(Object fn, InvokeByName invoke) { + if(!(fn instanceof ScriptFunction)) { + throw new UnsupportedOperationException("The script object doesn't have a function named " + invoke.getName()); + } + } + + private static IndexOutOfBoundsException invalidIndex(int index) { + return new IndexOutOfBoundsException(String.valueOf(index)); + } + + @Override + public boolean offer(Object e) { + return offerLast(e); + } + + @Override + public boolean offerFirst(Object e) { + addFirst(e); + return true; + } + + @Override + public boolean offerLast(Object e) { + addLast(e); + return true; + } + + @Override + public Object pop() { + return removeFirst(); + } + + @Override + public Object remove() { + return removeFirst(); + } + + @Override + public Object removeFirst() { + checkNonEmpty(); + return invokeShift(); + } + + @Override + public Object removeLast() { + checkNonEmpty(); + return invokePop(); + } + + private void checkNonEmpty() { + if(isEmpty()) { + throw new NoSuchElementException(); + } + } + + @Override + public Object remove(int index) { + if(index < 0) { + throw invalidIndex(index); + } else if (index == 0) { + return invokeShift(); + } else { + final int maxIndex = size() - 1; + if(index < maxIndex) { + final Object prevValue = get(index); + invokeSpliceRemove(index, 1); + return prevValue; + } else if(index == maxIndex) { + return invokePop(); + } else { + throw invalidIndex(index); + } + } + } + + private Object invokeShift() { + try { + final Object fn = SHIFT.getGetter().invokeExact(obj); + checkFunction(fn, SHIFT); + return SHIFT.getInvoker().invokeExact(fn, obj); + } catch(RuntimeException | Error ex) { + throw ex; + } catch(Throwable t) { + throw new RuntimeException(t); + } + } + + private Object invokePop() { + try { + final Object fn = POP.getGetter().invokeExact(obj); + checkFunction(fn, POP); + return POP.getInvoker().invokeExact(fn, obj); + } catch(RuntimeException | Error ex) { + throw ex; + } catch(Throwable t) { + throw new RuntimeException(t); + } + } + + @Override + protected void removeRange(int fromIndex, int toIndex) { + invokeSpliceRemove(fromIndex, toIndex - fromIndex); + } + + private void invokeSpliceRemove(int fromIndex, int count) { + try { + final Object fn = SPLICE_REMOVE.getGetter().invokeExact(obj); + checkFunction(fn, SPLICE_REMOVE); + SPLICE_REMOVE.getInvoker().invokeExact(fn, obj, fromIndex, count); + } catch(RuntimeException | Error ex) { + throw ex; + } catch(Throwable t) { + throw new RuntimeException(t); + } + } + + @Override + public Object poll() { + return pollFirst(); + } + + @Override + public Object pollFirst() { + return isEmpty() ? null : invokeShift(); + } + + @Override + public Object pollLast() { + return isEmpty() ? null : invokePop(); + } + + @Override + public Object peek() { + return peekFirst(); + } + + @Override + public Object peekFirst() { + return isEmpty() ? null : get(0); + } + + @Override + public Object peekLast() { + return isEmpty() ? null : get(size() - 1); + } + + @Override + public Object element() { + return getFirst(); + } + + @Override + public Object getFirst() { + checkNonEmpty(); + return get(0); + } + + @Override + public Object getLast() { + checkNonEmpty(); + return get(size() - 1); + } + + @Override + public Iterator descendingIterator() { + final ListIterator it = listIterator(size()); + return new Iterator() { + @Override + public boolean hasNext() { + return it.hasPrevious(); + } + + @Override + public Object next() { + return it.previous(); + } + + @Override + public void remove() { + it.remove(); + } + }; + } + + @Override + public boolean removeFirstOccurrence(Object o) { + return removeOccurrence(o, iterator()); + } + + @Override + public boolean removeLastOccurrence(Object o) { + return removeOccurrence(o, descendingIterator()); + } + + private static boolean removeOccurrence(Object o, Iterator it) { + while(it.hasNext()) { + final Object e = it.next(); + if(o == null ? e == null : o.equals(e)) { + it.remove(); + return true; + } + } + return false; + } +} diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/Logging.java --- a/nashorn/src/jdk/nashorn/internal/runtime/Logging.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/Logging.java Wed Jul 05 18:57:52 2017 +0200 @@ -26,6 +26,7 @@ package jdk.nashorn.internal.runtime; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.logging.ConsoleHandler; @@ -117,7 +118,7 @@ if ("".equals(value)) { level = Level.INFO; } else { - level = Level.parse(value.toUpperCase()); + level = Level.parse(value.toUpperCase(Locale.ENGLISH)); } final String name = Logging.lastPart(key); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java --- a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java Wed Jul 05 18:57:52 2017 +0200 @@ -25,10 +25,16 @@ package jdk.nashorn.internal.runtime; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.beans.StaticClass; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.support.Guards; +import jdk.nashorn.internal.lookup.MethodHandleFactory; +import jdk.nashorn.internal.lookup.MethodHandleFunctionality; import jdk.nashorn.internal.objects.NativeJava; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Function; @@ -65,6 +71,10 @@ * */ public final class NativeJavaPackage extends ScriptObject { + private static final MethodHandleFunctionality MH = MethodHandleFactory.getFunctionality(); + private static final MethodHandle CLASS_NOT_FOUND = findOwnMH("classNotFound", Void.TYPE, NativeJavaPackage.class); + private static final MethodHandle TYPE_GUARD = Guards.getClassGuard(NativeJavaPackage.class); + /** Full name of package (includes path.) */ private final String name; @@ -123,6 +133,30 @@ return super.getDefaultValue(hint); } + @Override + protected GuardedInvocation findNewMethod(CallSiteDescriptor desc) { + return createClassNotFoundInvocation(desc); + } + + @Override + protected GuardedInvocation findCallMethod(CallSiteDescriptor desc, LinkRequest request) { + return createClassNotFoundInvocation(desc); + } + + private static GuardedInvocation createClassNotFoundInvocation(final CallSiteDescriptor desc) { + // If NativeJavaPackage is invoked either as a constructor or as a function, throw a ClassNotFoundException as + // we can assume the user attempted to instantiate a non-existent class. + final MethodType type = desc.getMethodType(); + return new GuardedInvocation( + MH.dropArguments(CLASS_NOT_FOUND, 1, type.parameterList().subList(1, type.parameterCount())), + type.parameterType(0) == NativeJavaPackage.class ? null : TYPE_GUARD); + } + + @SuppressWarnings("unused") + private static void classNotFound(final NativeJavaPackage pkg) throws ClassNotFoundException { + throw new ClassNotFoundException(pkg.name); + } + /** * "No such property" call placeholder. * @@ -188,4 +222,7 @@ return noSuchProperty(desc, request); } + private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { + return MH.findStatic(MethodHandles.lookup(), NativeJavaPackage.class, name, MH.type(rtype, types)); + } } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/Property.java --- a/nashorn/src/jdk/nashorn/internal/runtime/Property.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/Property.java Wed Jul 05 18:57:52 2017 +0200 @@ -52,6 +52,9 @@ * we can use leave flag byte initialized with (the default) zero value. */ + /** Mask for property being both writable, enumerable and configurable */ + public static final int WRITABLE_ENUMERABLE_CONFIGURABLE = 0b0000_0000_0000; + /** ECMA 8.6.1 - Is this property not writable? */ public static final int NOT_WRITABLE = 0b0000_0000_0001; @@ -352,6 +355,27 @@ } /** + * Set the value of this property in {@code owner}. This allows to bypass creation of the + * setter MethodHandle for spill and user accessor properties. + * + * @param self the this object + * @param owner the owner object + * @param value the new property value + * @param strict is this a strict setter? + */ + protected abstract void setObjectValue(ScriptObject self, ScriptObject owner, Object value, boolean strict); + + /** + * Set the Object value of this property from {@code owner}. This allows to bypass creation of the + * getter MethodHandle for spill and user accessor properties. + * + * @param self the this object + * @param owner the owner object + * @return the property value + */ + protected abstract Object getObjectValue(ScriptObject self, ScriptObject owner); + + /** * Abstract method for retrieving the setter for the property. We do not know * anything about the internal representation when we request the setter, we only * know that the setter will take the property as a parameter of the given type. diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java --- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Wed Jul 05 18:57:52 2017 +0200 @@ -30,6 +30,8 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedList; import jdk.nashorn.internal.codegen.Compiler; @@ -49,9 +51,16 @@ */ public final class RecompilableScriptFunctionData extends ScriptFunctionData { + /** FunctionNode with the code for this ScriptFunction */ private FunctionNode functionNode; - private final PropertyMap allocatorMap; + + /** Allocator map from makeMap() */ + private final PropertyMap allocatorMap; + + /** Code installer used for all further recompilation/specialization of this ScriptFunction */ private final CodeInstaller installer; + + /** Name of class where allocator function resides */ private final String allocatorClassName; /** lazily generated allocator */ @@ -60,6 +69,23 @@ private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); /** + * Used for specialization based on runtime arguments. Whenever we specialize on + * callsite parameter types at runtime, we need to use a parameter type guard to + * ensure that the specialized version of the script function continues to be + * applicable for a particular callsite * + */ + private static final MethodHandle PARAM_TYPE_GUARD = findOwnMH("paramTypeGuard", boolean.class, Type[].class, Object[].class); + + /** + * It is usually a good gamble whever we detect a runtime callsite with a double + * (or java.lang.Number instance) to specialize the parameter to an integer, if the + * parameter in question can be represented as one. The double typically only exists + * because the compiler doesn't know any better than "a number type" and conservatively + * picks doubles when it can't prove that an integer addition wouldn't overflow + */ + private static final MethodHandle ENSURE_INT = findOwnMH("ensureInt", int.class, Object.class); + + /** * Constructor - public as scripts use it * * @param functionNode functionNode that represents this function code @@ -141,14 +167,6 @@ return; // nothing to do, we have code, at least some. } - // check if function node is lazy, need to compile it. - // note that currently function cloning is not working completely, which - // means that the compiler will mutate the function node it has been given - // once it has been compiled, it cannot be recompiled. This means that - // lazy compilation works (not compiled yet) but e.g. specializations won't - // until the copy-on-write changes for IR are in, making cloning meaningless. - // therefore, currently method specialization is disabled. TODO - if (functionNode.isLazy()) { Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'"); final Compiler compiler = new Compiler(installer); @@ -156,38 +174,55 @@ assert !functionNode.isLazy(); compiler.install(functionNode); - // we don't need to update any flags - varArgs and needsCallee are instrincic - // in the function world we need to get a destination node from the compile instead - // and replace it with our function node. TODO + /* + * We don't need to update any flags - varArgs and needsCallee are instrincic + * in the function world we need to get a destination node from the compile instead + * and replace it with our function node. TODO + */ } - // we can't get here unless we have bytecode, either from eager compilation or from - // running a lazy compile on the lines above + /* + * We can't get to this program point unless we have bytecode, either from + * eager compilation or from running a lazy compile on the lines above + */ assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode); // code exists - look it up and add it into the automatically sorted invoker list - addCode(functionNode, null, null); + addCode(functionNode); } - private MethodHandle addCode(final FunctionNode fn, final MethodHandle guard, final MethodHandle fallback) { - final MethodHandle target = + private MethodHandle addCode(final FunctionNode fn) { + return addCode(fn, null, null, null); + } + + private MethodHandle addCode(final FunctionNode fn, final MethodType runtimeType, final MethodHandle guard, final MethodHandle fallback) { + final MethodType targetType = new FunctionSignature(fn).getMethodType(); + MethodHandle target = MH.findStatic( LOOKUP, fn.getCompileUnit().getCode(), fn.getName(), - new FunctionSignature(fn). - getMethodType()); - MethodHandle mh = target; - if (guard != null) { - try { - mh = MH.guardWithTest(MH.asCollector(guard, Object[].class, target.type().parameterCount()), MH.asType(target, fallback.type()), fallback); - } catch (Throwable e) { - e.printStackTrace(); + targetType); + + /* + * For any integer argument. a double that is representable as an integer is OK. + * otherwise the guard would have failed. in that case introduce a filter that + * casts the double to an integer, which we know will preserve all precision. + */ + for (int i = 0; i < targetType.parameterCount(); i++) { + if (targetType.parameterType(i) == int.class) { + //representable as int + target = MH.filterArguments(target, i, ENSURE_INT); } } - final CompiledFunction cf = new CompiledFunction(mh); + MethodHandle mh = target; + if (guard != null) { + mh = MH.guardWithTest(MH.asCollector(guard, Object[].class, target.type().parameterCount()), MH.asType(target, fallback.type()), fallback); + } + + final CompiledFunction cf = new CompiledFunction(runtimeType == null ? targetType : runtimeType, mh); code.add(cf); return cf.getInvoker(); @@ -212,69 +247,162 @@ return Type.OBJECT; } - @SuppressWarnings("unused") - private static boolean paramTypeGuard(final Type[] compileTimeTypes, final Type[] runtimeTypes, Object... args) { - //System.err.println("Param type guard " + Arrays.asList(args)); + private static boolean canCoerce(final Object arg, final Type type) { + Type argType = runtimeType(arg); + if (Type.widest(argType, type) == type || arg == ScriptRuntime.UNDEFINED) { + return true; + } + System.err.println(arg + " does not fit in "+ argType + " " + type + " " + arg.getClass()); + new Throwable().printStackTrace(); return false; } - private static final MethodHandle PARAM_TYPE_GUARD = findOwnMH("paramTypeGuard", boolean.class, Type[].class, Type[].class, Object[].class); + @SuppressWarnings("unused") + private static boolean paramTypeGuard(final Type[] paramTypes, final Object... args) { + final int length = args.length; + assert args.length >= paramTypes.length; + + //i==start, skip the this, callee params etc + int start = args.length - paramTypes.length; + for (int i = start; i < args.length; i++) { + final Object arg = args[i]; + if (!canCoerce(arg, paramTypes[i - start])) { + return false; + } + } + return true; + } + + @SuppressWarnings("unused") + private static int ensureInt(final Object arg) { + if (arg instanceof Number) { + return ((Number)arg).intValue(); + } else if (arg instanceof Undefined) { + return 0; + } + throw new AssertionError(arg); + } + + /** + * Given the runtime callsite args, compute a method type that is equivalent to what + * was passed - this is typically a lot more specific that what the compiler has been + * able to deduce + * @param callSiteType callsite type for the compiled callsite target + * @param args runtime arguments to the compiled callsite target + * @return adjusted method type, narrowed as to conform to runtime callsite type instead + */ + private static MethodType runtimeType(final MethodType callSiteType, final Object[] args) { + if (args == null) { + //for example bound, or otherwise runtime arguments to callsite unavailable, then + //do not change the type + return callSiteType; + } + final Class[] paramTypes = new Class[callSiteType.parameterCount()]; + final int start = args.length - callSiteType.parameterCount(); + for (int i = start; i < args.length; i++) { + paramTypes[i - start] = runtimeType(args[i]).getTypeClass(); + } + return MH.type(callSiteType.returnType(), paramTypes); + } + + private static ArrayList runtimeType(final MethodType mt) { + final ArrayList type = new ArrayList<>(); + for (int i = 0; i < mt.parameterCount(); i++) { + type.add(Type.typeFor(mt.parameterType(i))); + } + return type; + } @Override MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) { - final MethodHandle mh = super.getBestInvoker(callSiteType, args); + final MethodType runtimeType = runtimeType(callSiteType, args); + assert runtimeType.parameterCount() == callSiteType.parameterCount(); + + final MethodHandle mh = super.getBestInvoker(runtimeType, args); - if (!functionNode.canSpecialize() || !code.isLessSpecificThan(callSiteType)) { + /* + * Not all functions can be specialized, for example, if we deemed memory + * footprint too large to store a parse snapshot, or if it is meaningless + * to do so, such as e.g. for runScript + */ + if (!functionNode.canSpecialize()) { return mh; } - final FunctionNode snapshot = functionNode.getSnapshot(); - if (snapshot == null) { + /* + * Check if best invoker is equally specific or more specific than runtime + * type. In that case, we don't need further specialization, but can use + * whatever we have already. We know that it will match callSiteType, or it + * would not have been returned from getBestInvoker + */ + if (!code.isLessSpecificThan(runtimeType)) { return mh; } int i; + final FunctionNode snapshot = functionNode.getSnapshot(); + assert snapshot != null; - //classes known at runtime - final LinkedList runtimeArgs = new LinkedList<>(); - for (i = args.length - 1; i >= args.length - snapshot.getParameters().size(); i--) { - runtimeArgs.addLast(runtimeType(args[i])); - } - - //classes known at compile time + /* + * Create a list of the arg types that the compiler knows about + * typically, the runtime args are a lot more specific, and we should aggressively + * try to use those whenever possible + * We WILL try to make an aggressive guess as possible, and add guards if needed. + * For example, if the compiler can deduce that we have a number type, but the runtime + * passes and int, we might still want to keep it an int, and the gamble to + * check that whatever is passed is int representable usually pays off + * If the compiler only knows that a parameter is an "Object", it is still worth + * it to try to specialize it by looking at the runtime arg. + */ final LinkedList compileTimeArgs = new LinkedList<>(); for (i = callSiteType.parameterCount() - 1; i >= 0 && compileTimeArgs.size() < snapshot.getParameters().size(); i--) { - compileTimeArgs.addLast(Type.typeFor(callSiteType.parameterType(i))); + compileTimeArgs.addFirst(Type.typeFor(callSiteType.parameterType(i))); } - //the classes known at compile time are a safe to generate as primitives without parameter guards - //the classes known at runtime are safe to generate as primitives IFF there are parameter guards + /* + * The classes known at compile time are a safe to generate as primitives without parameter guards + * But the classes known at runtime (if more specific than compile time types) are safe to generate as primitives + * IFF there are parameter guards + */ MethodHandle guard = null; + final ArrayList runtimeParamTypes = runtimeType(runtimeType); + while (runtimeParamTypes.size() > functionNode.getParameters().size()) { + runtimeParamTypes.remove(0); + } for (i = 0; i < compileTimeArgs.size(); i++) { - final Type runtimeType = runtimeArgs.get(i); - final Type compileType = compileTimeArgs.get(i); + final Type rparam = Type.typeFor(runtimeType.parameterType(i)); + final Type cparam = compileTimeArgs.get(i); - if (compileType.isObject() && !runtimeType.isObject()) { + if (cparam.isObject() && !rparam.isObject()) { + //check that the runtime object is still coercible to the runtime type, because compiler can't prove it's always primitive if (guard == null) { - guard = PARAM_TYPE_GUARD; - guard = MH.insertArguments(guard, 0, compileTimeArgs.toArray(new Type[compileTimeArgs.size()]), runtimeArgs.toArray(new Type[runtimeArgs.size()])); + guard = MH.insertArguments(PARAM_TYPE_GUARD, 0, (Object)runtimeParamTypes.toArray(new Type[runtimeParamTypes.size()])); } } } - //System.err.println("Specialized " + name + " " + runtimeArgs + " known=" + compileTimeArgs); + Compiler.LOG.info("Callsite specialized ", name, " runtimeType=", runtimeType, " parameters=", snapshot.getParameters(), " args=", Arrays.asList(args)); assert snapshot != null; assert snapshot != functionNode; final Compiler compiler = new Compiler(installer); - final FunctionNode compiledSnapshot = compiler.compile(snapshot.setHints(null, new Compiler.Hints(compileTimeArgs.toArray(new Type[compileTimeArgs.size()])))); + + final FunctionNode compiledSnapshot = compiler.compile( + snapshot.setHints( + null, + new Compiler.Hints(runtimeParamTypes.toArray(new Type[runtimeParamTypes.size()])))); + /* + * No matter how narrow your types were, they can never be narrower than Attr during recompile made them. I.e. you + * can put an int into the function here, if you see it as a runtime type, but if the function uses a multiplication + * on it, it will still need to be a double. At least until we have overflow checks. Similarly, if an int is + * passed but it is used as a string, it makes no sense to make the parameter narrower than Object. At least until + * the "different types for one symbol in difference places" work is done + */ compiler.install(compiledSnapshot); - final MethodHandle nmh = addCode(compiledSnapshot, guard, mh); - - return nmh; + return addCode(compiledSnapshot, runtimeType, guard, mh); } private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Wed Jul 05 18:57:52 2017 +0200 @@ -54,7 +54,7 @@ private final Namespace namespace; /** Current Options object. */ - private Options options; + private final Options options; /** Always allow functions as statements */ public final boolean _anon_functions; @@ -155,6 +155,9 @@ /** print symbols and their contents for the script */ public final boolean _print_symbols; + /** range analysis for known types */ + public final boolean _range_analysis; + /** is this environment in scripting mode? */ public final boolean _scripting; @@ -183,7 +186,7 @@ * @param out output print writer * @param err error print writer */ - ScriptEnvironment(final Options options, final PrintWriter out, final PrintWriter err) { + public ScriptEnvironment(final Options options, final PrintWriter out, final PrintWriter err) { this.out = out; this.err = err; this.namespace = new Namespace(); @@ -219,6 +222,7 @@ _print_parse = options.getBoolean("print.parse"); _print_lower_parse = options.getBoolean("print.lower.parse"); _print_symbols = options.getBoolean("print.symbols"); + _range_analysis = options.getBoolean("range.analysis"); _scripting = options.getBoolean("scripting"); _strict = options.getBoolean("strict"); _version = options.getBoolean("version"); @@ -258,14 +262,19 @@ } this._callsite_flags = callSiteFlags; - final Option option = options.get("timezone"); - if (option != null) { - this._timezone = (TimeZone)option.getValue(); + final Option timezoneOption = options.get("timezone"); + if (timezoneOption != null) { + this._timezone = (TimeZone)timezoneOption.getValue(); } else { this._timezone = TimeZone.getDefault(); } - this._locale = Locale.getDefault(); + final Option localeOption = options.get("locale"); + if (localeOption != null) { + this._locale = (Locale)localeOption.getValue(); + } else { + this._locale = Locale.getDefault(); + } } /** diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Wed Jul 05 18:57:52 2017 +0200 @@ -25,14 +25,13 @@ package jdk.nashorn.internal.runtime; +import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; -import static jdk.nashorn.internal.lookup.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; - import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; /** @@ -92,12 +91,13 @@ CompiledFunction bind(final CompiledFunction originalInv, final ScriptFunction fn, final Object self, final Object[] args) { final MethodHandle boundInvoker = bindInvokeHandle(originalInv.getInvoker(), fn, self, args); + //TODO the boundinvoker.type() could actually be more specific here if (isConstructor()) { ensureConstructor(originalInv); - return new CompiledFunction(boundInvoker, bindConstructHandle(originalInv.getConstructor(), fn, args)); + return new CompiledFunction(boundInvoker.type(), boundInvoker, bindConstructHandle(originalInv.getConstructor(), fn, args)); } - return new CompiledFunction(boundInvoker); + return new CompiledFunction(boundInvoker.type(), boundInvoker); } /** @@ -389,7 +389,9 @@ boundInvoker = noArgBoundInvoker; } } else { - final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount(), args.length + (isTargetBound ? 0 : (needsCallee ? 2 : 1)))]; + // If target is already bound, insert additional bound arguments after "this" argument, at position 1. + final int argInsertPos = isTargetBound ? 1 : 0; + final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount() - argInsertPos, args.length + (isTargetBound ? 0 : (needsCallee ? 2 : 1)))]; int next = 0; if (!isTargetBound) { if (needsCallee) { @@ -403,7 +405,7 @@ // "this" will get dropped anyway by the target invoker. We previously asserted that already bound functions // don't take a callee parameter, so we can know that the signature is (this[, args...]) therefore args // start at position 1. If the function is not bound, we start inserting arguments at position 0. - boundInvoker = MH.insertArguments(originalInvoker, isTargetBound ? 1 : 0, boundArgs); + boundInvoker = MH.insertArguments(originalInvoker, argInsertPos, boundArgs); } if (isTargetBound) { diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Wed Jul 05 18:57:52 2017 +0200 @@ -25,7 +25,6 @@ package jdk.nashorn.internal.runtime; -import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall; import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup; import static jdk.nashorn.internal.lookup.Lookup.MH; @@ -151,17 +150,6 @@ /** Method handle for setting the user accessors of a ScriptObject */ public static final Call SET_USER_ACCESSORS = virtualCall(ScriptObject.class, "setUserAccessors", void.class, String.class, ScriptFunction.class, ScriptFunction.class); - /** Method handle for getter for {@link UserAccessorProperty}, given a slot */ - static final Call USER_ACCESSOR_GETTER = staticCall(MethodHandles.lookup(), ScriptObject.class, "userAccessorGetter", Object.class, ScriptObject.class, int.class, Object.class); - - /** Method handle for setter for {@link UserAccessorProperty}, given a slot */ - static final Call USER_ACCESSOR_SETTER = staticCall(MethodHandles.lookup(), ScriptObject.class, "userAccessorSetter", void.class, ScriptObject.class, int.class, String.class, Object.class, Object.class); - - private static final MethodHandle INVOKE_UA_GETTER = Bootstrap.createDynamicInvoker("dyn:call", Object.class, - Object.class, Object.class); - private static final MethodHandle INVOKE_UA_SETTER = Bootstrap.createDynamicInvoker("dyn:call", void.class, - Object.class, Object.class, Object.class); - /** * Constructor */ @@ -699,17 +687,9 @@ * @return New property. */ public final Property addOwnProperty(final String key, final int propertyFlags, final Object value) { - final MethodHandle setter = addSpill(key, propertyFlags); - - try { - setter.invokeExact((Object)this, value); - } catch (final Error|RuntimeException e) { - throw e; - } catch (final Throwable e) { - throw new RuntimeException(e); - } - - return getMap().findProperty(key); + final Property property = addSpillProperty(key, propertyFlags); + property.setObjectValue(this, this, value, false); + return property; } /** @@ -744,15 +724,7 @@ // Erase the property field value with undefined. If the property is defined // by user-defined accessors, we don't want to call the setter!! if (!(property instanceof UserAccessorProperty)) { - try { - // make the property value to be undefined - //TODO specproperties - property.getSetter(Object.class, getMap()).invokeExact((Object)this, (Object)UNDEFINED); - } catch (final RuntimeException | Error e) { - throw e; - } catch (final Throwable t) { - throw new RuntimeException(t); - } + property.setObjectValue(this, this, UNDEFINED, false); } } @@ -948,18 +920,7 @@ * @return the value of the property */ protected static Object getObjectValue(final FindProperty find) { - final MethodHandle getter = find.getGetter(Object.class); - if (getter != null) { - try { - return getter.invokeExact((Object)find.getGetterReceiver()); - } catch (final Error|RuntimeException e) { - throw e; - } catch (final Throwable e) { - throw new RuntimeException(e); - } - } - - return UNDEFINED; + return find.getObjectValue(); } /** @@ -2087,11 +2048,7 @@ property = addOwnProperty(property); } else { int i = getMap().getSpillLength(); - MethodHandle getter = MH.arrayElementGetter(Object[].class); - MethodHandle setter = MH.arrayElementSetter(Object[].class); - getter = MH.asType(MH.insertArguments(getter, 1, i), Lookup.GET_OBJECT_TYPE); - setter = MH.asType(MH.insertArguments(setter, 1, i), Lookup.SET_OBJECT_TYPE); - property = new AccessorProperty(key, propertyFlags | Property.IS_SPILL, i, getter, setter); + property = new AccessorProperty(key, propertyFlags | Property.IS_SPILL, i); notifyPropertyAdded(this, property); property = addOwnProperty(property); i = property.getSlot(); @@ -2115,20 +2072,15 @@ /** * Add a spill entry for the given key. - * @param key Property key. - * @param propertyFlags Property flags. + * @param key Property key. * @return Setter method handle. */ - private MethodHandle addSpill(final String key, final int propertyFlags) { - final Property spillProperty = addSpillProperty(key, propertyFlags); + MethodHandle addSpill(final String key) { + final Property spillProperty = addSpillProperty(key, 0); final Class type = Object.class; return spillProperty.getSetter(type, getMap()); //TODO specfields } - MethodHandle addSpill(final String key) { - return addSpill(key, 0); - } - /** * Make sure arguments are paired correctly, with respect to more parameters than declared, * fewer parameters than declared and other things that JavaScript allows. This might involve @@ -2659,14 +2611,8 @@ return; } - try { - final MethodHandle setter = f.getSetter(Object.class, strict); //TODO specfields - setter.invokeExact((Object)f.getSetterReceiver(), value); - } catch (final Error|RuntimeException e) { - throw e; - } catch (final Throwable e) { - throw new RuntimeException(e); - } + f.setObjectValue(value, strict); + } else if (!isExtensible()) { if (strict) { throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this)); @@ -2677,13 +2623,7 @@ } private void spill(final String key, final Object value) { - try { - addSpill(key).invokeExact((Object)this, value); - } catch (final Error|RuntimeException e) { - throw e; - } catch (final Throwable e) { - throw new RuntimeException(e); - } + addSpillProperty(key, 0).setObjectValue(this, this, value, false); } @@ -3217,46 +3157,6 @@ return (index < 0 || (index >= spill.length)) ? null : spill[index]; } - // User defined getter and setter are always called by "dyn:call". Note that the user - // getter/setter may be inherited. If so, proto is bound during lookup. In either - // inherited or self case, slot is also bound during lookup. Actual ScriptFunction - // to be called is retrieved everytime and applied. - @SuppressWarnings("unused") - private static Object userAccessorGetter(final ScriptObject proto, final int slot, final Object self) { - final ScriptObject container = (proto != null) ? proto : (ScriptObject)self; - final Object func = container.getSpill(slot); - - if (func instanceof ScriptFunction) { - try { - return INVOKE_UA_GETTER.invokeExact(func, self); - } catch(final Error|RuntimeException t) { - throw t; - } catch(final Throwable t) { - throw new RuntimeException(t); - } - } - - return UNDEFINED; - } - - @SuppressWarnings("unused") - private static void userAccessorSetter(final ScriptObject proto, final int slot, final String name, final Object self, final Object value) { - final ScriptObject container = (proto != null) ? proto : (ScriptObject)self; - final Object func = container.getSpill(slot); - - if (func instanceof ScriptFunction) { - try { - INVOKE_UA_SETTER.invokeExact(func, self, value); - } catch(final Error|RuntimeException t) { - throw t; - } catch(final Throwable t) { - throw new RuntimeException(t); - } - } else if (name != null) { - throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self)); - } - } - private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { final Class own = ScriptObject.class; final MethodType mt = MH.type(rtype, types); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java Wed Jul 05 18:57:52 2017 +0200 @@ -36,6 +36,7 @@ import java.lang.reflect.Array; import java.util.Collections; import java.util.Iterator; +import java.util.Locale; import java.util.NoSuchElementException; import java.util.Objects; import jdk.internal.dynalink.beans.StaticClass; @@ -788,7 +789,7 @@ return false; } - throw typeError("in.with.non.object", rvalType.toString().toLowerCase()); + throw typeError("in.with.non.object", rvalType.toString().toLowerCase(Locale.ENGLISH)); } /** diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java Wed Jul 05 18:57:52 2017 +0200 @@ -46,7 +46,7 @@ public final class ScriptingFunctions { /** Handle to implementation of {@link ScriptingFunctions#readLine} - Nashorn extension */ - public static final MethodHandle READLINE = findOwnMH("readLine", Object.class, Object.class); + public static final MethodHandle READLINE = findOwnMH("readLine", Object.class, Object.class, Object.class); /** Handle to implementation of {@link ScriptingFunctions#readFully} - Nashorn extension */ public static final MethodHandle READFULLY = findOwnMH("readFully", Object.class, Object.class, Object.class); @@ -78,13 +78,17 @@ * Nashorn extension: global.readLine (scripting-mode-only) * Read one line of input from the standard input. * - * @param self self reference + * @param self self reference + * @param prompt String used as input prompt * * @return line that was read * * @throws IOException if an exception occurs */ - public static Object readLine(final Object self) throws IOException { + public static Object readLine(final Object self, final Object prompt) throws IOException { + if (prompt != UNDEFINED) { + System.out.print(JSType.toString(prompt)); + } final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); return reader.readLine(); } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java --- a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java Wed Jul 05 18:57:52 2017 +0200 @@ -183,17 +183,10 @@ private SetMethod createNewSpillPropertySetter() { final int nextSpill = getMap().getSpillLength(); - final Property property = createSpillProperty(nextSpill); + final Property property = new AccessorProperty(getName(), Property.IS_SPILL, nextSpill); return new SetMethod(createSpillMethodHandle(nextSpill, property), property); } - private Property createSpillProperty(final int nextSpill) { - final MethodHandle getter = MH.asType(MH.insertArguments(MH.arrayElementGetter(Object[].class), 1, nextSpill), Lookup.GET_OBJECT_TYPE); - final MethodHandle setter = MH.asType(MH.insertArguments(MH.arrayElementSetter(Object[].class), 1, nextSpill), Lookup.SET_OBJECT_TYPE); - - return new AccessorProperty(getName(), Property.IS_SPILL, nextSpill, getter, setter); - } - private MethodHandle createSpillMethodHandle(final int nextSpill, Property property) { final PropertyMap oldMap = getMap(); final PropertyMap newMap = getNewMap(property); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java --- a/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java Wed Jul 05 18:57:52 2017 +0200 @@ -26,7 +26,15 @@ package jdk.nashorn.internal.runtime; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; + +import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.lookup.Lookup; +import jdk.nashorn.internal.runtime.linker.Bootstrap; + +import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; +import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; +import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; /** * Property with user defined getters/setters. Actual getter and setter @@ -51,6 +59,22 @@ /** User defined setter function slot. */ private final int setterSlot; + /** Getter method handle */ + private final static CompilerConstants.Call USER_ACCESSOR_GETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class, + "userAccessorGetter", Object.class, ScriptObject.class, int.class, Object.class); + + /** Setter method handle */ + private final static CompilerConstants.Call USER_ACCESSOR_SETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class, + "userAccessorSetter", void.class, ScriptObject.class, int.class, String.class, Object.class, Object.class); + + /** Dynamic invoker for getter */ + private static final MethodHandle INVOKE_UA_GETTER = Bootstrap.createDynamicInvoker("dyn:call", Object.class, + Object.class, Object.class); + + /** Dynamic invoker for setter */ + private static final MethodHandle INVOKE_UA_SETTER = Bootstrap.createDynamicInvoker("dyn:call", void.class, + Object.class, Object.class, Object.class); + /** * Constructor * @@ -134,8 +158,18 @@ } @Override + protected Object getObjectValue(final ScriptObject self, final ScriptObject owner) { + return userAccessorGetter(owner, getGetterSlot(), self); + } + + @Override + protected void setObjectValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) { + userAccessorSetter(owner, getSetterSlot(), strict ? getKey() : null, self, value); + } + + @Override public MethodHandle getGetter(final Class type) { - return Lookup.filterReturnType(ScriptObject.USER_ACCESSOR_GETTER.methodHandle(), type); + return Lookup.filterReturnType(USER_ACCESSOR_GETTER.methodHandle(), type); } @Override @@ -146,7 +180,7 @@ @Override public MethodHandle getSetter(final Class type, final PropertyMap currentMap) { - return ScriptObject.USER_ACCESSOR_SETTER.methodHandle(); + return USER_ACCESSOR_SETTER.methodHandle(); } @Override @@ -155,4 +189,42 @@ return (value instanceof ScriptFunction) ? (ScriptFunction) value : null; } + // User defined getter and setter are always called by "dyn:call". Note that the user + // getter/setter may be inherited. If so, proto is bound during lookup. In either + // inherited or self case, slot is also bound during lookup. Actual ScriptFunction + // to be called is retrieved everytime and applied. + static Object userAccessorGetter(final ScriptObject proto, final int slot, final Object self) { + final ScriptObject container = (proto != null) ? proto : (ScriptObject)self; + final Object func = container.getSpill(slot); + + if (func instanceof ScriptFunction) { + try { + return INVOKE_UA_GETTER.invokeExact(func, self); + } catch(final Error|RuntimeException t) { + throw t; + } catch(final Throwable t) { + throw new RuntimeException(t); + } + } + + return UNDEFINED; + } + + static void userAccessorSetter(final ScriptObject proto, final int slot, final String name, final Object self, final Object value) { + final ScriptObject container = (proto != null) ? proto : (ScriptObject)self; + final Object func = container.getSpill(slot); + + if (func instanceof ScriptFunction) { + try { + INVOKE_UA_SETTER.invokeExact(func, self, value); + } catch(final Error|RuntimeException t) { + throw t; + } catch(final Throwable t) { + throw new RuntimeException(t); + } + } else if (name != null) { + throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self)); + } + } + } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/linker/InvokeByName.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/InvokeByName.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/InvokeByName.java Wed Jul 05 18:57:52 2017 +0200 @@ -40,7 +40,7 @@ * private static final InvokeByName TO_JSON = new InvokeByName("toJSON", Object.class, Object.class, Object.class); * ... * final Object toJSONFn = TO_JSON.getGetter().invokeExact(obj); - * value = TO_JSON.getInvoker().invokeExact(toJSON, obj, key); + * value = TO_JSON.getInvoker().invokeExact(toJSONFn, obj, key); * * In practice, you can have stronger type assumptions if it makes sense for your code, just remember that you must use * the same parameter types as the formal types of the arguments for {@code invokeExact} to work: @@ -50,7 +50,7 @@ * final ScriptObject sobj = (ScriptObject)obj; * final Object toJSONFn = TO_JSON.getGetter().invokeExact(sobj); * if(toJSONFn instanceof ScriptFunction) { - * value = TO_JSON.getInvoker().invokeExact(toJSON, sobj, key); + * value = TO_JSON.getInvoker().invokeExact(toJSONFn, sobj, key); * } * * Note that in general you will not want to reuse a single instance of this class for implementing more than one call @@ -59,6 +59,7 @@ * separate instance of this class for every place. */ public class InvokeByName { + private final String name; private final MethodHandle getter; private final MethodHandle invoker; @@ -81,6 +82,7 @@ * @param ptypes the parameter types of the function. */ public InvokeByName(final String name, final Class targetClass, final Class rtype, final Class... ptypes) { + this.name = name; getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getItem:" + name, Object.class, targetClass); final Class[] finalPtypes; @@ -97,6 +99,14 @@ } /** + * Returns the name of the function retrieved through this invoker. + * @return the name of the function retrieved through this invoker. + */ + public String getName() { + return name; + } + + /** * Returns the property getter that can be invoked on an object to retrieve the function object that will be * subsequently invoked by the invoker returned by {@link #getInvoker()}. * @return the property getter method handle for the function. diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Wed Jul 05 18:57:52 2017 +0200 @@ -38,7 +38,7 @@ import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; import jdk.internal.dynalink.support.CallSiteDescriptorFactory; import jdk.nashorn.internal.runtime.JSType; -import netscape.javascript.JSObject; +import jdk.nashorn.api.scripting.JSObject; /** * A Dynalink linker to handle web browser built-in JS (DOM etc.) objects as well diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Wed Jul 05 18:57:52 2017 +0200 @@ -310,7 +310,34 @@ Type.getMethodDescriptor(Type.VOID_TYPE), null, null)); mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getClassOverrides", GET_CLASS_INITIALIZER_DESCRIPTOR); - // Assign MethodHandle fields through invoking getHandle() + final Label initGlobal; + if(samName != null) { + // If the class is a SAM, allow having a ScriptFunction passed as class overrides + final Label notAFunction = new Label(); + mv.dup(); + mv.instanceOf(SCRIPT_FUNCTION_TYPE); + mv.ifeq(notAFunction); + mv.checkcast(SCRIPT_FUNCTION_TYPE); + + // Assign MethodHandle fields through invoking getHandle() for a ScriptFunction, only assigning the SAM + // method(s). + for (final MethodInfo mi : methodInfos) { + if(mi.getName().equals(samName)) { + mv.dup(); + mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString())); + mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_FUNCTION_DESCRIPTOR); + } else { + mv.visitInsn(ACONST_NULL); + } + mv.putstatic(generatedClassName, mi.methodHandleClassFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); + } + initGlobal = new Label(); + mv.goTo(initGlobal); + mv.visitLabel(notAFunction); + } else { + initGlobal = null; + } + // Assign MethodHandle fields through invoking getHandle() for a ScriptObject for (final MethodInfo mi : methodInfos) { mv.dup(); mv.aconst(mi.getName()); @@ -319,6 +346,9 @@ mv.putstatic(generatedClassName, mi.methodHandleClassFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); } + if(initGlobal != null) { + mv.visitLabel(initGlobal); + } // Assign "staticGlobal = Context.getGlobal()" invokeGetGlobalWithNullCheck(mv); mv.putstatic(generatedClassName, STATIC_GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java Wed Jul 05 18:57:52 2017 +0200 @@ -43,6 +43,7 @@ import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.security.SecureClassLoader; + import jdk.internal.dynalink.beans.StaticClass; import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.Opcodes; @@ -58,6 +59,7 @@ * "class loader", it does not, in fact, extend {@code ClassLoader}, but rather uses them internally. Instances of this * class are normally created by {@link JavaAdapterBytecodeGenerator}. */ +@SuppressWarnings("javadoc") class JavaAdapterClassLoader extends JavaAdapterGeneratorBase { private static final Type PRIVILEGED_ACTION_TYPE = Type.getType(PrivilegedAction.class); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java Wed Jul 05 18:57:52 2017 +0200 @@ -39,6 +39,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; + import jdk.internal.dynalink.beans.StaticClass; import jdk.internal.dynalink.support.LinkRequestImpl; import jdk.nashorn.internal.objects.NativeJava; @@ -66,6 +67,7 @@ *

    */ +@SuppressWarnings("javadoc") public final class JavaAdapterFactory { /** * A mapping from an original Class object to AdapterInfo representing the adapter for the class it represents. diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterGeneratorBase.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterGeneratorBase.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterGeneratorBase.java Wed Jul 05 18:57:52 2017 +0200 @@ -33,6 +33,7 @@ * Base class for both {@link JavaAdapterBytecodeGenerator} and {@link JavaAdapterClassLoader}, containing those * bytecode types, type names and method descriptor that are used by both. */ +@SuppressWarnings("javadoc") abstract class JavaAdapterGeneratorBase { static final Type CONTEXT_TYPE = Type.getType(Context.class); static final Type OBJECT_TYPE = Type.getType(Object.class); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/options/Option.java --- a/nashorn/src/jdk/nashorn/internal/runtime/options/Option.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/options/Option.java Wed Jul 05 18:57:52 2017 +0200 @@ -42,10 +42,6 @@ this.value = value; } - void setValue(final T value) { - this.value = value; - } - /** * Return the value of an option * @return the option value diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java --- a/nashorn/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java Wed Jul 05 18:57:52 2017 +0200 @@ -25,6 +25,7 @@ package jdk.nashorn.internal.runtime.options; +import java.util.Locale; import java.util.TimeZone; import jdk.nashorn.internal.runtime.QuotedStringTokenizer; @@ -151,6 +152,9 @@ case "timezone": this.defaultValue = TimeZone.getDefault().getID(); break; + case "locale": + this.defaultValue = Locale.getDefault().toLanguageTag(); + break; default: break; } @@ -263,7 +267,7 @@ this.params = arg; break; case "type": - this.type = arg.toLowerCase(); + this.type = arg.toLowerCase(Locale.ENGLISH); break; case "default": this.defaultValue = arg; diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/options/Options.java --- a/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java Wed Jul 05 18:57:52 2017 +0200 @@ -499,10 +499,10 @@ case "timezone": // default value "TimeZone.getDefault()" return new Option<>(TimeZone.getTimeZone(value)); + case "locale": + return new Option<>(Locale.forLanguageTag(value)); case "keyvalues": return new KeyValueOption(value); - case "values": - return new ValueOption(value); case "log": final KeyValueOption kv = new KeyValueOption(value); Logging.initialize(kv.getValues()); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/options/ValueOption.java --- a/nashorn/src/jdk/nashorn/internal/runtime/options/ValueOption.java Thu May 30 10:58:13 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +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.options; - -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.StringTokenizer; - -/** - * This option represents a collection of comma separated values - */ -public class ValueOption extends Option { - - private Collection values; - - ValueOption(final String value) { - super(value); - if (value != null) { - values = new LinkedHashSet<>(); - final StringTokenizer st = new StringTokenizer(getValue(), ","); - while (st.hasMoreElements()) { - values.add(st.nextToken()); - } - } - } - - /** - * Get the values in the option - * @return collection of strings - */ - public Collection getValues() { - return Collections.unmodifiableCollection(values); - } - -} diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java Thu May 30 10:58:13 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +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.regexp; - -import jdk.nashorn.internal.runtime.ParserException; - -import static java.util.regex.Pattern.CASE_INSENSITIVE; -import static java.util.regex.Pattern.MULTILINE; -import static java.util.regex.Pattern.UNICODE_CASE; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -/** - * Default regular expression implementation based on java.util.regex package. - * - * Note that this class is not thread-safe as it stores the current match result - * and the string being matched in instance fields. - */ -public class DefaultRegExp extends RegExp { - - /** Java regexp pattern to use for match. We compile to one of these */ - private Pattern pattern; - - /** The matcher */ - private RegExpMatcher matcher; - - /** - * Construct a Regular expression from the given {@code source} and {@code flags} strings. - * - * @param source RegExp source string - * @param flags RegExp flag string - * @throws ParserException if flags is invalid or source string has syntax error. - */ - public DefaultRegExp(final String source, final String flags) throws ParserException { - super(source, flags); - - int intFlags = 0; - - if (isIgnoreCase()) { - intFlags |= CASE_INSENSITIVE | UNICODE_CASE; - } - if (isMultiline()) { - intFlags |= MULTILINE; - } - - try { - RegExpScanner parsed; - - try { - parsed = RegExpScanner.scan(source); - } catch (final PatternSyntaxException e) { - // refine the exception with a better syntax error, if this - // passes, just rethrow what we have - Pattern.compile(source, intFlags); - throw e; - } - - if (parsed != null) { - this.pattern = Pattern.compile(parsed.getJavaPattern(), intFlags); - this.groupsInNegativeLookahead = parsed.getGroupsInNegativeLookahead(); - } - } catch (final PatternSyntaxException e2) { - throwParserException("syntax", e2.getMessage()); - } - } - - @Override - public RegExpMatcher match(final String str) { - if (pattern == null) { - return null; // never matches or similar, e.g. a[] - } - - RegExpMatcher currentMatcher = this.matcher; - - if (currentMatcher == null || matcher.getInput() != str) { - currentMatcher = new DefaultMatcher(str); - this.matcher = currentMatcher; - } - - return currentMatcher; - } - - class DefaultMatcher implements RegExpMatcher { - final String input; - final Matcher defaultMatcher; - - DefaultMatcher(final String input) { - this.input = input; - this.defaultMatcher = pattern.matcher(input); - } - - @Override - public boolean search(final int start) { - return defaultMatcher.find(start); - } - - @Override - public String getInput() { - return input; - } - - @Override - public int start() { - return defaultMatcher.start(); - } - - @Override - public int start(final int group) { - return defaultMatcher.start(group); - } - - @Override - public int end() { - return defaultMatcher.end(); - } - - @Override - public int end(final int group) { - return defaultMatcher.end(group); - } - - @Override - public String group() { - return defaultMatcher.group(); - } - - @Override - public String group(final int group) { - return defaultMatcher.group(group); - } - - @Override - public int groupCount() { - return defaultMatcher.groupCount(); - } - } - -} diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/JdkRegExp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/JdkRegExp.java Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,163 @@ +/* + * 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.regexp; + +import jdk.nashorn.internal.runtime.ParserException; + +import static java.util.regex.Pattern.CASE_INSENSITIVE; +import static java.util.regex.Pattern.MULTILINE; +import static java.util.regex.Pattern.UNICODE_CASE; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * Default regular expression implementation based on java.util.regex package. + * + * Note that this class is not thread-safe as it stores the current match result + * and the string being matched in instance fields. + */ +public class JdkRegExp extends RegExp { + + /** Java regexp pattern to use for match. We compile to one of these */ + private Pattern pattern; + + /** The matcher */ + private RegExpMatcher matcher; + + /** + * Construct a Regular expression from the given {@code source} and {@code flags} strings. + * + * @param source RegExp source string + * @param flags RegExp flag string + * @throws ParserException if flags is invalid or source string has syntax error. + */ + public JdkRegExp(final String source, final String flags) throws ParserException { + super(source, flags); + + int intFlags = 0; + + if (isIgnoreCase()) { + intFlags |= CASE_INSENSITIVE | UNICODE_CASE; + } + if (isMultiline()) { + intFlags |= MULTILINE; + } + + try { + RegExpScanner parsed; + + try { + parsed = RegExpScanner.scan(source); + } catch (final PatternSyntaxException e) { + // refine the exception with a better syntax error, if this + // passes, just rethrow what we have + Pattern.compile(source, intFlags); + throw e; + } + + if (parsed != null) { + this.pattern = Pattern.compile(parsed.getJavaPattern(), intFlags); + this.groupsInNegativeLookahead = parsed.getGroupsInNegativeLookahead(); + } + } catch (final PatternSyntaxException e2) { + throwParserException("syntax", e2.getMessage()); + } + } + + @Override + public RegExpMatcher match(final String str) { + if (pattern == null) { + return null; // never matches or similar, e.g. a[] + } + + RegExpMatcher currentMatcher = this.matcher; + + if (currentMatcher == null || matcher.getInput() != str) { + currentMatcher = new DefaultMatcher(str); + this.matcher = currentMatcher; + } + + return currentMatcher; + } + + class DefaultMatcher implements RegExpMatcher { + final String input; + final Matcher defaultMatcher; + + DefaultMatcher(final String input) { + this.input = input; + this.defaultMatcher = pattern.matcher(input); + } + + @Override + public boolean search(final int start) { + return defaultMatcher.find(start); + } + + @Override + public String getInput() { + return input; + } + + @Override + public int start() { + return defaultMatcher.start(); + } + + @Override + public int start(final int group) { + return defaultMatcher.start(group); + } + + @Override + public int end() { + return defaultMatcher.end(); + } + + @Override + public int end(final int group) { + return defaultMatcher.end(group); + } + + @Override + public String group() { + return defaultMatcher.group(); + } + + @Override + public String group(final int group) { + return defaultMatcher.group(group); + } + + @Override + public int groupCount() { + return defaultMatcher.groupCount(); + } + } + +} diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java Wed Jul 05 18:57:52 2017 +0200 @@ -113,7 +113,7 @@ public static class Factory extends RegExpFactory { @Override - protected RegExp compile(final String pattern, final String flags) throws ParserException { + public RegExp compile(final String pattern, final String flags) throws ParserException { return new JoniRegExp(pattern, flags); } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java Wed Jul 05 18:57:52 2017 +0200 @@ -29,7 +29,7 @@ import jdk.nashorn.internal.runtime.options.Options; /** - * Factory class for regular expressions. This class creates instances of {@link DefaultRegExp}. + * Factory class for regular expressions. This class creates instances of {@link JdkRegExp}. * An alternative factory can be installed using the {@code nashorn.regexp.impl} system property. */ public class RegExpFactory { @@ -62,8 +62,8 @@ * @return new RegExp * @throws ParserException if flags is invalid or pattern string has syntax error. */ - protected RegExp compile(final String pattern, final String flags) throws ParserException { - return new DefaultRegExp(pattern, flags); + public RegExp compile(final String pattern, final String flags) throws ParserException { + return new JdkRegExp(pattern, flags); } /** diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java Wed Jul 05 18:57:52 2017 +0200 @@ -868,6 +868,9 @@ * \ ClassEscape */ private boolean classAtomNoDash() { + if (atEOF()) { + return false; + } final int startIn = position; final int startOut = sb.length(); diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java Wed Jul 05 18:57:52 2017 +0200 @@ -21,10 +21,7 @@ import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsAll; import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsAt; -import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsClear; import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsOnAt; -import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsOnAtSimple; -import static jdk.nashorn.internal.runtime.regexp.joni.Option.isCaptureGroup; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isFindCondition; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isIgnoreCase; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isMultiline; @@ -36,8 +33,6 @@ import jdk.nashorn.internal.runtime.regexp.joni.ast.AnchorNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.BackRefNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode; -import jdk.nashorn.internal.runtime.regexp.joni.ast.CTypeNode; -import jdk.nashorn.internal.runtime.regexp.joni.ast.CallNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.ConsAltNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.EncloseNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.Node; @@ -49,9 +44,7 @@ import jdk.nashorn.internal.runtime.regexp.joni.constants.RegexState; import jdk.nashorn.internal.runtime.regexp.joni.constants.StackPopLevel; import jdk.nashorn.internal.runtime.regexp.joni.constants.TargetInfo; -import jdk.nashorn.internal.runtime.regexp.joni.encoding.CharacterType; import jdk.nashorn.internal.runtime.regexp.joni.encoding.ObjPtr; -import jdk.nashorn.internal.runtime.regexp.joni.encoding.Ptr; final class Analyser extends Parser { @@ -74,38 +67,9 @@ //regex.repeatRangeAlloc = 0; regex.repeatRangeLo = null; regex.repeatRangeHi = null; - regex.numCombExpCheck = 0; - - if (Config.USE_COMBINATION_EXPLOSION_CHECK) regex.numCombExpCheck = 0; parse(); - if (Config.USE_NAMED_GROUP) { - /* mixed use named group and no-named group */ - if (env.numNamed > 0 && syntax.captureOnlyNamedGroup() && !isCaptureGroup(regex.options)) { - if (env.numNamed != env.numMem) { - root = disableNoNameGroupCapture(root); - } else { - numberedRefCheck(root); - } - } - } // USE_NAMED_GROUP - - if (Config.USE_NAMED_GROUP) { - if (env.numCall > 0) { - env.unsetAddrList = new UnsetAddrList(env.numCall); - setupSubExpCall(root); - // r != 0 ??? - subexpRecursiveCheckTrav(root); - // r < 0 -< err, FOUND_CALLED_NODE = 1 - subexpInfRecursiveCheckTrav(root); - // r != 0 recursion infinite ??? - regex.numCall = env.numCall; - } else { - regex.numCall = 0; - } - } // USE_NAMED_GROUP - if (Config.DEBUG_PARSE_TREE_RAW && Config.DEBUG_PARSE_TREE) { Config.log.println(""); Config.log.println(root + "\n"); @@ -129,27 +93,6 @@ regex.btMemEnd |= regex.captureHistory; } - if (Config.USE_COMBINATION_EXPLOSION_CHECK) { - if (env.backrefedMem == 0 || (Config.USE_SUBEXP_CALL && env.numCall == 0)) { - setupCombExpCheck(root, 0); - - if (Config.USE_SUBEXP_CALL && env.hasRecursion) { - env.numCombExpCheck = 0; - } else { // USE_SUBEXP_CALL - if (env.combExpMaxRegNum > 0) { - for (int i=1; ic)/ - node = noNameDisableMap(node, map, counter); - } - } else { - //en.target = noNameDisableMap(en.target, map, counter); - en.setTarget(noNameDisableMap(en.target, map, counter)); // ??? - } - return node; - } - - private void noNameDisableMapFor_anchor(Node node, int[]map, Ptr counter) { - AnchorNode an = (AnchorNode)node; - switch (an.type) { - case AnchorNode.PREC_READ: - case AnchorNode.PREC_READ_NOT: - case AnchorNode.LOOK_BEHIND: - case AnchorNode.LOOK_BEHIND_NOT: - an.setTarget(noNameDisableMap(an.target, map, counter)); - } - } - - private Node noNameDisableMap(Node node, int[]map, Ptr counter) { - switch (node.getType()) { - case NodeType.LIST: - case NodeType.ALT: - noNameDisableMapFor_cosAlt(node, map, counter); - break; - case NodeType.QTFR: - noNameDisableMapFor_quantifier(node, map, counter); - break; - case NodeType.ENCLOSE: - node = noNameDisableMapFor_enclose(node, map, counter); - break; - case NodeType.ANCHOR: - noNameDisableMapFor_anchor(node, map, counter); - break; - } // switch - return node; - } - - private void renumberByMap(Node node, int[]map) { - switch (node.getType()) { - case NodeType.LIST: - case NodeType.ALT: - ConsAltNode can = (ConsAltNode)node; - do { - renumberByMap(can.car, map); - } while ((can = can.cdr) != null); - break; - - case NodeType.QTFR: - renumberByMap(((QuantifierNode)node).target, map); - break; - - case NodeType.ENCLOSE: - renumberByMap(((EncloseNode)node).target, map); - break; - - case NodeType.BREF: - ((BackRefNode)node).renumber(map); - break; - } // switch - } - - protected final void numberedRefCheck(Node node) { - switch (node.getType()) { - case NodeType.LIST: - case NodeType.ALT: - ConsAltNode can = (ConsAltNode)node; - do { - numberedRefCheck(can.car); - } while ((can = can.cdr) != null); - break; - - case NodeType.QTFR: - numberedRefCheck(((QuantifierNode)node).target); - break; - - case NodeType.ENCLOSE: - numberedRefCheck(((EncloseNode)node).target); - break; - - case NodeType.BREF: - BackRefNode br = (BackRefNode)node; - if (!br.isNameRef()) newValueException(ERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED); - break; - } // switch - } - - protected final Node disableNoNameGroupCapture(Node root) { - int[]map = new int[env.numMem + 1]; - - for (int i=1; i<=env.numMem; i++) map[i] = 0; - - root = noNameDisableMap(root, map, new Ptr(0)); - renumberByMap(root, map); - - for (int i=1, pos=1; i<=env.numMem; i++) { - if (map[i] > 0) { - env.memNodes[pos] = env.memNodes[i]; - pos++; - } - } - - int loc = env.captureHistory; - env.captureHistory = bsClear(); - - for (int i=1; i<=Config.MAX_CAPTURE_HISTORY_GROUP; i++) { - if (bsAt(loc, i)) { - env.captureHistory = bsOnAtSimple(env.captureHistory, map[i]); - } - } - - env.numMem = env.numNamed; - regex.numMem = env.numNamed; - - regex.renumberNameTable(map); - - return root; - } - private void swap(Node a, Node b) { a.swap(b); @@ -352,17 +143,6 @@ } while ((can = can.cdr) != null); break; - case NodeType.CALL: - if (Config.USE_SUBEXP_CALL) { - CallNode cn = (CallNode)node; - if (cn.isRecursion()) { - return TargetInfo.IS_EMPTY_REC; /* tiny version */ - } else { - info = quantifiersMemoryInfo(cn.target); - } - } // USE_SUBEXP_CALL - break; - case NodeType.QTFR: QuantifierNode qn = (QuantifierNode)node; if (qn.upper != 0) { @@ -417,18 +197,6 @@ } break; - case NodeType.CALL: - if (Config.USE_SUBEXP_CALL) { - CallNode cn = (CallNode)node; - if (cn.isRecursion()) { - EncloseNode en = (EncloseNode)cn.target; - if (en.isMinFixed()) min = en.minLength; - } else { - min = getMinMatchLength(cn.target); - } - } // USE_SUBEXP_CALL - break; - case NodeType.LIST: ConsAltNode can = (ConsAltNode)node; do { @@ -474,15 +242,13 @@ EncloseNode en = (EncloseNode)node; switch (en.type) { case EncloseType.MEMORY: - if (Config.USE_SUBEXP_CALL) { - if (en.isMinFixed()) { - min = en.minLength; - } else { - min = getMinMatchLength(en.target); - en.minLength = min; - en.setMinFixed(); - } - } // USE_SUBEXP_CALL + if (en.isMinFixed()) { + min = en.minLength; + } else { + min = getMinMatchLength(en.target); + en.minLength = min; + en.setMinFixed(); + } break; case EncloseType.OPTION: @@ -547,17 +313,6 @@ } break; - case NodeType.CALL: - if (Config.USE_SUBEXP_CALL) { - CallNode cn = (CallNode)node; - if (!cn.isRecursion()) { - max = getMaxMatchLength(cn.target); - } else { - max = MinMaxLen.INFINITE_DISTANCE; - } - } // USE_SUBEXP_CALL - break; - case NodeType.QTFR: QuantifierNode qn = (QuantifierNode)node; if (qn.upper != 0) { @@ -576,15 +331,13 @@ EncloseNode en = (EncloseNode)node; switch (en.type) { case EncloseType.MEMORY: - if (Config.USE_SUBEXP_CALL) { - if (en.isMaxFixed()) { - max = en.maxLength; - } else { - max = getMaxMatchLength(en.target); - en.maxLength = max; - en.setMaxFixed(); - } - } // USE_SUBEXP_CALL + if (en.isMaxFixed()) { + max = en.maxLength; + } else { + max = getMaxMatchLength(en.target); + en.maxLength = max; + en.setMaxFixed(); + } break; case EncloseType.OPTION: @@ -663,17 +416,6 @@ } break; - case NodeType.CALL: - if (Config.USE_SUBEXP_CALL) { - CallNode cn = (CallNode)node; - if (!cn.isRecursion()) { - len = getCharLengthTree(cn.target, level); - } else { - returnCode = GET_CHAR_LEN_VARLEN; - } - } // USE_SUBEXP_CALL - break; - case NodeType.CTYPE: len = 1; @@ -686,17 +428,15 @@ EncloseNode en = (EncloseNode)node; switch(en.type) { case EncloseType.MEMORY: - if (Config.USE_SUBEXP_CALL) { - if (en.isCLenFixed()) { - len = en.charLength; - } else { - len = getCharLengthTree(en.target, level); - if (returnCode == 0) { - en.charLength = len; - en.setCLenFixed(); - } + if (en.isCLenFixed()) { + len = en.charLength; + } else { + len = getCharLengthTree(en.target, level); + if (returnCode == 0) { + en.charLength = len; + en.setCLenFixed(); } - } // USE_SUBEXP_CALL + } break; case EncloseType.OPTION: @@ -727,10 +467,6 @@ switch(x.getType()) { case NodeType.CTYPE: switch(yType) { - case NodeType.CTYPE: - CTypeNode cny = (CTypeNode)y; - CTypeNode cnx = (CTypeNode)x; - return cny.ctype == cnx.ctype && cny.not != cnx.not; case NodeType.CCLASS: // !swap:! @@ -756,37 +492,6 @@ CClassNode xc = (CClassNode)x; switch(yType) { - case NodeType.CTYPE: - switch(((CTypeNode)y).ctype) { - case CharacterType.WORD: - if (!((CTypeNode)y).not) { - if (xc.mbuf == null && !xc.isNot()) { - for (int i=0; i 0) newValueException(ERR_NEVER_ENDING_RECURSION); - en.clearMark1(); - } - r = subexpInfRecursiveCheckTrav(en.target); - break; - - default: - break; - } // switch - - return r; - } - - private int subexpRecursiveCheck(Node node) { - int r = 0; - - switch (node.getType()) { - case NodeType.LIST: - case NodeType.ALT: - ConsAltNode can = (ConsAltNode)node; - do { - r |= subexpRecursiveCheck(can.car); - } while ((can = can.cdr) != null); - break; - - case NodeType.QTFR: - r = subexpRecursiveCheck(((QuantifierNode)node).target); - break; - - case NodeType.ANCHOR: - AnchorNode an = (AnchorNode)node; - switch (an.type) { - case AnchorType.PREC_READ: - case AnchorType.PREC_READ_NOT: - case AnchorType.LOOK_BEHIND: - case AnchorType.LOOK_BEHIND_NOT: - r = subexpRecursiveCheck(an.target); - break; - } // inner switch - break; - - case NodeType.CALL: - CallNode cn = (CallNode)node; - r = subexpRecursiveCheck(cn.target); - if (r != 0) cn.setRecursion(); - break; - - case NodeType.ENCLOSE: - EncloseNode en = (EncloseNode)node; - if (en.isMark2()) { - return 0; - } else if (en.isMark1()) { - return 1; /* recursion */ - } else { - en.setMark2(); - r = subexpRecursiveCheck(en.target); - en.clearMark2(); - } - break; - - default: - break; - } // switch - - return r; - } - - private static final int FOUND_CALLED_NODE = 1; - protected final int subexpRecursiveCheckTrav(Node node) { - int r = 0; - - switch (node.getType()) { - case NodeType.LIST: - case NodeType.ALT: - ConsAltNode can = (ConsAltNode)node; - do { - int ret = subexpRecursiveCheckTrav(can.car); - if (ret == FOUND_CALLED_NODE) { - r = FOUND_CALLED_NODE; - } - // else if (ret < 0) return ret; ??? - } while ((can = can.cdr) != null); - break; - - case NodeType.QTFR: - QuantifierNode qn = (QuantifierNode)node; - r = subexpRecursiveCheckTrav(qn.target); - if (qn.upper == 0) { - if (r == FOUND_CALLED_NODE) qn.isRefered = true; - } - break; - - case NodeType.ANCHOR: - AnchorNode an = (AnchorNode)node; - switch (an.type) { - case AnchorType.PREC_READ: - case AnchorType.PREC_READ_NOT: - case AnchorType.LOOK_BEHIND: - case AnchorType.LOOK_BEHIND_NOT: - r = subexpRecursiveCheckTrav(an.target); - break; - } // inner switch - break; - - case NodeType.ENCLOSE: - EncloseNode en = (EncloseNode)node; - if (!en.isRecursion()) { - if (en.isCalled()) { - en.setMark1(); - r = subexpRecursiveCheck(en.target); - if (r != 0) en.setRecursion(); - en.clearMark1(); - } - } - r = subexpRecursiveCheckTrav(en.target); - if (en.isCalled()) r |= FOUND_CALLED_NODE; - break; - - default: - break; - } // switch - - return r; - } - - private void setCallAttr(CallNode cn) { - cn.target = env.memNodes[cn.groupNum]; // no setTarget in call nodes! - if (cn.target == null) newValueException(ERR_UNDEFINED_NAME_REFERENCE, cn.nameP, cn.nameEnd); - - ((EncloseNode)cn.target).setCalled(); - env.btMemStart = BitStatus.bsOnAt(env.btMemStart, cn.groupNum); - cn.unsetAddrList = env.unsetAddrList; - } - - protected final void setupSubExpCall(Node node) { - - switch(node.getType()) { - case NodeType.LIST: - ConsAltNode ln = (ConsAltNode)node; - do { - setupSubExpCall(ln.car); - } while ((ln = ln.cdr) != null); - break; - - case NodeType.ALT: - ConsAltNode can = (ConsAltNode)node; - do { - setupSubExpCall(can.car); - } while ((can = can.cdr) != null); - break; - - case NodeType.QTFR: - setupSubExpCall(((QuantifierNode)node).target); - break; - - case NodeType.ENCLOSE: - setupSubExpCall(((EncloseNode)node).target); - break; - - case NodeType.CALL: - CallNode cn = (CallNode)node; - - if (cn.groupNum != 0) { - int gNum = cn.groupNum; - - if (Config.USE_NAMED_GROUP) { - if (env.numNamed > 0 && syntax.captureOnlyNamedGroup() && !isCaptureGroup(env.option)) { - newValueException(ERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED); - } - } // USE_NAMED_GROUP - if (gNum > env.numMem) newValueException(ERR_UNDEFINED_GROUP_REFERENCE, cn.nameP, cn.nameEnd); - setCallAttr(cn); - } else { - if (Config.USE_NAMED_GROUP) { - NameEntry ne = regex.nameToGroupNumbers(cn.name, cn.nameP, cn.nameEnd); - - if (ne == null) { - newValueException(ERR_UNDEFINED_NAME_REFERENCE, cn.nameP, cn.nameEnd); - } else if (ne.backNum > 1) { - newValueException(ERR_MULTIPLEX_DEFINITION_NAME_CALL, cn.nameP, cn.nameEnd); - } else { - cn.groupNum = ne.backRef1; // ne.backNum == 1 ? ne.backRef1 : ne.backRefs[0]; // ??? need to check ? - setCallAttr(cn); - } - } - } - break; - - case NodeType.ANCHOR: - AnchorNode an = (AnchorNode)node; - switch (an.type) { - case AnchorType.PREC_READ: - case AnchorType.PREC_READ_NOT: - case AnchorType.LOOK_BEHIND: - case AnchorType.LOOK_BEHIND_NOT: - setupSubExpCall(an.target); - break; - } - break; - - } // switch - } - /* divide different length alternatives in look-behind. (?<=A|B) ==> (?<=A)|(?<=B) (? (?= 0 && (ln = ln.cdr) != null); - break; - - case NodeType.ALT: - ConsAltNode an = (ConsAltNode)node; - do { - ret = setupCombExpCheck(an.car, state); - r |= ret; - } while (ret >= 0 && (an = an.cdr) != null); - break; - - case NodeType.QTFR: - QuantifierNode qn = (QuantifierNode)node; - int childState = state; - int addState = 0; - int varNum; - - if (!isRepeatInfinite(qn.upper)) { - if (qn.upper > 1) { - /* {0,1}, {1,1} are allowed */ - childState |= CEC_IN_FINITE_REPEAT; - - /* check (a*){n,m}, (a+){n,m} => (a*){n,n}, (a+){n,n} */ - if (env.backrefedMem == 0) { - if (qn.target.getType() == NodeType.ENCLOSE) { - EncloseNode en = (EncloseNode)qn.target; - if (en.type == EncloseType.MEMORY) { - if (en.target.getType() == NodeType.QTFR) { - QuantifierNode q = (QuantifierNode)en.target; - if (isRepeatInfinite(q.upper) && q.greedy == qn.greedy) { - qn.upper = qn.lower == 0 ? 1 : qn.lower; - if (qn.upper == 1) childState = state; - } - } - } - } - } - } - } - - if ((state & CEC_IN_FINITE_REPEAT) != 0) { - qn.combExpCheckNum = -1; - } else { - if (isRepeatInfinite(qn.upper)) { - varNum = CEC_INFINITE_NUM; - childState |= CEC_IN_INFINITE_REPEAT; - } else { - varNum = qn.upper - qn.lower; - } - - if (varNum >= CEC_THRES_NUM_BIG_REPEAT) addState |= CEC_CONT_BIG_REPEAT; - - if (((state & CEC_IN_INFINITE_REPEAT) != 0 && varNum != 0) || - ((state & CEC_CONT_BIG_REPEAT) != 0 && varNum >= CEC_THRES_NUM_BIG_REPEAT)) { - if (qn.combExpCheckNum == 0) { - env.numCombExpCheck++; - qn.combExpCheckNum = env.numCombExpCheck; - if (env.currMaxRegNum > env.combExpMaxRegNum) { - env.combExpMaxRegNum = env.currMaxRegNum; - } - } - } - } - r = setupCombExpCheck(qn.target, childState); - r |= addState; - break; - - case NodeType.ENCLOSE: - EncloseNode en = (EncloseNode)node; - switch( en.type) { - case EncloseNode.MEMORY: - if (env.currMaxRegNum < en.regNum) { - env.currMaxRegNum = en.regNum; - } - r = setupCombExpCheck(en.target, state); - break; - - default: - r = setupCombExpCheck(en.target, state); - } // inner switch - break; - - case NodeType.CALL: - if (Config.USE_SUBEXP_CALL) { - CallNode cn = (CallNode)node; - if (cn.isRecursion()) { - env.hasRecursion = true; - } else { - r = setupCombExpCheck(cn.target, state); - } - } // USE_SUBEXP_CALL - break; - - default: - break; - - } // switch - - return r; - } - private static final int IN_ALT = (1<<0); private static final int IN_NOT = (1<<1); private static final int IN_REPEAT = (1<<2); @@ -1691,20 +953,12 @@ case NodeType.CANY: break; - case NodeType.CALL: // if (Config.USE_SUBEXP_CALL) ? - break; - case NodeType.BREF: BackRefNode br = (BackRefNode)node; for (int i=0; i env.numMem) newValueException(ERR_INVALID_BACKREF); env.backrefedMem = bsOnAt(env.backrefedMem, br.back[i]); env.btMemStart = bsOnAt(env.btMemStart, br.back[i]); - if (Config.USE_BACKREF_WITH_LEVEL) { - if (br.isNestLevel()) { - env.btMemEnd = bsOnAt(env.btMemEnd, br.back[i]); - } - } // USE_BACKREF_AT_LEVEL ((EncloseNode)env.memNodes[br.back[i]]).setMemBackrefed(); } break; @@ -1916,37 +1170,6 @@ break; } - case NodeType.CTYPE: { - int min; - int max = 1; - if (max == 1) { - min = 1; - CTypeNode cn = (CTypeNode)node; - - switch (cn.ctype) { - case CharacterType.WORD: - if (cn.not) { - for (int i=0; i MAX_NODE_OPT_INFO_REF_COUNT) { + if (++en.optCount > MAX_NODE_OPT_INFO_REF_COUNT) { int min = 0; int max = MinMaxLen.INFINITE_DISTANCE; if (en.isMinFixed()) min = en.minLength; diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ArrayCompiler.java Wed Jul 05 18:57:52 2017 +0200 @@ -28,8 +28,6 @@ import jdk.nashorn.internal.runtime.regexp.joni.ast.AnchorNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.BackRefNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode; -import jdk.nashorn.internal.runtime.regexp.joni.ast.CTypeNode; -import jdk.nashorn.internal.runtime.regexp.joni.ast.CallNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.ConsAltNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.EncloseNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.Node; @@ -71,11 +69,6 @@ regex.templates = templates; regex.templateNum = templateNum; regex.factory = MatcherFactory.DEFAULT; - - if (Config.USE_SUBEXP_CALL && analyser.env.unsetAddrList != null) { - analyser.env.unsetAddrList.fix(regex); - analyser.env.unsetAddrList = null; - } } @Override @@ -119,7 +112,7 @@ return isNeedStrLenOpExact(op); } - private int selectStrOpcode(int mbLength, int strLength, boolean ignoreCase) { + private int selectStrOpcode(int strLength, boolean ignoreCase) { int op; if (ignoreCase) { @@ -128,31 +121,14 @@ default:op = OPCode.EXACTN_IC; break; } // switch } else { - switch (mbLength) { - case 1: - switch (strLength) { - case 1: op = OPCode.EXACT1; break; - case 2: op = OPCode.EXACT2; break; - case 3: op = OPCode.EXACT3; break; - case 4: op = OPCode.EXACT4; break; - case 5: op = OPCode.EXACT5; break; - default:op = OPCode.EXACTN; break; - } // inner switch - break; - case 2: - switch (strLength) { - case 1: op = OPCode.EXACTMB2N1; break; - case 2: op = OPCode.EXACTMB2N2; break; - case 3: op = OPCode.EXACTMB2N3; break; - default:op = OPCode.EXACTMB2N; break; - } // inner switch - break; - case 3: - op = OPCode.EXACTMB3N; - break; - default: - op = OPCode.EXACTMBN; - } // switch + switch (strLength) { + case 1: op = OPCode.EXACT1; break; + case 2: op = OPCode.EXACT2; break; + case 3: op = OPCode.EXACT3; break; + case 4: op = OPCode.EXACT4; break; + case 5: op = OPCode.EXACT5; break; + default:op = OPCode.EXACTN; break; + } // inner switch } return op; } @@ -185,8 +161,8 @@ } } - private int addCompileStringlength(char[] chars, int p, int mbLength, int strLength, boolean ignoreCase) { - int op = selectStrOpcode(mbLength, strLength, ignoreCase); + private int addCompileStringlength(char[] chars, int p, int strLength, boolean ignoreCase) { + int op = selectStrOpcode(strLength, ignoreCase); int len = OPSize.OPCODE; if (Config.USE_STRING_TEMPLATES && opTemplated(op)) { @@ -194,25 +170,21 @@ len += OPSize.LENGTH + OPSize.INDEX + OPSize.INDEX; } else { if (isNeedStrLenOpExact(op)) len += OPSize.LENGTH; - len += mbLength * strLength; + len += strLength; } if (op == OPCode.EXACTMBN) len += OPSize.LENGTH; return len; } @Override - protected final void addCompileString(char[] chars, int p, int mbLength, int strLength, boolean ignoreCase) { - int op = selectStrOpcode(mbLength, strLength, ignoreCase); + protected final void addCompileString(char[] chars, int p, int strLength, boolean ignoreCase) { + int op = selectStrOpcode(strLength, ignoreCase); addOpcode(op); - if (op == OPCode.EXACTMBN) addLength(mbLength); + if (op == OPCode.EXACTMBN) addLength(1); if (isNeedStrLenOpExact(op)) { - if (op == OPCode.EXACTN_IC || op == OPCode.EXACTN_IC_SB) { - addLength(mbLength * strLength); - } else { - addLength(strLength); - } + addLength(strLength); } if (Config.USE_STRING_TEMPLATES && opTemplated(op)) { @@ -220,7 +192,7 @@ addInt(p); addTemplate(chars); } else { - addChars(chars, p, mbLength * strLength); + addChars(chars, p, strLength); } } @@ -242,14 +214,14 @@ slen++; p++; } - int r = addCompileStringlength(chars, prev, 1, slen, ambig); + int r = addCompileStringlength(chars, prev, slen, ambig); rlen += r; return rlen; } private int compileLengthStringRawNode(StringNode sn) { if (sn.length() <= 0) return 0; - return addCompileStringlength(sn.chars, sn.p, 1 /*sb*/, sn.length(), false); + return addCompileStringlength(sn.chars, sn.p, sn.length(), false); } private void addMultiByteCClass(CodeRangeBuffer mbuf) { @@ -312,26 +284,6 @@ } @Override - protected void compileCTypeNode(CTypeNode node) { - CTypeNode cn = node; - int op; - switch (cn.ctype) { - case CharacterType.WORD: - if (cn.not) { - op = OPCode.NOT_WORD; - } else { - op = OPCode.WORD; - } - break; - - default: - newInternalException(ERR_PARSER_BUG); - return; // not reached - } // inner switch - addOpcode(op); - } - - @Override protected void compileAnyCharNode() { if (isMultiline(regex.options)) { addOpcode(OPCode.ANYCHAR_ML); @@ -341,30 +293,15 @@ } @Override - protected void compileCallNode(CallNode node) { - addOpcode(OPCode.CALL); - node.unsetAddrList.add(codeLength, node.target); - addAbsAddr(0); /*dummy addr.*/ - } - - @Override protected void compileBackrefNode(BackRefNode node) { BackRefNode br = node; - if (Config.USE_BACKREF_WITH_LEVEL && br.isNestLevel()) { - addOpcode(OPCode.BACKREF_WITH_LEVEL); - addOption(regex.options & Option.IGNORECASE); - addLength(br.nestLevel); - // !goto add_bacref_mems;! - addLength(br.backNum); - for (int i=br.backNum-1; i>=0; i--) addMemNum(br.back[i]); - return; - } else { // USE_BACKREF_AT_LEVEL - if (br.backNum == 1) { - if (isIgnoreCase(regex.options)) { - addOpcode(OPCode.BACKREFN_IC); - addMemNum(br.back[0]); - } else { - switch (br.back[0]) { + // USE_BACKREF_AT_LEVEL + if (br.backNum == 1) { + if (isIgnoreCase(regex.options)) { + addOpcode(OPCode.BACKREFN_IC); + addMemNum(br.back[0]); + } else { + switch (br.back[0]) { case 1: addOpcode(OPCode.BACKREF1); break; @@ -375,18 +312,17 @@ addOpcode(OPCode.BACKREFN); addOpcode(br.back[0]); break; - } // switch - } + } // switch + } + } else { + if (isIgnoreCase(regex.options)) { + addOpcode(OPCode.BACKREF_MULTI_IC); } else { - if (isIgnoreCase(regex.options)) { - addOpcode(OPCode.BACKREF_MULTI_IC); - } else { - addOpcode(OPCode.BACKREF_MULTI); - } - // !add_bacref_mems:! - addLength(br.backNum); - for (int i=br.backNum-1; i>=0; i--) addMemNum(br.back[i]); + addOpcode(OPCode.BACKREF_MULTI); } + // !add_bacref_mems:! + addLength(br.backNum); + for (int i=br.backNum-1; i>=0; i--) addMemNum(br.back[i]); } } @@ -419,7 +355,7 @@ compileTreeEmptyCheck(qn.target, emptyInfo); - if ((Config.USE_SUBEXP_CALL && regex.numCall > 0) || qn.isInRepeat()) { + if (qn.isInRepeat()) { addOpcode(qn.greedy ? OPCode.REPEAT_INC_SG : OPCode.REPEAT_INC_NG_SG); } else { addOpcode(qn.greedy ? OPCode.REPEAT_INC : OPCode.REPEAT_INC_NG); @@ -434,193 +370,6 @@ return ckn > 0; } - private int compileCECLengthQuantifierNode(QuantifierNode qn) { - boolean infinite = isRepeatInfinite(qn.upper); - int emptyInfo = qn.targetEmptyInfo; - - int tlen = compileLengthTree(qn.target); - int ckn = regex.numCombExpCheck > 0 ? qn.combExpCheckNum : 0; - int cklen = cknOn(ckn) ? OPSize.STATE_CHECK_NUM : 0; - - /* anychar repeat */ - if (qn.target.getType() == NodeType.CANY) { - if (qn.greedy && infinite) { - if (qn.nextHeadExact != null && !cknOn(ckn)) { - return OPSize.ANYCHAR_STAR_PEEK_NEXT + tlen * qn.lower + cklen; - } else { - return OPSize.ANYCHAR_STAR + tlen * qn.lower + cklen; - } - } - } - - int modTLen; - if (emptyInfo != 0) { - modTLen = tlen + (OPSize.NULL_CHECK_START + OPSize.NULL_CHECK_END); - } else { - modTLen = tlen; - } - - int len; - if (infinite && qn.lower <= 1) { - if (qn.greedy) { - if (qn.lower == 1) { - len = OPSize.JUMP; - } else { - len = 0; - } - len += OPSize.PUSH + cklen + modTLen + OPSize.JUMP; - } else { - if (qn.lower == 0) { - len = OPSize.JUMP; - } else { - len = 0; - } - len += modTLen + OPSize.PUSH + cklen; - } - } else if (qn.upper == 0) { - if (qn.isRefered) { /* /(?..){0}/ */ - len = OPSize.JUMP + tlen; - } else { - len = 0; - } - } else if (qn.upper == 1 && qn.greedy) { - if (qn.lower == 0) { - if (cknOn(ckn)) { - len = OPSize.STATE_CHECK_PUSH + tlen; - } else { - len = OPSize.PUSH + tlen; - } - } else { - len = tlen; - } - } else if (!qn.greedy && qn.upper == 1 && qn.lower == 0) { /* '??' */ - len = OPSize.PUSH + cklen + OPSize.JUMP + tlen; - } else { - len = OPSize.REPEAT_INC + modTLen + OPSize.OPCODE + OPSize.RELADDR + OPSize.MEMNUM; - - if (cknOn(ckn)) { - len += OPSize.STATE_CHECK; - } - } - return len; - } - - @Override - protected void compileCECQuantifierNode(QuantifierNode qn) { - boolean infinite = isRepeatInfinite(qn.upper); - int emptyInfo = qn.targetEmptyInfo; - - int tlen = compileLengthTree(qn.target); - - int ckn = regex.numCombExpCheck > 0 ? qn.combExpCheckNum : 0; - - if (qn.isAnyCharStar()) { - compileTreeNTimes(qn.target, qn.lower); - if (qn.nextHeadExact != null && !cknOn(ckn)) { - if (isMultiline(regex.options)) { - addOpcode(OPCode.ANYCHAR_ML_STAR_PEEK_NEXT); - } else { - addOpcode(OPCode.ANYCHAR_STAR_PEEK_NEXT); - } - if (cknOn(ckn)) { - addStateCheckNum(ckn); - } - StringNode sn = (StringNode)qn.nextHeadExact; - addChars(sn.chars, sn.p, 1); - return; - } else { - if (isMultiline(regex.options)) { - if (cknOn(ckn)) { - addOpcode(OPCode.STATE_CHECK_ANYCHAR_ML_STAR); - } else { - addOpcode(OPCode.ANYCHAR_ML_STAR); - } - } else { - if (cknOn(ckn)) { - addOpcode(OPCode.STATE_CHECK_ANYCHAR_STAR); - } else { - addOpcode(OPCode.ANYCHAR_STAR); - } - } - if (cknOn(ckn)) { - addStateCheckNum(ckn); - } - return; - } - } - - int modTLen; - if (emptyInfo != 0) { - modTLen = tlen + (OPSize.NULL_CHECK_START + OPSize.NULL_CHECK_END); - } else { - modTLen = tlen; - } - if (infinite && qn.lower <= 1) { - if (qn.greedy) { - if (qn.lower == 1) { - addOpcodeRelAddr(OPCode.JUMP, cknOn(ckn) ? OPSize.STATE_CHECK_PUSH : - OPSize.PUSH); - } - if (cknOn(ckn)) { - addOpcode(OPCode.STATE_CHECK_PUSH); - addStateCheckNum(ckn); - addRelAddr(modTLen + OPSize.JUMP); - } else { - addOpcodeRelAddr(OPCode.PUSH, modTLen + OPSize.JUMP); - } - compileTreeEmptyCheck(qn.target, emptyInfo); - addOpcodeRelAddr(OPCode.JUMP, -(modTLen + OPSize.JUMP + (cknOn(ckn) ? - OPSize.STATE_CHECK_PUSH : - OPSize.PUSH))); - } else { - if (qn.lower == 0) { - addOpcodeRelAddr(OPCode.JUMP, modTLen); - } - compileTreeEmptyCheck(qn.target, emptyInfo); - if (cknOn(ckn)) { - addOpcode(OPCode.STATE_CHECK_PUSH_OR_JUMP); - addStateCheckNum(ckn); - addRelAddr(-(modTLen + OPSize.STATE_CHECK_PUSH_OR_JUMP)); - } else { - addOpcodeRelAddr(OPCode.PUSH, -(modTLen + OPSize.PUSH)); - } - } - } else if (qn.upper == 0) { - if (qn.isRefered) { /* /(?..){0}/ */ - addOpcodeRelAddr(OPCode.JUMP, tlen); - compileTree(qn.target); - } // else r=0 ??? - } else if (qn.upper == 1 && qn.greedy) { - if (qn.lower == 0) { - if (cknOn(ckn)) { - addOpcode(OPCode.STATE_CHECK_PUSH); - addStateCheckNum(ckn); - addRelAddr(tlen); - } else { - addOpcodeRelAddr(OPCode.PUSH, tlen); - } - } - compileTree(qn.target); - } else if (!qn.greedy && qn.upper == 1 && qn.lower == 0){ /* '??' */ - if (cknOn(ckn)) { - addOpcode(OPCode.STATE_CHECK_PUSH); - addStateCheckNum(ckn); - addRelAddr(OPSize.JUMP); - } else { - addOpcodeRelAddr(OPCode.PUSH, OPSize.JUMP); - } - - addOpcodeRelAddr(OPCode.JUMP, tlen); - compileTree(qn.target); - } else { - compileRangeRepeatNode(qn, modTLen, emptyInfo); - if (cknOn(ckn)) { - addOpcode(OPCode.STATE_CHECK); - addStateCheckNum(ckn); - } - } - } - private int compileNonCECLengthQuantifierNode(QuantifierNode qn) { boolean infinite = isRepeatInfinite(qn.upper); int emptyInfo = qn.targetEmptyInfo; @@ -821,21 +570,12 @@ int len; switch (node.type) { case EncloseType.MEMORY: - if (Config.USE_SUBEXP_CALL && node.isCalled()) { - len = OPSize.MEMORY_START_PUSH + tlen + OPSize.CALL + OPSize.JUMP + OPSize.RETURN; - if (bsAt(regex.btMemEnd, node.regNum)) { - len += node.isRecursion() ? OPSize.MEMORY_END_PUSH_REC : OPSize.MEMORY_END_PUSH; - } else { - len += node.isRecursion() ? OPSize.MEMORY_END_REC : OPSize.MEMORY_END; - } - } else { // USE_SUBEXP_CALL - if (bsAt(regex.btMemStart, node.regNum)) { - len = OPSize.MEMORY_START_PUSH; - } else { - len = OPSize.MEMORY_START; - } - len += tlen + (bsAt(regex.btMemEnd, node.regNum) ? OPSize.MEMORY_END_PUSH : OPSize.MEMORY_END); + if (bsAt(regex.btMemStart, node.regNum)) { + len = OPSize.MEMORY_START_PUSH; + } else { + len = OPSize.MEMORY_START; } + len += tlen + (bsAt(regex.btMemEnd, node.regNum) ? OPSize.MEMORY_END_PUSH : OPSize.MEMORY_END); break; case EncloseType.STOP_BACKTRACK: @@ -860,23 +600,6 @@ int len; switch (node.type) { case EncloseType.MEMORY: - if (Config.USE_SUBEXP_CALL) { - if (node.isCalled()) { - addOpcode(OPCode.CALL); - node.callAddr = codeLength + OPSize.ABSADDR + OPSize.JUMP; - node.setAddrFixed(); - addAbsAddr(node.callAddr); - len = compileLengthTree(node.target); - len += OPSize.MEMORY_START_PUSH + OPSize.RETURN; - if (bsAt(regex.btMemEnd, node.regNum)) { - len += node.isRecursion() ? OPSize.MEMORY_END_PUSH_REC : OPSize.MEMORY_END_PUSH; - } else { - len += node.isRecursion() ? OPSize.MEMORY_END_REC : OPSize.MEMORY_END; - } - addOpcodeRelAddr(OPCode.JUMP, len); - } - } // USE_SUBEXP_CALL - if (bsAt(regex.btMemStart, node.regNum)) { addOpcode(OPCode.MEMORY_START_PUSH); } else { @@ -886,22 +609,12 @@ addMemNum(node.regNum); compileTree(node.target); - if (Config.USE_SUBEXP_CALL && node.isCalled()) { - if (bsAt(regex.btMemEnd, node.regNum)) { - addOpcode(node.isRecursion() ? OPCode.MEMORY_END_PUSH_REC : OPCode.MEMORY_END_PUSH); - } else { - addOpcode(node.isRecursion() ? OPCode.MEMORY_END_REC : OPCode.MEMORY_END); - } - addMemNum(node.regNum); - addOpcode(OPCode.RETURN); - } else { // USE_SUBEXP_CALL - if (bsAt(regex.btMemEnd, node.regNum)) { - addOpcode(OPCode.MEMORY_END_PUSH); - } else { - addOpcode(OPCode.MEMORY_END); - } - addMemNum(node.regNum); + if (bsAt(regex.btMemEnd, node.regNum)) { + addOpcode(OPCode.MEMORY_END_PUSH); + } else { + addOpcode(OPCode.MEMORY_END); } + addMemNum(node.regNum); break; case EncloseType.STOP_BACKTRACK: @@ -1078,32 +791,17 @@ case NodeType.BREF: BackRefNode br = (BackRefNode)node; - if (Config.USE_BACKREF_WITH_LEVEL && br.isNestLevel()) { - len = OPSize.OPCODE + OPSize.OPTION + OPSize.LENGTH + - OPSize.LENGTH + (OPSize.MEMNUM * br.backNum); - } else { // USE_BACKREF_AT_LEVEL - if (br.backNum == 1) { - len = ((!isIgnoreCase(regex.options) && br.back[0] <= 2) - ? OPSize.OPCODE : (OPSize.OPCODE + OPSize.MEMNUM)); - } else { - len = OPSize.OPCODE + OPSize.LENGTH + (OPSize.MEMNUM * br.backNum); - } + // USE_BACKREF_AT_LEVEL + if (br.backNum == 1) { + len = ((!isIgnoreCase(regex.options) && br.back[0] <= 2) + ? OPSize.OPCODE : (OPSize.OPCODE + OPSize.MEMNUM)); + } else { + len = OPSize.OPCODE + OPSize.LENGTH + (OPSize.MEMNUM * br.backNum); } break; - case NodeType.CALL: - if (Config.USE_SUBEXP_CALL) { - len = OPSize.CALL; - break; - } // USE_SUBEXP_CALL - break; - case NodeType.QTFR: - if (Config.USE_COMBINATION_EXPLOSION_CHECK) { - len = compileCECLengthQuantifierNode((QuantifierNode)node); - } else { - len = compileNonCECLengthQuantifierNode((QuantifierNode)node); - } + len = compileNonCECLengthQuantifierNode((QuantifierNode)node); break; case NodeType.ENCLOSE: diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompiler.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompiler.java Thu May 30 10:58:13 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,109 +0,0 @@ -/* - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package jdk.nashorn.internal.runtime.regexp.joni; - -import jdk.nashorn.internal.runtime.regexp.joni.ast.AnchorNode; -import jdk.nashorn.internal.runtime.regexp.joni.ast.BackRefNode; -import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode; -import jdk.nashorn.internal.runtime.regexp.joni.ast.CTypeNode; -import jdk.nashorn.internal.runtime.regexp.joni.ast.CallNode; -import jdk.nashorn.internal.runtime.regexp.joni.ast.ConsAltNode; -import jdk.nashorn.internal.runtime.regexp.joni.ast.EncloseNode; -import jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode; - -final class AsmCompiler extends AsmCompilerSupport { - - public AsmCompiler(Analyser analyser) { - super(analyser); - } - - @Override - protected void prepare() { - REG_NUM++; - prepareMachine(); - prepareMachineInit(); - prepareMachineMatch(); - - prepareFactory(); - prepareFactoryInit(); - } - - @Override - protected void finish() { - setupFactoryInit(); - - setupMachineInit(); - setupMachineMatch(); - - setupClasses(); - } - - @Override - protected void compileAltNode(ConsAltNode node) { - } - - @Override - protected void addCompileString(char[] chars, int p, int mbLength, int strLength, boolean ignoreCase) { - String template = installTemplate(chars, p, strLength); - } - - @Override - protected void compileCClassNode(CClassNode node) { - if (node.bs != null) { - String bitsetName = installBitSet(node.bs.bits); - } - } - - @Override - protected void compileCTypeNode(CTypeNode node) { - } - - @Override - protected void compileAnyCharNode() { - } - - @Override - protected void compileBackrefNode(BackRefNode node) { - } - - @Override - protected void compileCallNode(CallNode node) { - } - - @Override - protected void compileCECQuantifierNode(QuantifierNode node) { - } - - @Override - protected void compileNonCECQuantifierNode(QuantifierNode node) { - } - - @Override - protected void compileOptionNode(EncloseNode node) { - } - - @Override - protected void compileEncloseNode(EncloseNode node) { - } - - @Override - protected void compileAnchorNode(AnchorNode node) { - } -} diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompilerSupport.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/AsmCompilerSupport.java Thu May 30 10:58:13 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,267 +0,0 @@ -/* - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package jdk.nashorn.internal.runtime.regexp.joni; - -import java.io.FileOutputStream; -import java.io.IOException; - -import jdk.nashorn.internal.runtime.regexp.joni.constants.AsmConstants; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import jdk.internal.org.objectweb.asm.Opcodes; - -abstract class AsmCompilerSupport extends Compiler implements Opcodes, AsmConstants { - protected ClassWriter factory; // matcher allocator, also bit set, code rage and string template container - protected MethodVisitor factoryInit;// factory constructor - protected String factoryName; - - protected ClassWriter machine; // matcher - protected MethodVisitor machineInit;// matcher constructor - protected MethodVisitor match; // actual matcher implementation (the matchAt method) - protected String machineName; - - // we will? try to manage visitMaxs ourselves for efficiency - protected int maxStack = 1; - protected int maxVars = LAST_INDEX; - - // for field generation - protected int bitsets, ranges, templates; - - // simple class name postfix scheme for now - static int REG_NUM = 0; - - // dummy class loader for now - private static final class DummyClassLoader extends ClassLoader { - public Class defineClass(String name, byte[] bytes) { - return super.defineClass(name, bytes, 0, bytes.length); - } - }; - - private static final DummyClassLoader loader = new DummyClassLoader(); - - AsmCompilerSupport(Analyser analyser) { - super(analyser); - } - - protected final void prepareFactory() { - factory = new ClassWriter(ClassWriter.COMPUTE_MAXS); - factoryName = "jdk/nashorn/internal/runtime/regexp/joni/MatcherFactory" + REG_NUM; - - factory.visit(V1_4, ACC_PUBLIC + ACC_FINAL, factoryName, null, "jdk/nashorn/internal/runtime/regexp/joni/MatcherFactory", null); - - MethodVisitor create = factory.visitMethod(ACC_SYNTHETIC, "create", "(Lorg/joni/Regex;[BII)Lorg/joni/Matcher;", null, null); - create.visitTypeInsn(NEW, machineName); - create.visitInsn(DUP); // instance - create.visitVarInsn(ALOAD, 1); // Regex - create.visitVarInsn(ALOAD, 2); // bytes[] - create.visitVarInsn(ILOAD, 3); // p - create.visitVarInsn(ILOAD, 4); // end - create.visitMethodInsn(INVOKESPECIAL, machineName, "", "(Lorg/joni/Regex;[BII)V"); - create.visitInsn(ARETURN); - create.visitMaxs(0, 0); - //create.visitMaxs(6, 5); - create.visitEnd(); - } - - protected final void prepareFactoryInit() { - factoryInit = factory.visitMethod(ACC_PUBLIC, "", "()V", null, null); - factoryInit.visitVarInsn(ALOAD, 0); - factoryInit.visitMethodInsn(INVOKESPECIAL, "jdk/nashorn/internal/runtime/regexp/joni/MatcherFactory", "", "()V"); - } - - protected final void setupFactoryInit() { - factoryInit.visitInsn(RETURN); - factoryInit.visitMaxs(0, 0); - //init.visitMaxs(1, 1); - factoryInit.visitEnd(); - } - - protected final void prepareMachine() { - machine = new ClassWriter(ClassWriter.COMPUTE_MAXS); - machineName = "jdk/nashorn/internal/runtime/regexp/joni/NativeMachine" + REG_NUM; - } - - protected final void prepareMachineInit() { - machine.visit(V1_4, ACC_PUBLIC + ACC_FINAL, machineName, null, "jdk/nashorn/internal/runtime/regexp/joni/NativeMachine", null); - machineInit = machine.visitMethod(ACC_PROTECTED, "", "(Lorg/joni/Regex;[BII)V", null, null); - machineInit.visitVarInsn(ALOAD, THIS); // this - machineInit.visitVarInsn(ALOAD, 1); // Regex - machineInit.visitVarInsn(ALOAD, 2); // bytes[] - machineInit.visitVarInsn(ILOAD, 3); // p - machineInit.visitVarInsn(ILOAD, 4); // end - machineInit.visitMethodInsn(INVOKESPECIAL, "jdk/nashorn/internal/runtime/regexp/joni/NativeMachine", "", "(Lorg/joni/Regex;[BII)V"); - } - - protected final void setupMachineInit() { - if (bitsets + ranges + templates > 0) { // ok, some of these are in use, we'd like to cache the factory - machine.visitField(ACC_PRIVATE + ACC_FINAL, "factory", "L" + factoryName + ";", null, null); - machineInit.visitVarInsn(ALOAD, THIS); // this - machineInit.visitVarInsn(ALOAD, 1); // this, Regex - machineInit.visitFieldInsn(GETFIELD, "jdk/nashorn/internal/runtime/regexp/joni/Regex", "factory", "Lorg/joni/MatcherFactory;"); // this, factory - machineInit.visitTypeInsn(CHECKCAST, factoryName); - machineInit.visitFieldInsn(PUTFIELD, machineName, "factory", "L" + factoryName + ";"); // [] - } - - machineInit.visitInsn(RETURN); - machineInit.visitMaxs(0, 0); - //init.visitMaxs(5, 5); - machineInit.visitEnd(); - } - - protected final void prepareMachineMatch() { - match = machine.visitMethod(ACC_SYNTHETIC, "matchAt", "(III)I", null, null); - move(S, SSTART); // s = sstart - load("bytes", "[B"); // - astore(BYTES); // byte[]bytes = this.bytes - } - - protected final void setupMachineMatch() { - match.visitInsn(ICONST_M1); - match.visitInsn(IRETURN); - - match.visitMaxs(maxStack, maxVars); - match.visitEnd(); - } - - protected final void setupClasses() { - byte[]factoryCode = factory.toByteArray(); - byte[]machineCode = machine.toByteArray(); - - if (Config.DEBUG_ASM) { - try { - FileOutputStream fos; - fos = new FileOutputStream(factoryName.substring(factoryName.lastIndexOf('/') + 1) + ".class"); - fos.write(factoryCode); - fos.close(); - fos = new FileOutputStream(machineName.substring(machineName.lastIndexOf('/') + 1) + ".class"); - fos.write(machineCode); - fos.close(); - } catch (IOException ioe) { - ioe.printStackTrace(Config.err); - } - } - - loader.defineClass(machineName.replace('/', '.'), machineCode); - Class cls = loader.defineClass(factoryName.replace('/', '.'), factoryCode); - try { - regex.factory = (MatcherFactory)cls.newInstance(); - } catch(Exception e) { - e.printStackTrace(Config.err); - } - } - - protected final void aload(int var) { - match.visitVarInsn(ALOAD, var); - } - - protected final void astore(int var) { - match.visitVarInsn(ASTORE, var); - } - - protected final void loadThis() { - match.visitVarInsn(ALOAD, THIS); - } - - protected final void load(int var) { - match.visitVarInsn(ILOAD, var); - } - - protected final void store(int var) { - match.visitVarInsn(ISTORE, var); - } - - protected final void move(int to, int from) { - load(from); - store(to); - } - - protected final void load(String field, String singature) { - loadThis(); - match.visitFieldInsn(GETFIELD, machineName, field, singature); - } - - protected final void load(String field) { - load(field, "I"); - } - - protected final void store(String field, String singature) { - loadThis(); - match.visitFieldInsn(PUTFIELD, machineName, field, singature); - } - - protected final void store(String field) { - store(field, "I"); - } - - protected final String installTemplate(char[] arr, int p, int length) { - String templateName = TEMPLATE + ++templates; - installArray(templateName, arr, p, length); - return templateName; - } - - protected final String installCodeRange(int[]arr) { - String coreRangeName = CODERANGE + ++ranges; - installArray(coreRangeName, arr); - return coreRangeName; - } - - protected final String installBitSet(int[]arr) { - String bitsetName = BITSET + ++bitsets; - installArray(bitsetName, arr); - return bitsetName; - } - - private void installArray(String name, int[]arr) { - factory.visitField(ACC_PRIVATE + ACC_FINAL, name, "[I", null, null); - factoryInit.visitVarInsn(ALOAD, THIS); // this; - loadInt(factoryInit, arr.length); // this, length - factoryInit.visitIntInsn(NEWARRAY, T_INT); // this, arr - for (int i=0;i < arr.length; i++) buildArray(i, arr[i], IASTORE); - factoryInit.visitFieldInsn(PUTFIELD, factoryName, name, "[I"); - } - - private void installArray(String name, char[]arr, int p, int length) { - factory.visitField(ACC_PRIVATE + ACC_FINAL, name, "[B", null, null); - factoryInit.visitVarInsn(ALOAD, THIS); // this; - loadInt(factoryInit, arr.length); // this, length - factoryInit.visitIntInsn(NEWARRAY, T_BYTE); // this, arr - for (int i=p, j=0; i < p + length; i++, j++) buildArray(j, arr[i] & 0xff, BASTORE); - factoryInit.visitFieldInsn(PUTFIELD, factoryName, name, "[B"); - } - - private void buildArray(int index, int value, int type) { - factoryInit.visitInsn(DUP); // ... arr, arr - loadInt(factoryInit, index); // ... arr, arr, index - loadInt(factoryInit, value); // ... arr, arr, index, value - factoryInit.visitInsn(type); // ... arr - } - - private void loadInt(MethodVisitor mv, int value) { - if (value >= -1 && value <= 5) { - mv.visitInsn(value + ICONST_0); // ICONST_0 == 3 - } else if (value >= 6 && value <= 127 || value >= -128 && value <= -2) { - mv.visitIntInsn(BIPUSH, value); - } else if (value >= 128 && value <= 32767 || value >= -32768 && value <= -129) { - mv.visitIntInsn(SIPUSH, value); - } else { - mv.visitLdcInsn(new Integer(value)); - } - } -} diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/BitSet.java Wed Jul 05 18:57:52 2017 +0200 @@ -51,10 +51,6 @@ bits[pos >>> ROOM_SHIFT] &= ~bit(pos); } - public void invert(int pos) { - bits[pos >>> ROOM_SHIFT] ^= bit(pos); - } - public void clear() { for (int i=0; i range) {opFail(); return;} - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - sprev = sbegin; // break; - } - - private void opExactMB2N2() { - if (s + 4 > range) {opFail(); return;} - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - sprev = s; - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - } - - private void opExactMB2N3() { - if (s + 6 > range) {opFail(); return;} - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - sprev = s; - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - } - - private void opExactMB2N() { - int tlen = code[ip++]; - if (s + tlen * 2 > range) {opFail(); return;} - - if (Config.USE_STRING_TEMPLATES) { - char[] bs = regex.templates[code[ip++]]; - int ps = code[ip++]; - - while(tlen-- > 0) { - if (bs[ps] != chars[s]) {opFail(); return;} - ps++; s++; - if (bs[ps] != chars[s]) {opFail(); return;} - ps++; s++; - } - } else { - while(tlen-- > 0) { - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - } - } - sprev = s - 2; - } - - private void opExactMB3N() { - int tlen = code[ip++]; - if (s + tlen * 3 > range) {opFail(); return;} - - if (Config.USE_STRING_TEMPLATES) { - char[] bs = regex.templates[code[ip++]]; - int ps = code[ip++]; - - while (tlen-- > 0) { - if (bs[ps] != chars[s]) {opFail(); return;} - ps++; s++; - if (bs[ps] != chars[s]) {opFail(); return;} - ps++; s++; - if (bs[ps] != chars[s]) {opFail(); return;} - ps++; s++; - } - } else { - while (tlen-- > 0) { - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - } - } - - sprev = s - 3; - } - - private void opExactMBN() { - int tlen = code[ip++]; /* mb-len */ - int tlen2= code[ip++]; /* string len */ - - tlen2 *= tlen; - if (s + tlen2 > range) {opFail(); return;} - - if (Config.USE_STRING_TEMPLATES) { - char[] bs = regex.templates[code[ip++]]; - int ps = code[ip++]; - - while (tlen2-- > 0) { - if (bs[ps] != chars[s]) {opFail(); return;} - ps++; s++; - } - } else { - while (tlen2-- > 0) { - if (code[ip] != chars[s]) {opFail(); return;} - ip++; s++; - } - } - - sprev = s - tlen; - } - private void opExact1IC() { if (s >= range || code[ip] != Character.toLowerCase(chars[s++])) {opFail(); return;} ip++; @@ -748,34 +558,6 @@ sprev = sbegin; // break; } - // CEC - private void opStateCheckAnyCharStar() { - int mem = code[ip++]; - final char[] chars = this.chars; - - while (s < range) { - if (stateCheckVal(s, mem)) {opFail(); return;} - pushAltWithStateCheck(ip, s, sprev, mem); - if (chars[s] == EncodingHelper.NEW_LINE) {opFail(); return;} - sprev = s; - s++; - } - sprev = sbegin; // break; - } - - // CEC - private void opStateCheckAnyCharMLStar() { - int mem = code[ip++]; - - while (s < range) { - if (stateCheckVal(s, mem)) {opFail(); return;} - pushAltWithStateCheck(ip, s, sprev, mem); - sprev = s; - s++; - } - sprev = sbegin; // break; - } - private void opWord() { if (s >= range || !EncodingHelper.isWord(chars[s])) {opFail(); return;} s++; @@ -1223,33 +1005,6 @@ pushAlt(ip + addr, s, sprev); } - // CEC - private void opStateCheckPush() { - int mem = code[ip++]; - if (stateCheckVal(s, mem)) {opFail(); return;} - int addr = code[ip++]; - pushAltWithStateCheck(ip + addr, s, sprev, mem); - } - - // CEC - private void opStateCheckPushOrJump() { - int mem = code[ip++]; - int addr= code[ip++]; - - if (stateCheckVal(s, mem)) { - ip += addr; - } else { - pushAltWithStateCheck(ip + addr, s, sprev, mem); - } - } - - // CEC - private void opStateCheck() { - int mem = code[ip++]; - if (stateCheckVal(s, mem)) {opFail(); return;} - pushStateCheck(s, mem); - } - private void opPop() { popOne(); } @@ -1425,17 +1180,6 @@ opFail(); } - private void opCall() { - int addr = code[ip++]; - pushCallFrame(ip); - ip = addr; // absolute address - } - - private void opReturn() { - ip = sreturn(); - pushReturn(); - } - private void opFail() { if (stack == null) { ip = regex.codeLength - 1; @@ -1447,13 +1191,6 @@ ip = e.getStatePCode(); s = e.getStatePStr(); sprev = e.getStatePStrPrev(); - - if (Config.USE_COMBINATION_EXPLOSION_CHECK) { - if (e.getStateCheck() != 0) { - e.type = STATE_CHECK_MARK; - stk++; - } - } } private int finish() { diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodePrinter.java Wed Jul 05 18:57:52 2017 +0200 @@ -34,6 +34,239 @@ int operantCount; WarnCallback warnings; + private final static String OpCodeNames[] = new String[] { + "finish", /*OP_FINISH*/ + "end", /*OP_END*/ + "exact1", /*OP_EXACT1*/ + "exact2", /*OP_EXACT2*/ + "exact3", /*OP_EXACT3*/ + "exact4", /*OP_EXACT4*/ + "exact5", /*OP_EXACT5*/ + "exactn", /*OP_EXACTN*/ + "exactmb2-n1", /*OP_EXACTMB2N1*/ + "exactmb2-n2", /*OP_EXACTMB2N2*/ + "exactmb2-n3", /*OP_EXACTMB2N3*/ + "exactmb2-n", /*OP_EXACTMB2N*/ + "exactmb3n", /*OP_EXACTMB3N*/ + "exactmbn", /*OP_EXACTMBN*/ + "exact1-ic", /*OP_EXACT1_IC*/ + "exactn-ic", /*OP_EXACTN_IC*/ + "cclass", /*OP_CCLASS*/ + "cclass-mb", /*OP_CCLASS_MB*/ + "cclass-mix", /*OP_CCLASS_MIX*/ + "cclass-not", /*OP_CCLASS_NOT*/ + "cclass-mb-not", /*OP_CCLASS_MB_NOT*/ + "cclass-mix-not", /*OP_CCLASS_MIX_NOT*/ + "cclass-node", /*OP_CCLASS_NODE*/ + "anychar", /*OP_ANYCHAR*/ + "anychar-ml", /*OP_ANYCHAR_ML*/ + "anychar*", /*OP_ANYCHAR_STAR*/ + "anychar-ml*", /*OP_ANYCHAR_ML_STAR*/ + "anychar*-peek-next", /*OP_ANYCHAR_STAR_PEEK_NEXT*/ + "anychar-ml*-peek-next", /*OP_ANYCHAR_ML_STAR_PEEK_NEXT*/ + "word", /*OP_WORD*/ + "not-word", /*OP_NOT_WORD*/ + "word-bound", /*OP_WORD_BOUND*/ + "not-word-bound", /*OP_NOT_WORD_BOUND*/ + "word-begin", /*OP_WORD_BEGIN*/ + "word-end", /*OP_WORD_END*/ + "begin-buf", /*OP_BEGIN_BUF*/ + "end-buf", /*OP_END_BUF*/ + "begin-line", /*OP_BEGIN_LINE*/ + "end-line", /*OP_END_LINE*/ + "semi-end-buf", /*OP_SEMI_END_BUF*/ + "begin-position", /*OP_BEGIN_POSITION*/ + "backref1", /*OP_BACKREF1*/ + "backref2", /*OP_BACKREF2*/ + "backrefn", /*OP_BACKREFN*/ + "backrefn-ic", /*OP_BACKREFN_IC*/ + "backref_multi", /*OP_BACKREF_MULTI*/ + "backref_multi-ic", /*OP_BACKREF_MULTI_IC*/ + "backref_at_level", /*OP_BACKREF_AT_LEVEL*/ + "mem-start", /*OP_MEMORY_START*/ + "mem-start-push", /*OP_MEMORY_START_PUSH*/ + "mem-end-push", /*OP_MEMORY_END_PUSH*/ + "mem-end-push-rec", /*OP_MEMORY_END_PUSH_REC*/ + "mem-end", /*OP_MEMORY_END*/ + "mem-end-rec", /*OP_MEMORY_END_REC*/ + "fail", /*OP_FAIL*/ + "jump", /*OP_JUMP*/ + "push", /*OP_PUSH*/ + "pop", /*OP_POP*/ + "push-or-jump-e1", /*OP_PUSH_OR_JUMP_EXACT1*/ + "push-if-peek-next", /*OP_PUSH_IF_PEEK_NEXT*/ + "repeat", /*OP_REPEAT*/ + "repeat-ng", /*OP_REPEAT_NG*/ + "repeat-inc", /*OP_REPEAT_INC*/ + "repeat-inc-ng", /*OP_REPEAT_INC_NG*/ + "repeat-inc-sg", /*OP_REPEAT_INC_SG*/ + "repeat-inc-ng-sg", /*OP_REPEAT_INC_NG_SG*/ + "null-check-start", /*OP_NULL_CHECK_START*/ + "null-check-end", /*OP_NULL_CHECK_END*/ + "null-check-end-memst", /*OP_NULL_CHECK_END_MEMST*/ + "null-check-end-memst-push", /*OP_NULL_CHECK_END_MEMST_PUSH*/ + "push-pos", /*OP_PUSH_POS*/ + "pop-pos", /*OP_POP_POS*/ + "push-pos-not", /*OP_PUSH_POS_NOT*/ + "fail-pos", /*OP_FAIL_POS*/ + "push-stop-bt", /*OP_PUSH_STOP_BT*/ + "pop-stop-bt", /*OP_POP_STOP_BT*/ + "look-behind", /*OP_LOOK_BEHIND*/ + "push-look-behind-not", /*OP_PUSH_LOOK_BEHIND_NOT*/ + "fail-look-behind-not", /*OP_FAIL_LOOK_BEHIND_NOT*/ + "call", /*OP_CALL*/ + "return", /*OP_RETURN*/ + "state-check-push", /*OP_STATE_CHECK_PUSH*/ + "state-check-push-or-jump", /*OP_STATE_CHECK_PUSH_OR_JUMP*/ + "state-check", /*OP_STATE_CHECK*/ + "state-check-anychar*", /*OP_STATE_CHECK_ANYCHAR_STAR*/ + "state-check-anychar-ml*", /*OP_STATE_CHECK_ANYCHAR_ML_STAR*/ + "set-option-push", /*OP_SET_OPTION_PUSH*/ + "set-option", /*OP_SET_OPTION*/ + + // single byte versions + "anychar-sb", /*OP_ANYCHAR*/ + "anychar-ml-sb", /*OP_ANYCHAR_ML*/ + "anychar*-sb", /*OP_ANYCHAR_STAR*/ + "anychar-ml*-sb", /*OP_ANYCHAR_ML_STAR*/ + "anychar*-peek-next-sb", /*OP_ANYCHAR_STAR_PEEK_NEXT*/ + "anychar-ml*-peek-next-sb", /*OP_ANYCHAR_ML_STAR_PEEK_NEXT*/ + "state-check-anychar*-sb", /*OP_STATE_CHECK_ANYCHAR_STAR*/ + "state-check-anychar-ml*-sb", /*OP_STATE_CHECK_ANYCHAR_ML_STAR*/ + + "cclass-sb", /*OP_CCLASS*/ + "cclass-not-sb", /*OP_CCLASS_NOT*/ + + "word-sb", /*OP_WORD*/ + "not-word-sb", /*OP_NOT_WORD*/ + "word-bound-sb", /*OP_WORD_BOUND*/ + "not-word-bound-sb", /*OP_NOT_WORD_BOUND*/ + "word-begin-sb", /*OP_WORD_BEGIN*/ + "word-end-sb", /*OP_WORD_END*/ + + "look-behind-sb", /*OP_LOOK_BEHIND*/ + + "exact1-ic-sb", /*OP_EXACT1_IC*/ + "exactn-ic-sb", /*OP_EXACTN_IC*/ + + }; + + private final static int OpCodeArgTypes[] = new int[] { + Arguments.NON, /*OP_FINISH*/ + Arguments.NON, /*OP_END*/ + Arguments.SPECIAL, /*OP_EXACT1*/ + Arguments.SPECIAL, /*OP_EXACT2*/ + Arguments.SPECIAL, /*OP_EXACT3*/ + Arguments.SPECIAL, /*OP_EXACT4*/ + Arguments.SPECIAL, /*OP_EXACT5*/ + Arguments.SPECIAL, /*OP_EXACTN*/ + Arguments.SPECIAL, /*OP_EXACTMB2N1*/ + Arguments.SPECIAL, /*OP_EXACTMB2N2*/ + Arguments.SPECIAL, /*OP_EXACTMB2N3*/ + Arguments.SPECIAL, /*OP_EXACTMB2N*/ + Arguments.SPECIAL, /*OP_EXACTMB3N*/ + Arguments.SPECIAL, /*OP_EXACTMBN*/ + Arguments.SPECIAL, /*OP_EXACT1_IC*/ + Arguments.SPECIAL, /*OP_EXACTN_IC*/ + Arguments.SPECIAL, /*OP_CCLASS*/ + Arguments.SPECIAL, /*OP_CCLASS_MB*/ + Arguments.SPECIAL, /*OP_CCLASS_MIX*/ + Arguments.SPECIAL, /*OP_CCLASS_NOT*/ + Arguments.SPECIAL, /*OP_CCLASS_MB_NOT*/ + Arguments.SPECIAL, /*OP_CCLASS_MIX_NOT*/ + Arguments.SPECIAL, /*OP_CCLASS_NODE*/ + Arguments.NON, /*OP_ANYCHAR*/ + Arguments.NON, /*OP_ANYCHAR_ML*/ + Arguments.NON, /*OP_ANYCHAR_STAR*/ + Arguments.NON, /*OP_ANYCHAR_ML_STAR*/ + Arguments.SPECIAL, /*OP_ANYCHAR_STAR_PEEK_NEXT*/ + Arguments.SPECIAL, /*OP_ANYCHAR_ML_STAR_PEEK_NEXT*/ + Arguments.NON, /*OP_WORD*/ + Arguments.NON, /*OP_NOT_WORD*/ + Arguments.NON, /*OP_WORD_BOUND*/ + Arguments.NON, /*OP_NOT_WORD_BOUND*/ + Arguments.NON, /*OP_WORD_BEGIN*/ + Arguments.NON, /*OP_WORD_END*/ + Arguments.NON, /*OP_BEGIN_BUF*/ + Arguments.NON, /*OP_END_BUF*/ + Arguments.NON, /*OP_BEGIN_LINE*/ + Arguments.NON, /*OP_END_LINE*/ + Arguments.NON, /*OP_SEMI_END_BUF*/ + Arguments.NON, /*OP_BEGIN_POSITION*/ + Arguments.NON, /*OP_BACKREF1*/ + Arguments.NON, /*OP_BACKREF2*/ + Arguments.MEMNUM, /*OP_BACKREFN*/ + Arguments.SPECIAL, /*OP_BACKREFN_IC*/ + Arguments.SPECIAL, /*OP_BACKREF_MULTI*/ + Arguments.SPECIAL, /*OP_BACKREF_MULTI_IC*/ + Arguments.SPECIAL, /*OP_BACKREF_AT_LEVEL*/ + Arguments.MEMNUM, /*OP_MEMORY_START*/ + Arguments.MEMNUM, /*OP_MEMORY_START_PUSH*/ + Arguments.MEMNUM, /*OP_MEMORY_END_PUSH*/ + Arguments.MEMNUM, /*OP_MEMORY_END_PUSH_REC*/ + Arguments.MEMNUM, /*OP_MEMORY_END*/ + Arguments.MEMNUM, /*OP_MEMORY_END_REC*/ + Arguments.NON, /*OP_FAIL*/ + Arguments.RELADDR, /*OP_JUMP*/ + Arguments.RELADDR, /*OP_PUSH*/ + Arguments.NON, /*OP_POP*/ + Arguments.SPECIAL, /*OP_PUSH_OR_JUMP_EXACT1*/ + Arguments.SPECIAL, /*OP_PUSH_IF_PEEK_NEXT*/ + Arguments.SPECIAL, /*OP_REPEAT*/ + Arguments.SPECIAL, /*OP_REPEAT_NG*/ + Arguments.MEMNUM, /*OP_REPEAT_INC*/ + Arguments.MEMNUM, /*OP_REPEAT_INC_NG*/ + Arguments.MEMNUM, /*OP_REPEAT_INC_SG*/ + Arguments.MEMNUM, /*OP_REPEAT_INC_NG_SG*/ + Arguments.MEMNUM, /*OP_NULL_CHECK_START*/ + Arguments.MEMNUM, /*OP_NULL_CHECK_END*/ + Arguments.MEMNUM, /*OP_NULL_CHECK_END_MEMST*/ + Arguments.MEMNUM, /*OP_NULL_CHECK_END_MEMST_PUSH*/ + Arguments.NON, /*OP_PUSH_POS*/ + Arguments.NON, /*OP_POP_POS*/ + Arguments.RELADDR, /*OP_PUSH_POS_NOT*/ + Arguments.NON, /*OP_FAIL_POS*/ + Arguments.NON, /*OP_PUSH_STOP_BT*/ + Arguments.NON, /*OP_POP_STOP_BT*/ + Arguments.SPECIAL, /*OP_LOOK_BEHIND*/ + Arguments.SPECIAL, /*OP_PUSH_LOOK_BEHIND_NOT*/ + Arguments.NON, /*OP_FAIL_LOOK_BEHIND_NOT*/ + Arguments.ABSADDR, /*OP_CALL*/ + Arguments.NON, /*OP_RETURN*/ + Arguments.SPECIAL, /*OP_STATE_CHECK_PUSH*/ + Arguments.SPECIAL, /*OP_STATE_CHECK_PUSH_OR_JUMP*/ + Arguments.STATE_CHECK, /*OP_STATE_CHECK*/ + Arguments.STATE_CHECK, /*OP_STATE_CHECK_ANYCHAR_STAR*/ + Arguments.STATE_CHECK, /*OP_STATE_CHECK_ANYCHAR_ML_STAR*/ + Arguments.OPTION, /*OP_SET_OPTION_PUSH*/ + Arguments.OPTION, /*OP_SET_OPTION*/ + + // single byte versions + Arguments.NON, /*OP_ANYCHAR*/ + Arguments.NON, /*OP_ANYCHAR_ML*/ + Arguments.NON, /*OP_ANYCHAR_STAR*/ + Arguments.NON, /*OP_ANYCHAR_ML_STAR*/ + Arguments.SPECIAL, /*OP_ANYCHAR_STAR_PEEK_NEXT*/ + Arguments.SPECIAL, /*OP_ANYCHAR_ML_STAR_PEEK_NEXT*/ + Arguments.STATE_CHECK, /*OP_STATE_CHECK_ANYCHAR_STAR*/ + Arguments.STATE_CHECK, /*OP_STATE_CHECK_ANYCHAR_ML_STAR*/ + + Arguments.SPECIAL, /*OP_CCLASS*/ + Arguments.SPECIAL, /*OP_CCLASS_NOT*/ + + Arguments.NON, /*OP_WORD*/ + Arguments.NON, /*OP_NOT_WORD*/ + Arguments.NON, /*OP_WORD_BOUND*/ + Arguments.NON, /*OP_NOT_WORD_BOUND*/ + Arguments.NON, /*OP_WORD_BEGIN*/ + Arguments.NON, /*OP_WORD_END*/ + + Arguments.SPECIAL, /*OP_LOOK_BEHIND*/ + + Arguments.SPECIAL, /*OP_EXACT1_IC*/ + Arguments.SPECIAL, /*OP_EXACTN_IC*/ + }; + public ByteCodePrinter(Regex regex) { code = regex.code; codeLength = regex.codeLength; @@ -76,8 +309,8 @@ CClassNode cc; int tm, idx; - sb.append("[" + OPCode.OpCodeNames[code[bp]]); - int argType = OPCode.OpCodeArgTypes[code[bp]]; + sb.append("[" + OpCodeNames[code[bp]]); + int argType = OpCodeArgTypes[code[bp]]; int ip = bp; if (argType != Arguments.SPECIAL) { bp++; diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/CaptureTreeNode.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/CaptureTreeNode.java Thu May 30 10:58:13 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package jdk.nashorn.internal.runtime.regexp.joni; - -public class CaptureTreeNode { - - - int group; - int beg; - int end; - // int allocated; - int numChildren; - CaptureTreeNode[]children; - - CaptureTreeNode() { - beg = Region.REGION_NOTPOS; - end = Region.REGION_NOTPOS; - group = -1; - } - - static final int HISTORY_TREE_INIT_ALLOC_SIZE = 8; - void addChild(CaptureTreeNode child) { - if (children == null) { - children = new CaptureTreeNode[HISTORY_TREE_INIT_ALLOC_SIZE]; - } else if (numChildren >= children.length) { - CaptureTreeNode[]tmp = new CaptureTreeNode[children.length << 1]; - System.arraycopy(children, 0, tmp, 0, children.length); - children = tmp; - } - - children[numChildren] = child; - numChildren++; - } - - void clear() { - for (int i=0; i, \k */ - final boolean USE_MONOMANIAC_CHECK_CAPTURES_IN_ENDLESS_REPEAT = true; /* /(?:()|())*\2/ */ final boolean USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE = true; /* /\n$/ =~ "\n" */ final boolean USE_WARNING_REDUNDANT_NESTED_REPEAT_OPERATOR = false; @@ -42,12 +38,10 @@ final boolean CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS = true; final boolean USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE = false; - final boolean USE_CAPTURE_HISTORY = false; final boolean USE_VARIABLE_META_CHARS = true; final boolean USE_WORD_BEGIN_END = true; /* "\<": word-begin, "\>": word-end */ - final boolean USE_POSIX_API_REGION_OPTION = true; /* needed for POSIX API support */ + final boolean USE_POSIX_API_REGION_OPTION = false; /* needed for POSIX API support */ final boolean USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE = true; - final boolean USE_COMBINATION_EXPLOSION_CHECK = false; final int NREGION = 10; final int MAX_BACKREF_NUM = 1000; @@ -73,13 +67,6 @@ final boolean USE_STRING_TEMPLATES = true; // use embeded string templates in Regex object as byte arrays instead of compiling them into int bytecode array - - final int MAX_CAPTURE_HISTORY_GROUP = 31; - - - final int CHECK_STRING_THRESHOLD_LEN = 7; - final int CHECK_BUFF_MAX_SIZE = 0x4000; - final boolean NON_UNICODE_SDW = true; @@ -95,6 +82,4 @@ final boolean DEBUG_COMPILE_BYTE_CODE_INFO = DEBUG_ALL; final boolean DEBUG_SEARCH = DEBUG_ALL; final boolean DEBUG_MATCH = DEBUG_ALL; - final boolean DEBUG_ASM = true; - final boolean DEBUG_ASM_EXEC = true; } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java Wed Jul 05 18:57:52 2017 +0200 @@ -95,20 +95,6 @@ return s; } - /* onigenc_with_ascii_strncmp */ - public static int strNCmp(char[] chars1, int p1, int end, char[] chars2, int p2, int n) { - while (n-- > 0) { - if (p1 >= end) return chars2[p2]; - int c = chars1[p1]; - int x = chars2[p2] - c; - if (x != 0) return x; - - p2++; - p1++; - } - return 0; - } - public static int mbcToCode(byte[] bytes, int p, int end) { int code = 0; for (int i = p; i < end; i++) { diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Lexer.java Wed Jul 05 18:57:52 2017 +0200 @@ -27,10 +27,7 @@ import jdk.nashorn.internal.runtime.regexp.joni.constants.MetaChar; import jdk.nashorn.internal.runtime.regexp.joni.constants.TokenType; import jdk.nashorn.internal.runtime.regexp.joni.encoding.CharacterType; -import jdk.nashorn.internal.runtime.regexp.joni.encoding.PosixBracket; -import jdk.nashorn.internal.runtime.regexp.joni.encoding.Ptr; import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages; -import jdk.nashorn.internal.runtime.regexp.joni.exception.JOniException; class Lexer extends ScannerSupport { protected final ScanEnvironment env; @@ -215,198 +212,6 @@ \k<-num+n>, \k<-num-n> */ - // value implicit (rnameEnd) - private boolean fetchNameWithLevel(int startCode, Ptr rbackNum, Ptr rlevel) { - int src = p; - boolean existLevel = false; - int isNum = 0; - int sign = 1; - - int endCode = nameEndCodePoint(startCode); - int pnumHead = p; - int nameEnd = stop; - - String err = null; - if (!left()) { - newValueException(ERR_EMPTY_GROUP_NAME); - } else { - fetch(); - if (c == endCode) newValueException(ERR_EMPTY_GROUP_NAME); - if (Character.isDigit(c)) { - isNum = 1; - } else if (c == '-') { - isNum = 2; - sign = -1; - pnumHead = p; - } else if (!EncodingHelper.isWord(c)) { - err = ERR_INVALID_GROUP_NAME; - } - } - - while (left()) { - nameEnd = p; - fetch(); - if (c == endCode || c == ')' || c == '+' || c == '-') { - if (isNum == 2) err = ERR_INVALID_GROUP_NAME; - break; - } - - if (isNum != 0) { - if (EncodingHelper.isDigit(c)) { - isNum = 1; - } else { - err = ERR_INVALID_GROUP_NAME; - // isNum = 0; - } - } else if (!EncodingHelper.isWord(c)) { - err = ERR_INVALID_CHAR_IN_GROUP_NAME; - } - } - - boolean isEndCode = false; - if (err == null && c != endCode) { - if (c == '+' || c == '-') { - int flag = c == '-' ? -1 : 1; - - fetch(); - if (!EncodingHelper.isDigit(c)) newValueException(ERR_INVALID_GROUP_NAME, src, stop); - unfetch(); - int level = scanUnsignedNumber(); - if (level < 0) newValueException(ERR_TOO_BIG_NUMBER); - rlevel.p = level * flag; - existLevel = true; - - fetch(); - isEndCode = c == endCode; - } - - if (!isEndCode) { - err = ERR_INVALID_GROUP_NAME; - nameEnd = stop; - } - } - - if (err == null) { - if (isNum != 0) { - mark(); - p = pnumHead; - int backNum = scanUnsignedNumber(); - restore(); - if (backNum < 0) { - newValueException(ERR_TOO_BIG_NUMBER); - } else if (backNum == 0) { - newValueException(ERR_INVALID_GROUP_NAME, src, stop); - } - rbackNum.p = backNum * sign; - } - value = nameEnd; - return existLevel; - } else { - newValueException(ERR_INVALID_GROUP_NAME, src, nameEnd); - return false; // not reached - } - } - - // USE_NAMED_GROUP - // ref: 0 -> define name (don't allow number name) - // 1 -> reference name (allow number name) - private int fetchNameForNamedGroup(int startCode, boolean ref) { - int src = p; - value = 0; - - int isNum = 0; - int sign = 1; - - int endCode = nameEndCodePoint(startCode); - int pnumHead = p; - int nameEnd = stop; - - String err = null; - if (!left()) { - newValueException(ERR_EMPTY_GROUP_NAME); - } else { - fetch(); - if (c == endCode) newValueException(ERR_EMPTY_GROUP_NAME); - if (EncodingHelper.isDigit(c)) { - if (ref) { - isNum = 1; - } else { - err = ERR_INVALID_GROUP_NAME; - // isNum = 0; - } - } else if (c == '-') { - if (ref) { - isNum = 2; - sign = -1; - pnumHead = p; - } else { - err = ERR_INVALID_GROUP_NAME; - // isNum = 0; - } - } else if (!EncodingHelper.isWord(c)) { - err = ERR_INVALID_CHAR_IN_GROUP_NAME; - } - } - - if (err == null) { - while (left()) { - nameEnd = p; - fetch(); - if (c == endCode || c == ')') { - if (isNum == 2) err = ERR_INVALID_GROUP_NAME; - break; - } - - if (isNum != 0) { - if (EncodingHelper.isDigit(c)) { - isNum = 1; - } else { - if (!EncodingHelper.isWord(c)) { - err = ERR_INVALID_CHAR_IN_GROUP_NAME; - } else { - err = ERR_INVALID_GROUP_NAME; - } - // isNum = 0; - } - } else { - if (!EncodingHelper.isWord(c)) { - err = ERR_INVALID_CHAR_IN_GROUP_NAME; - } - } - } - - if (c != endCode) { - err = ERR_INVALID_GROUP_NAME; - nameEnd = stop; - } - - int backNum = 0; - if (isNum != 0) { - mark(); - p = pnumHead; - backNum = scanUnsignedNumber(); - restore(); - if (backNum < 0) { - newValueException(ERR_TOO_BIG_NUMBER); - } else if (backNum == 0) { - newValueException(ERR_INVALID_GROUP_NAME, src, nameEnd); - } - backNum *= sign; - } - value = nameEnd; - return backNum; - } else { - while (left()) { - nameEnd = p; - fetch(); - if (c == endCode || c == ')') break; - } - if (!left()) nameEnd = stop; - newValueException(err, src, nameEnd); - return 0; // not reached - } - } - // #else USE_NAMED_GROUP // make it return nameEnd! private final int fetchNameForNoNamedGroup(int startCode, boolean ref) { @@ -472,11 +277,7 @@ } protected final int fetchName(int startCode, boolean ref) { - if (Config.USE_NAMED_GROUP) { - return fetchNameForNamedGroup(startCode, ref); - } else { - return fetchNameForNoNamedGroup(startCode, ref); - } + return fetchNameForNoNamedGroup(startCode, ref); } private boolean strExistCheckWithEsc(int[]s, int n, int bad) { @@ -519,26 +320,6 @@ token.setPropNot(flag); } - private void fetchTokenInCCFor_p() { - int c2 = peek(); // !!! migrate to peekIs - if (c2 == '{' && syntax.op2EscPBraceCharProperty()) { - inc(); - token.type = TokenType.CHAR_PROPERTY; - token.setPropNot(c == 'P'); - - if (syntax.op2EscPBraceCircumflexNot()) { - c2 = fetchTo(); - if (c2 == '^') { - token.setPropNot(!token.getPropNot()); - } else { - unfetch(); - } - } - } else { - syntaxWarn(Warnings.INVALID_UNICODE_PROPERTY, (char)c); - } - } - private void fetchTokenInCCFor_x() { if (!left()) return; int last = p; @@ -604,30 +385,6 @@ } } - private void fetchTokenInCCFor_posixBracket() { - if (syntax.opPosixBracket() && peekIs(':')) { - token.backP = p; /* point at '[' is readed */ - inc(); - if (strExistCheckWithEsc(send, send.length, ']')) { - token.type = TokenType.POSIX_BRACKET_OPEN; - } else { - unfetch(); - // remove duplication, goto cc_in_cc; - if (syntax.op2CClassSetOp()) { - token.type = TokenType.CC_CC_OPEN; - } else { - env.ccEscWarn("["); - } - } - } else { // cc_in_cc: - if (syntax.op2CClassSetOp()) { - token.type = TokenType.CC_CC_OPEN; - } else { - env.ccEscWarn("["); - } - } - } - private void fetchTokenInCCFor_and() { if (syntax.op2CClassSetOp() && left() && peekIs('&')) { inc(); @@ -683,10 +440,6 @@ case 'H': if (syntax.op2EscHXDigit()) fetchTokenInCCFor_charType(true, CharacterType.XDIGIT); break; - case 'p': - case 'P': - fetchTokenInCCFor_p(); - break; case 'x': fetchTokenInCCFor_x(); break; @@ -714,18 +467,12 @@ break; } // switch - } else if (c == '[') { - fetchTokenInCCFor_posixBracket(); } else if (c == '&') { fetchTokenInCCFor_and(); } return token.type; } - protected final int backrefRelToAbs(int relNo) { - return env.numMem + 1 + relNo; - } - private void fetchTokenFor_repeat(int lower, int upper) { token.type = TokenType.OP_REPEAT; token.setRepeatLower(lower); @@ -815,7 +562,6 @@ token.setBackrefNum(1); token.setBackrefRef1(num); token.setBackrefByName(false); - if (Config.USE_BACKREF_WITH_LEVEL) token.setBackrefExistLevel(false); return; } @@ -845,76 +591,6 @@ } } - private void fetchTokenFor_namedBackref() { - if (syntax.op2EscKNamedBackref()) { - if (left()) { - fetch(); - if (c =='<' || c == '\'') { - int last = p; - int backNum; - if (Config.USE_BACKREF_WITH_LEVEL) { - Ptr rbackNum = new Ptr(); - Ptr rlevel = new Ptr(); - token.setBackrefExistLevel(fetchNameWithLevel(c, rbackNum, rlevel)); - token.setBackrefLevel(rlevel.p); - backNum = rbackNum.p; - } else { - backNum = fetchName(c, true); - } // USE_BACKREF_AT_LEVEL - int nameEnd = value; // set by fetchNameWithLevel/fetchName - - if (backNum != 0) { - if (backNum < 0) { - backNum = backrefRelToAbs(backNum); - if (backNum <= 0) newValueException(ERR_INVALID_BACKREF); - } - - if (syntax.strictCheckBackref() && (backNum > env.numMem || env.memNodes == null)) { - newValueException(ERR_INVALID_BACKREF); - } - token.type = TokenType.BACKREF; - token.setBackrefByName(false); - token.setBackrefNum(1); - token.setBackrefRef1(backNum); - } else { - NameEntry e = env.reg.nameToGroupNumbers(chars, last, nameEnd); - if (e == null) newValueException(ERR_UNDEFINED_NAME_REFERENCE, last, nameEnd); - - if (syntax.strictCheckBackref()) { - if (e.backNum == 1) { - if (e.backRef1 > env.numMem || - env.memNodes == null || - env.memNodes[e.backRef1] == null) newValueException(ERR_INVALID_BACKREF); - } else { - for (int i=0; i env.numMem || - env.memNodes == null || - env.memNodes[e.backRefs[i]] == null) newValueException(ERR_INVALID_BACKREF); - } - } - } - - token.type = TokenType.BACKREF; - token.setBackrefByName(true); - - if (e.backNum == 1) { - token.setBackrefNum(1); - token.setBackrefRef1(e.backRef1); - } else { - token.setBackrefNum(e.backNum); - token.setBackrefRefs(e.backRefs); - } - } - } else { - unfetch(); - syntaxWarn(Warnings.INVALID_BACKREFERENCE); - } - } else { - syntaxWarn(Warnings.INVALID_BACKREFERENCE); - } - } - } - private void fetchTokenFor_subexpCall() { if (syntax.op2EscGSubexpCall()) { if (left()) { @@ -937,25 +613,6 @@ } } - private void fetchTokenFor_charProperty() { - if (peekIs('{') && syntax.op2EscPBraceCharProperty()) { - inc(); - token.type = TokenType.CHAR_PROPERTY; - token.setPropNot(c == 'P'); - - if (syntax.op2EscPBraceCircumflexNot()) { - fetch(); - if (c == '^') { - token.setPropNot(!token.getPropNot()); - } else { - unfetch(); - } - } - } else { - syntaxWarn(Warnings.INVALID_UNICODE_PROPERTY, (char)c); - } - } - private void fetchTokenFor_metaChars() { if (c == syntax.metaCharTable.anyChar) { token.type = TokenType.ANYCHAR; @@ -1091,19 +748,6 @@ case '0': fetchTokenFor_zero(); break; - case 'k': - if (Config.USE_NAMED_GROUP) fetchTokenFor_namedBackref(); - break; - case 'g': - if (Config.USE_SUBEXP_CALL) fetchTokenFor_subexpCall(); - break; - case 'Q': - if (syntax.op2EscCapitalQQuote()) token.type = TokenType.QUOTE_OPEN; - break; - case 'p': - case 'P': - fetchTokenFor_charProperty(); - break; default: unfetch(); @@ -1244,24 +888,6 @@ } } - protected final int fetchCharPropertyToCType() { - mark(); - - while (left()) { - int last = p; - fetch(); - if (c == '}') { - String name = new String(chars, _p, last - _p); - return PosixBracket.propertyNameToCType(name); - } else if (c == '(' || c == ')' || c == '{' || c == '|') { - String name = new String(chars, _p, last - _p); - throw new JOniException(ERR_INVALID_CHAR_PROPERTY_NAME.replaceAll("%n", name)); - } - } - newInternalException(ERR_PARSER_BUG); - return 0; // not reached - } - protected final void syntaxWarn(String message, char c) { syntaxWarn(message.replace("<%n>", Character.toString(c))); } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Matcher.java Wed Jul 05 18:57:52 2017 +0200 @@ -58,17 +58,10 @@ // main matching method protected abstract int matchAt(int range, int sstart, int sprev); - protected abstract void stateCheckBuffInit(int strLength, int offset, int stateNum); - protected abstract void stateCheckBuffClear(); - public final Region getRegion() { return msaRegion; } - public final Region getEagerRegion() { - return msaRegion != null ? msaRegion : new Region(msaBegin, msaEnd); - } - public final int getBegin() { return msaBegin; } @@ -86,11 +79,6 @@ public final int match(int at, int range, int option) { msaInit(option, at); - if (Config.USE_COMBINATION_EXPLOSION_CHECK) { - int offset = at = str; - stateCheckBuffInit(end - str, offset, regex.numCombExpCheck); // move it to construction? - } // USE_COMBINATION_EXPLOSION_CHECK - int prev = EncodingHelper.prevCharHead(str, at); if (Config.USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE) { @@ -377,8 +365,6 @@ prev = -1; msaInit(option, start); - if (Config.USE_COMBINATION_EXPLOSION_CHECK) stateCheckBuffClear(); - if (matchCheck(end, s, prev)) return match(s); return mismatch(); } @@ -393,10 +379,6 @@ } msaInit(option, origStart); - if (Config.USE_COMBINATION_EXPLOSION_CHECK) { - int offset = Math.min(start, range) - str; - stateCheckBuffInit(end - str, offset, regex.numCombExpCheck); - } s = start; if (range > start) { /* forward search */ diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/NameEntry.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/NameEntry.java Thu May 30 10:58:13 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package jdk.nashorn.internal.runtime.regexp.joni; - -public final class NameEntry { - static final int INIT_NAME_BACKREFS_ALLOC_NUM = 8; - - public final char[] name; - public final int nameP; - public final int nameEnd; - - int backNum; - int backRef1; - int backRefs[]; - - public NameEntry(char[] chars, int p, int end) { - name = chars; - nameP = p; - nameEnd = end; - } - - public int[] getBackRefs() { - switch (backNum) { - case 0: - return new int[]{}; - case 1: - return new int[]{backRef1}; - default: - int[]result = new int[backNum]; - System.arraycopy(backRefs, 0, result, 0, backNum); - return result; - } - } - - private void alloc() { - backRefs = new int[INIT_NAME_BACKREFS_ALLOC_NUM]; - } - - private void ensureSize() { - if (backNum > backRefs.length) { - int[]tmp = new int[backRefs.length << 1]; - System.arraycopy(backRefs, 0, tmp, 0, backRefs.length); - backRefs = tmp; - } - } - - public void addBackref(int backRef) { - backNum++; - - switch (backNum) { - case 1: - backRef1 = backRef; - break; - case 2: - alloc(); - backRefs[0] = backRef1; - backRefs[1] = backRef; - break; - default: - ensureSize(); - backRefs[backNum - 1] = backRef; - } - } - - public String toString() { - StringBuilder buff = new StringBuilder(new String(name, nameP, nameEnd - nameP) + " "); - if (backNum == 0) { - buff.append("-"); - } else if (backNum == 1){ - buff.append(backRef1); - } else { - for (int i=0; i 0) buff.append(", "); - buff.append(backRefs[i]); - } - } - return buff.toString(); - } - -} diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/NativeMachine.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/NativeMachine.java Thu May 30 10:58:13 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package jdk.nashorn.internal.runtime.regexp.joni; - -public abstract class NativeMachine extends Matcher { - - protected NativeMachine(Regex regex, char[] chars, int p, int end) { - super(regex, chars, p, end); - } -} diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java Wed Jul 05 18:57:52 2017 +0200 @@ -19,20 +19,15 @@ */ package jdk.nashorn.internal.runtime.regexp.joni; -import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsOnAtSimple; import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsOnOff; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isDontCaptureGroup; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isIgnoreCase; import jdk.nashorn.internal.runtime.regexp.joni.encoding.CharacterType; -import jdk.nashorn.internal.runtime.regexp.joni.encoding.PosixBracket; -import jdk.nashorn.internal.runtime.regexp.joni.encoding.Ptr; import jdk.nashorn.internal.runtime.regexp.joni.ast.AnchorNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.AnyCharNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.BackRefNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode; -import jdk.nashorn.internal.runtime.regexp.joni.ast.CTypeNode; -import jdk.nashorn.internal.runtime.regexp.joni.ast.CallNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.ConsAltNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.EncloseNode; import jdk.nashorn.internal.runtime.regexp.joni.ast.Node; @@ -66,65 +61,6 @@ return root; } - private static final int POSIX_BRACKET_NAME_MIN_LEN = 4; - private static final int POSIX_BRACKET_CHECK_LIMIT_LENGTH = 20; - private static final char BRACKET_END[] = ":]".toCharArray(); - private boolean parsePosixBracket(CClassNode cc) { - mark(); - - boolean not; - if (peekIs('^')) { - inc(); - not = true; - } else { - not = false; - } - if (stop - p >= POSIX_BRACKET_NAME_MIN_LEN + 3) { // else goto not_posix_bracket - char[][] pbs = PosixBracket.PBSNamesLower; - for (int i=0; i POSIX_BRACKET_CHECK_LIMIT_LENGTH) break; - } - - if (c == ':' && left()) { - inc(); - if (left()) { - fetch(); - if (c == ']') newSyntaxException(ERR_INVALID_POSIX_BRACKET_TYPE); - } - } - restore(); - return true; /* 1: is not POSIX bracket, but no error. */ - } - - private CClassNode parseCharProperty() { - int ctype = fetchCharPropertyToCType(); - CClassNode n = new CClassNode(); - n.addCType(ctype, false, env, this); - if (token.getPropNot()) n.setNot(); - return n; - } - private boolean codeExistCheck(int code, boolean ignoreEscaped) { mark(); @@ -225,29 +161,11 @@ parseCharClassValEntry(cc, arg); // val_entry:, val_entry2 break; - case POSIX_BRACKET_OPEN: - if (parsePosixBracket(cc)) { /* true: is not POSIX bracket */ - env.ccEscWarn("["); - p = token.backP; - arg.v = token.getC(); - arg.vIsRaw = false; - parseCharClassValEntry(cc, arg); // goto val_entry - break; - } - cc.nextStateClass(arg, env); // goto next_class - break; - case CHAR_TYPE: cc.addCType(token.getPropCType(), token.getPropNot(), env, this); cc.nextStateClass(arg, env); // next_class: break; - case CHAR_PROPERTY: - int ctype = fetchCharPropertyToCType(); - cc.addCType(ctype, token.getPropNot(), env, this); - cc.nextStateClass(arg, env); // goto next_class - break; - case CC_RANGE: if (arg.state == CCSTATE.VALUE) { fetchTokenInCC(); @@ -413,15 +331,6 @@ node = new EncloseNode(EncloseType.STOP_BACKTRACK); // node_new_enclose break; case '\'': - if (Config.USE_NAMED_GROUP) { - if (syntax.op2QMarkLtNamedGroup()) { - listCapture = false; // goto named_group1 - node = parseEncloseNamedGroup2(listCapture); - break; - } else { - newSyntaxException(ERR_UNDEFINED_GROUP_OPTION); - } - } // USE_NAMED_GROUP break; case '<': /* look behind (?<=...), (?...) */ - } - unfetch(); - } - } // USE_NAMED_GROUP - EncloseNode en = new EncloseNode(env.option, false); // node_new_enclose_memory + EncloseNode en = new EncloseNode(); // node_new_enclose_memory int num = env.addMemEntry(); if (num >= BitStatus.BIT_STATUS_BITS_NUM) newValueException(ERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY); en.regNum = num; @@ -546,7 +431,7 @@ returnCode = 1; /* group */ return node; } - EncloseNode en = new EncloseNode(env.option, false); // node_new_enclose_memory + EncloseNode en = new EncloseNode(); // node_new_enclose_memory int num = env.addMemEntry(); en.regNum = num; node = en; @@ -570,48 +455,6 @@ return node; // ?? } - private Node parseEncloseNamedGroup2(boolean listCapture) { - int nm = p; - int num = fetchName(c, false); - int nameEnd = value; - num = env.addMemEntry(); - if (listCapture && num >= BitStatus.BIT_STATUS_BITS_NUM) newValueException(ERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY); - - regex.nameAdd(chars, nm, nameEnd, num, syntax); - EncloseNode en = new EncloseNode(env.option, true); // node_new_enclose_memory - en.regNum = num; - - Node node = en; - - if (listCapture) env.captureHistory = bsOnAtSimple(env.captureHistory, num); - env.numNamed++; - return node; - } - - private int findStrPosition(int[]s, int n, int from, int to, Ptr nextChar) { - int x; - int q; - int p = from; - int i = 0; - while (p < to) { - x = chars[p]; - q = p + 1; - if (x == s[0]) { - for (i=1; i= n) { - if (chars[nextChar.p] != 0) nextChar.p = q; // we may need zero term semantics... - return p; - } - } - p = q; - } - return -1; - } - private Node parseExp(TokenType term) { if (token.type == term) return StringNode.EMPTY; // goto end_of_token @@ -656,16 +499,6 @@ node = new StringNode(buf, 0, 1); break; - case QUOTE_OPEN: - int[] endOp = new int[] {syntax.metaCharTable.esc, 'E'}; - int qstart = p; - Ptr nextChar = new Ptr(); - int qend = findStrPosition(endOp, endOp.length, qstart, stop, nextChar); - if (qend == -1) nextChar.p = qend = stop; - node = new StringNode(chars, qstart, qend); - p = nextChar.p; - break; - case CHAR_TYPE: switch(token.getPropCType()) { case CharacterType.D: @@ -679,10 +512,6 @@ } break; - case CharacterType.WORD: - node = new CTypeNode(token.getPropCType(), token.getPropNot()); - break; - case CharacterType.SPACE: case CharacterType.DIGIT: case CharacterType.XDIGIT: @@ -699,10 +528,6 @@ } // inner switch break; - case CHAR_PROPERTY: - node = parseCharProperty(); - break; - case CC_CC_OPEN: CClassNode cc = parseCharClass(); node = cc; @@ -735,20 +560,6 @@ token.getBackrefExistLevel(), // #ifdef USE_BACKREF_AT_LEVEL token.getBackrefLevel(), // ... env); - - break; - - case CALL: - if (Config.USE_SUBEXP_CALL) { - int gNum = token.getCallGNum(); - - if (gNum < 0) { - gNum = backrefRelToAbs(gNum); - if (gNum <= 0) newValueException(ERR_INVALID_BACKREF); - } - node = new CallNode(chars, token.getCallNameP(), token.getCallNameEnd(), gNum); - env.numCall++; - } // USE_SUBEXP_CALL break; case ANCHOR: diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Regex.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Regex.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Regex.java Wed Jul 05 18:57:52 2017 +0200 @@ -23,9 +23,11 @@ import static jdk.nashorn.internal.runtime.regexp.joni.Option.isCaptureGroup; import static jdk.nashorn.internal.runtime.regexp.joni.Option.isDontCaptureGroup; +import java.nio.file.Files; import java.util.HashMap; import java.util.Iterator; +import jdk.nashorn.internal.runtime.regexp.joni.ast.Node; import jdk.nashorn.internal.runtime.regexp.joni.constants.AnchorType; import jdk.nashorn.internal.runtime.regexp.joni.constants.RegexState; import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages; @@ -44,7 +46,6 @@ int numMem; /* used memory(...) num counted from 1 */ int numRepeat; /* OP_REPEAT/OP_REPEAT_NG id-counter */ int numNullCheck; /* OP_NULL_CHECK_START/END id counter */ - int numCombExpCheck; /* combination explosion check */ int numCall; /* number of subexp call */ int captureHistory; /* (?@...) flag (1-31) */ int btMemStart; /* need backtrack flag */ @@ -57,7 +58,7 @@ WarnCallback warnings; MatcherFactory factory; - private Analyser analyser; + protected Analyser analyser; int options; int userOptions; @@ -65,8 +66,6 @@ //final Syntax syntax; final int caseFoldFlag; - HashMap nameTable; // named entries - /* optimization info (string search, char-map and anchors) */ SearchAlgorithm searchAlgorithm; /* optimize flag */ int thresholdLength; /* search str-length for apply optimize */ @@ -172,112 +171,6 @@ return numMem; } - public int numberOfCaptureHistories() { - if (Config.USE_CAPTURE_HISTORY) { - int n = 0; - for (int i=0; i<=Config.MAX_CAPTURE_HISTORY_GROUP; i++) { - if (bsAt(captureHistory, i)) n++; - } - return n; - } else { - return 0; - } - } - - String nameTableToString() { - StringBuilder sb = new StringBuilder(); - - if (nameTable != null) { - sb.append("name table\n"); - for (NameEntry ne : nameTable.values()) { - sb.append(" " + ne + "\n"); - } - sb.append("\n"); - } - return sb.toString(); - } - - NameEntry nameFind(char[] name, int nameP, int nameEnd) { - if (nameTable != null) return nameTable.get(new String(name, nameP, nameEnd - nameP)); - return null; - } - - void renumberNameTable(int[]map) { - if (nameTable != null) { - for (NameEntry e : nameTable.values()) { - if (e.backNum > 1) { - for (int i=0; i(); // 13, oni defaults to 5 - } else { - e = nameFind(name, nameP, nameEnd); - } - - if (e == null) { - // dup the name here as oni does ?, what for ? (it has to manage it, we don't) - e = new NameEntry(name, nameP, nameEnd); - nameTable.put(new String(name, nameP, nameEnd - nameP), e); - } else if (e.backNum >= 1 && !syntax.allowMultiplexDefinitionName()) { - throw new ValueException(ErrorMessages.ERR_MULTIPLEX_DEFINED_NAME, new String(name, nameP, nameEnd - nameP)); - } - - e.addBackref(backRef); - } - - NameEntry nameToGroupNumbers(char[] name, int nameP, int nameEnd) { - return nameFind(name, nameP, nameEnd); - } - - public int nameToBackrefNumber(char[] name, int nameP, int nameEnd, Region region) { - NameEntry e = nameToGroupNumbers(name, nameP, nameEnd); - if (e == null) throw new ValueException(ErrorMessages.ERR_UNDEFINED_NAME_REFERENCE, - new String(name, nameP, nameEnd - nameP)); - - switch(e.backNum) { - case 0: - throw new InternalException(ErrorMessages.ERR_PARSER_BUG); - case 1: - return e.backRef1; - default: - if (region != null) { - for (int i = e.backNum - 1; i >= 0; i--) { - if (region.beg[e.backRefs[i]] != Region.REGION_NOTPOS) return e.backRefs[i]; - } - } - return e.backRefs[e.backNum - 1]; - } - } - - public Iterator namedBackrefIterator() { - return nameTable.values().iterator(); - } - - public boolean noNameGroupIsActive(Syntax syntax) { - if (isDontCaptureGroup(options)) return false; - - if (Config.USE_NAMED_GROUP) { - if (numberOfNames() > 0 && syntax.captureOnlyNamedGroup() && !isCaptureGroup(options)) return false; - } - return true; - } - /* set skip map for Boyer-Moor search */ void setupBMSkipMap() { char[] chars = exact; @@ -353,16 +246,6 @@ exactP = exactEnd = 0; } - public String encStringToString(byte[]bytes, int p, int end) { - StringBuilder sb = new StringBuilder("\nPATTERN: /"); - - while (p < end) { - sb.append(new String(new byte[]{bytes[p]})); - p++; - } - return sb.append("/").toString(); - } - public String optimizeInfoToString() { String s = ""; s += "optimize: " + searchAlgorithm.getName() + "\n"; @@ -410,19 +293,13 @@ return options; } - public void setUserOptions(int options) { - this.userOptions = options; - } - - public int getUserOptions() { - return userOptions; + public String dumpTree() { + return analyser == null ? null : analyser.root.toString(); } - public void setUserObject(Object object) { - this.userObject = object; + public String dumpByteCode() { + compile(); + return new ByteCodePrinter(this).byteCodeListToString(); } - public Object getUserObject() { - return userObject; - } } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Region.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Region.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Region.java Wed Jul 05 18:57:52 2017 +0200 @@ -25,7 +25,6 @@ public final int numRegs; public final int[]beg; public final int[]end; - public CaptureTreeNode historyRoot; public Region(int num) { this.numRegs = num; @@ -33,20 +32,6 @@ this.end = new int[num]; } - public Region(int begin, int end) { - this.numRegs = 1; - this.beg = new int[]{begin}; - this.end = new int[]{end}; - } - - public Region clone() { - Region region = new Region(numRegs); - System.arraycopy(beg, 0, region.beg, 0, beg.length); - System.arraycopy(end, 0, region.end, 0, end.length); - if (historyRoot != null) region.historyRoot = historyRoot.cloneTree(); - return region; - } - public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Region: \n"); @@ -54,10 +39,6 @@ return sb.toString(); } - CaptureTreeNode getCaptureTree() { - return historyRoot; - } - void clear() { for (int i=0; i 0 && strLength >= Config.CHECK_STRING_THRESHOLD_LEN) { - int size = ((strLength + 1) * stateNum + 7) >>> 3; - offset = (offset * stateNum) >>> 3; - - if (size > 0 && offset < size && size < Config.CHECK_BUFF_MAX_SIZE) { - if (size >= STATE_CHECK_BUFF_MALLOC_THRESHOLD_SIZE) { - stateCheckBuff = new byte[size]; - } else { - // same impl, reduce... - stateCheckBuff = new byte[size]; - } - Arrays.fill(stateCheckBuff, offset, (size - offset), (byte)0); - stateCheckBuffSize = size; - } else { - stateCheckBuff = null; // reduce - stateCheckBuffSize = 0; - } - } else { - stateCheckBuff = null; // reduce - stateCheckBuffSize = 0; - } - } - - protected final void stateCheckBuffClear() { - stateCheckBuff = null; - stateCheckBuffSize = 0; - } - private void push(int type, int pat, int s, int prev) { StackEntry e = ensure1(); e.type = type; e.setStatePCode(pat); e.setStatePStr(s); e.setStatePStrPrev(prev); - if (Config.USE_COMBINATION_EXPLOSION_CHECK) e.setStateCheck(0); stk++; } @@ -172,30 +112,9 @@ StackEntry e = stack[stk]; e.type = type; e.setStatePCode(pat); - if (Config.USE_COMBINATION_EXPLOSION_CHECK) e.setStateCheck(0); stk++; } - protected final void pushAltWithStateCheck(int pat, int s, int sprev, int snum) { - StackEntry e = ensure1(); - e.type = ALT; - e.setStatePCode(pat); - e.setStatePStr(s); - e.setStatePStrPrev(sprev); - if (Config.USE_COMBINATION_EXPLOSION_CHECK) e.setStateCheck(stateCheckBuff != null ? snum : 0); - stk++; - } - - protected final void pushStateCheck(int s, int snum) { - if (stateCheckBuff != null) { - StackEntry e = ensure1(); - e.type = STATE_CHECK_MARK; - e.setStatePStr(s); - e.setStateCheck(snum); - stk++; - } - } - protected final void pushAlt(int pat, int s, int prev) { push(ALT, pat, s, prev); } @@ -294,19 +213,6 @@ stk++; } - protected final void pushCallFrame(int pat) { - StackEntry e = ensure1(); - e.type = CALL_FRAME; - e.setCallFrameRetAddr(pat); - stk++; - } - - protected final void pushReturn() { - StackEntry e = ensure1(); - e.type = RETURN; - stk++; - } - // stack debug routines here // ... @@ -331,8 +237,6 @@ if ((e.type & MASK_POP_USED) != 0) { return e; - } else if (Config.USE_COMBINATION_EXPLOSION_CHECK) { - if (e.type == STATE_CHECK_MARK) stateCheckMark(); } } } @@ -346,8 +250,6 @@ } else if (e.type == MEM_START) { repeatStk[memStartStk + e.getMemNum()] = e.getMemStart(); repeatStk[memEndStk + e.getMemNum()] = e.getMemEnd(); - } else if (Config.USE_COMBINATION_EXPLOSION_CHECK) { - if (e.type == STATE_CHECK_MARK) stateCheckMark(); } } } @@ -368,8 +270,6 @@ } else if (e.type == MEM_END) { repeatStk[memStartStk + e.getMemNum()] = e.getMemStart(); repeatStk[memEndStk + e.getMemNum()] = e.getMemEnd(); - } else if (Config.USE_COMBINATION_EXPLOSION_CHECK) { - if (e.type == STATE_CHECK_MARK) stateCheckMark(); } } } @@ -391,8 +291,6 @@ } else if (e.type == MEM_END){ repeatStk[memStartStk + e.getMemNum()] = e.getMemStart(); repeatStk[memEndStk + e.getMemNum()] = e.getMemStart(); - } else if (Config.USE_COMBINATION_EXPLOSION_CHECK) { - if (e.type == STATE_CHECK_MARK) stateCheckMark(); } } } @@ -414,8 +312,6 @@ } else if (e.type == MEM_END) { repeatStk[memStartStk + e.getMemNum()] = e.getMemStart(); repeatStk[memEndStk + e.getMemNum()] = e.getMemEnd(); - } else if (Config.USE_COMBINATION_EXPLOSION_CHECK) { - if (e.type == STATE_CHECK_MARK) stateCheckMark(); } } } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Syntax.java Wed Jul 05 18:57:52 2017 +0200 @@ -609,7 +609,7 @@ OP_ESC_CONTROL_CHARS | OP_ESC_C_CONTROL | OP_ESC_X_HEX2) & ~OP_ESC_LTGT_WORD_BEGIN_END ), - ( OP2_QMARK_GROUP_EFFECT | OP2_CCLASS_SET_OP | + ( OP2_QMARK_GROUP_EFFECT | OP2_ESC_V_VTAB | OP2_ESC_U_HEX4 ), ( GNU_REGEX_BV | DIFFERENT_LEN_ALT_LOOK_BEHIND ), diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/UnsetAddrList.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/UnsetAddrList.java Thu May 30 10:58:13 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package jdk.nashorn.internal.runtime.regexp.joni; - -import jdk.nashorn.internal.runtime.regexp.joni.ast.EncloseNode; -import jdk.nashorn.internal.runtime.regexp.joni.ast.Node; -import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages; -import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException; - -public final class UnsetAddrList { - int num; - Node[]targets; - int[]offsets; - - public UnsetAddrList(int size) { - targets = new Node[size]; - offsets = new int[size]; - } - - public void add(int offset, Node node) { - if (num >= offsets.length) { - Node []ttmp = new Node[targets.length << 1]; - System.arraycopy(targets, 0, ttmp, 0, num); - targets = ttmp; - int[]otmp = new int[offsets.length << 1]; - System.arraycopy(offsets, 0, otmp, 0, num); - offsets = otmp; - } - targets[num] = node; - offsets[num] = offset; - - num++; - } - - public void fix(Regex regex) { - for (int i=0; i 0) { - for (int i=0; i set, WarnCallback warnings) { - if (target == null || target.parent == this) - warnings.warn(this.getAddressName() + " doesn't point to a target or the target has been stolen"); - // do not recurse here - } - - @Override - public String toString(int level) { - StringBuilder value = new StringBuilder(super.toString(level)); - value.append("\n name: " + new String(name, nameP, nameEnd - nameP)); - value.append("\n groupNum: " + groupNum); - value.append("\n target: " + pad(target.getAddressName(), level + 1)); - value.append("\n unsetAddrList: " + pad(unsetAddrList, level + 1)); - - return value.toString(); - } - -} diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/EncloseNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -25,7 +25,7 @@ public final class EncloseNode extends StateNode implements EncloseType { - public int type; // enclose type + public final int type; // enclose type public int regNum; public int option; public Node target; /* EncloseNode : ENCLOSE_MEMORY */ @@ -42,10 +42,8 @@ } // node_new_enclose_memory - public EncloseNode(int option, boolean isNamed) { + public EncloseNode() { this(MEMORY); - if (isNamed) setNamedGroup(); - if (Config.USE_SUBEXP_CALL) this.option = option; } // node_new_option @@ -104,46 +102,14 @@ return types.toString(); } - public void setEncloseStatus(int flag) { - state |= flag; - } - - public void clearEncloseStatus(int flag) { - state &= ~flag; - } - - public void clearMemory() { - type &= ~MEMORY; - } - - public void setMemory() { - type |= MEMORY; - } - public boolean isMemory() { return (type & MEMORY) != 0; } - public void clearOption() { - type &= ~OPTION; - } - - public void setOption() { - type |= OPTION; - } - public boolean isOption() { return (type & OPTION) != 0; } - public void clearStopBacktrack() { - type &= ~STOP_BACKTRACK; - } - - public void setStopBacktrack() { - type |= STOP_BACKTRACK; - } - public boolean isStopBacktrack() { return (type & STOP_BACKTRACK) != 0; } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/QuantifierNode.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/QuantifierNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/QuantifierNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -21,9 +21,10 @@ import jdk.nashorn.internal.runtime.regexp.joni.Config; import jdk.nashorn.internal.runtime.regexp.joni.ScanEnvironment; -import jdk.nashorn.internal.runtime.regexp.joni.constants.Reduce; import jdk.nashorn.internal.runtime.regexp.joni.constants.TargetInfo; +import static jdk.nashorn.internal.runtime.regexp.joni.ast.QuantifierNode.ReduceType.*; + public final class QuantifierNode extends StateNode { public Node target; @@ -37,8 +38,33 @@ public Node nextHeadExact; public boolean isRefered; /* include called node. don't eliminate even if {0} */ - // USE_COMBINATION_EXPLOSION_CHECK - public int combExpCheckNum; /* 1,2,3...: check, 0: no check */ + enum ReduceType { + ASIS, /* as is */ + DEL, /* delete parent */ + A, /* to '*' */ + AQ, /* to '*?' */ + QQ, /* to '??' */ + P_QQ, /* to '+)??' */ + PQ_Q, /* to '+?)?' */ + } + + private final static ReduceType[][] REDUCE_TABLE = { + {DEL, A, A, QQ, AQ, ASIS}, /* '?' */ + {DEL, DEL, DEL, P_QQ, P_QQ, DEL}, /* '*' */ + {A, A, DEL, ASIS, P_QQ, DEL}, /* '+' */ + {DEL, AQ, AQ, DEL, AQ, AQ}, /* '??' */ + {DEL, DEL, DEL, DEL, DEL, DEL}, /* '*?' */ + {ASIS, PQ_Q, DEL, AQ, AQ, DEL} /* '+?' */ + }; + + private final static String PopularQStr[] = new String[] { + "?", "*", "+", "??", "*?", "+?" + }; + + private final static String ReduceQStr[]= new String[] { + "", "", "*", "*?", "??", "+ and ??", "+? and ?" + }; + public QuantifierNode(int lower, int upper, boolean byNumber) { this.lower = lower; @@ -92,7 +118,6 @@ value.append("\n headExact: " + pad(headExact, level + 1)); value.append("\n nextHeadExact: " + pad(nextHeadExact, level + 1)); value.append("\n isRefered: " + isRefered); - value.append("\n combExpCheckNum: " + combExpCheckNum); return value.toString(); } @@ -134,7 +159,6 @@ headExact = other.headExact; nextHeadExact = other.nextHeadExact; isRefered = other.isRefered; - combExpCheckNum = other.combExpCheckNum; } public void reduceNestedQuantifier(QuantifierNode other) { @@ -143,7 +167,7 @@ if (pnum < 0 || cnum < 0) return; - switch(Reduce.REDUCE_TABLE[cnum][pnum]) { + switch(REDUCE_TABLE[cnum][pnum]) { case DEL: // no need to set the parent here... // swap ? @@ -226,7 +250,7 @@ if (Config.USE_WARNING_REDUNDANT_NESTED_REPEAT_OPERATOR) { if (!isByNumber() && !qnt.isByNumber() && env.syntax.warnReduntantNestedRepeat()) { - switch(Reduce.REDUCE_TABLE[targetQNum][nestQNum]) { + switch(REDUCE_TABLE[targetQNum][nestQNum]) { case ASIS: break; @@ -237,9 +261,9 @@ default: env.reg.getWarnings().warn(new String(chars, p, end) + - " nested repeat operator " + Reduce.PopularQStr[targetQNum] + - " and " + Reduce.PopularQStr[nestQNum] + " was replaced with '" + - Reduce.ReduceQStr[Reduce.REDUCE_TABLE[targetQNum][nestQNum].ordinal()] + "'"); + " nested repeat operator " + PopularQStr[targetQNum] + + " and " + PopularQStr[nestQNum] + " was replaced with '" + + ReduceQStr[REDUCE_TABLE[targetQNum][nestQNum].ordinal()] + "'"); } } } // USE_WARNING_REDUNDANT_NESTED_REPEAT_OPERATOR diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/StateNode.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/StateNode.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/ast/StateNode.java Wed Jul 05 18:57:52 2017 +0200 @@ -40,7 +40,6 @@ if (isRecursion()) states.append("RECURSION "); if (isCalled()) states.append("CALLED "); if (isAddrFixed()) states.append("ADDR_FIXED "); - if (isNamedGroup()) states.append("NAMED_GROUP "); if (isNameRef()) states.append("NAME_REF "); if (isInRepeat()) states.append("IN_REPEAT "); if (isNestLevel()) states.append("NEST_LEVEL "); @@ -57,10 +56,6 @@ state |= NST_MIN_FIXED; } - public void clearMinFixed() { - state &= ~NST_MIN_FIXED; - } - public boolean isMaxFixed() { return (state & NST_MAX_FIXED) != 0; } @@ -69,10 +64,6 @@ state |= NST_MAX_FIXED; } - public void clearMaxFixed() { - state &= ~NST_MAX_FIXED; - } - public boolean isCLenFixed() { return (state & NST_CLEN_FIXED) != 0; } @@ -81,10 +72,6 @@ state |= NST_CLEN_FIXED; } - public void clearCLenFixed() { - state &= ~NST_CLEN_FIXED; - } - public boolean isMark1() { return (state & NST_MARK1) != 0; } @@ -93,10 +80,6 @@ state |= NST_MARK1; } - public void clearMark1() { - state &= ~NST_MARK1; - } - public boolean isMark2() { return (state & NST_MARK2) != 0; } @@ -117,10 +100,6 @@ state |= NST_MEM_BACKREFED; } - public void clearMemBackrefed() { - state &= ~NST_MEM_BACKREFED; - } - public boolean isStopBtSimpleRepeat() { return (state & NST_STOP_BT_SIMPLE_REPEAT) != 0; } @@ -129,10 +108,6 @@ state |= NST_STOP_BT_SIMPLE_REPEAT; } - public void clearStopBtSimpleRepeat() { - state &= ~NST_STOP_BT_SIMPLE_REPEAT; - } - public boolean isRecursion() { return (state & NST_RECURSION) != 0; } @@ -141,10 +116,6 @@ state |= NST_RECURSION; } - public void clearRecursion() { - state &= ~NST_RECURSION; - } - public boolean isCalled() { return (state & NST_CALLED) != 0; } @@ -153,10 +124,6 @@ state |= NST_CALLED; } - public void clearCAlled() { - state &= ~NST_CALLED; - } - public boolean isAddrFixed() { return (state & NST_ADDR_FIXED) != 0; } @@ -165,22 +132,6 @@ state |= NST_ADDR_FIXED; } - public void clearAddrFixed() { - state &= ~NST_ADDR_FIXED; - } - - public boolean isNamedGroup() { - return (state & NST_NAMED_GROUP) != 0; - } - - public void setNamedGroup() { - state |= NST_NAMED_GROUP; - } - - public void clearNamedGroup() { - state &= ~NST_NAMED_GROUP; - } - public boolean isNameRef() { return (state & NST_NAME_REF) != 0; } @@ -189,10 +140,6 @@ state |= NST_NAME_REF; } - public void clearNameRef() { - state &= ~NST_NAME_REF; - } - public boolean isInRepeat() { return (state & NST_IN_REPEAT) != 0; } @@ -201,10 +148,6 @@ state |= NST_IN_REPEAT; } - public void clearInRepeat() { - state &= ~NST_IN_REPEAT; - } - public boolean isNestLevel() { return (state & NST_NEST_LEVEL) != 0; } @@ -213,10 +156,6 @@ state |= NST_NEST_LEVEL; } - public void clearNestLevel() { - state &= ~NST_NEST_LEVEL; - } - public boolean isByNumber() { return (state & NST_BY_NUMBER) != 0; } @@ -225,8 +164,4 @@ state |= NST_BY_NUMBER; } - public void clearByNumber() { - state &= ~NST_BY_NUMBER; - } - } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/bench/AbstractBench.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/bench/AbstractBench.java Thu May 30 10:58:13 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -package jdk.nashorn.internal.runtime.regexp.joni.bench; - -import jdk.nashorn.internal.runtime.regexp.joni.Option; -import jdk.nashorn.internal.runtime.regexp.joni.Regex; -import jdk.nashorn.internal.runtime.regexp.joni.Syntax; - -public abstract class AbstractBench { - protected void bench(String _reg, String _str, int warmup, int times) throws Exception { - char[] reg = _reg.toCharArray(); - char[] str = _str.toCharArray(); - - Regex p = new Regex(reg,0,reg.length,Option.DEFAULT,Syntax.DEFAULT); - - System.err.println("::: /" + _reg + "/ =~ \"" + _str + "\", " + warmup + " * " + times + " times"); - - for(int j=0;j NULL = new ObjPtr(); } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/PosixBracket.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/PosixBracket.java Thu May 30 10:58:13 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS".toCharArray(), WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package jdk.nashorn.internal.runtime.regexp.joni.encoding; - -import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages; -import jdk.nashorn.internal.runtime.regexp.joni.exception.JOniException; - -import java.util.HashMap; - -public class PosixBracket { - - public static final char[][] PBSNamesLower = { - "alnum".toCharArray(), - "alpha".toCharArray(), - "blank".toCharArray(), - "cntrl".toCharArray(), - "digit".toCharArray(), - "graph".toCharArray(), - "lower".toCharArray(), - "print".toCharArray(), - "punct".toCharArray(), - "space".toCharArray(), - "upper".toCharArray(), - "xdigit".toCharArray(), - "ascii".toCharArray(), - "word".toCharArray() - }; - - public static final int PBSValues[] = { - CharacterType.ALNUM, - CharacterType.ALPHA, - CharacterType.BLANK, - CharacterType.CNTRL, - CharacterType.DIGIT, - CharacterType.GRAPH, - CharacterType.LOWER, - CharacterType.PRINT, - CharacterType.PUNCT, - CharacterType.SPACE, - CharacterType.UPPER, - CharacterType.XDIGIT, - CharacterType.ASCII, - CharacterType.WORD, - }; - - public static int propertyNameToCType(String name) { - name = name.toLowerCase(); - if (!PBSTableUpper.containsKey(name)) { - throw new JOniException(ErrorMessages.ERR_INVALID_CHAR_PROPERTY_NAME.replaceAll("%n", name)); - } - return PBSTableUpper.get(name); - } - - private static final HashMap PBSTableUpper = new HashMap(); - - static { - for (int i=0; i" : "invalid char in group number <%n>"; - final String ERR_UNDEFINED_NAME_REFERENCE = "undefined name <%n> reference"; - final String ERR_UNDEFINED_GROUP_REFERENCE = "undefined group <%n> reference"; - final String ERR_MULTIPLEX_DEFINED_NAME = "multiplex defined name <%n>"; - final String ERR_MULTIPLEX_DEFINITION_NAME_CALL = "multiplex definition name <%n> call"; - final String ERR_NEVER_ENDING_RECURSION = "never ending recursion"; + final String ERR_INVALID_CHAR_IN_GROUP_NAME = "invalid char in group number <%n>"; final String ERR_GROUP_NUMBER_OVER_FOR_CAPTURE_HISTORY = "group number is too big for capture history"; - final String ERR_NOT_SUPPORTED_ENCODING_COMBINATION = "not supported encoding combination"; final String ERR_INVALID_COMBINATION_OF_OPTIONS = "invalid combination of options"; - final String ERR_OVER_THREAD_PASS_LIMIT_COUNT = "over thread pass limit count"; - final String ERR_TOO_BIG_SB_CHAR_VALUE = "too big singlebyte char value"; } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ValueException.java --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ValueException.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/exception/ValueException.java Wed Jul 05 18:57:52 2017 +0200 @@ -30,8 +30,4 @@ super(message.replaceAll("%n", str)); } - public ValueException(String message, byte[]bytes, int p, int end) { - this(message, new String(bytes, p, end - p)); - } - } diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties Wed Jul 05 18:57:52 2017 +0200 @@ -125,6 +125,7 @@ type.error.no.method.matches.args=Can not invoke method {0} with the passed arguments; they do not match any of its method signatures. type.error.method.not.constructor=Java method {0} can't be used as a constructor. type.error.env.not.object=$ENV must be an Object. +type.error.unsupported.java.to.type=Unsupported Java.to target type {0}. range.error.inappropriate.array.length=inappropriate array length: {0} range.error.invalid.fraction.digits=fractionDigits argument to {0} must be in [0, 20] range.error.invalid.precision=precision argument toPrecision() must be in [1, 21] diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties Wed Jul 05 18:57:52 2017 +0200 @@ -277,6 +277,12 @@ desc="Print the symbol table." \ } +nashorn.option.range.analysis = { \ + name="--range-analysis", \ + is_undocumented=true, \ + desc="Do range analysis using known compile time types, and try to narrow number types" \ +} + nashorn.option.D = { \ name="-D", \ desc="-Dname=value. Set a system property. This option can be repeated.", \ @@ -326,6 +332,15 @@ type=TimeZone \ } +nashorn.option.locale = { \ + name="--locale", \ + short_name="-l", \ + is_undocumented=true, \ + params="", \ + desc="Set Locale for script execution.", \ + type=Locale \ +} + nashorn.option.trace.callsites = { \ name="--trace-callsites", \ short_name="-tcs", \ diff -r a233c04832cf -r a08d0f5b08bc nashorn/src/netscape/javascript/JSObject.java --- a/nashorn/src/netscape/javascript/JSObject.java Thu May 30 10:58:13 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +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 netscape.javascript; - -import java.applet.Applet; - -/** - * Stub for JSObject to get compilation going. - */ -public abstract class JSObject { - - /** - * Get the window for an {@link Applet}. Not supported - * by Nashorn - * - * @param a applet - * @return the window instance - */ - public static JSObject getWindow(final Applet a) { - throw new UnsupportedOperationException("getWindow"); - } - - /** - * Call a JavaScript method - * - * @param methodName name of method - * @param args arguments to method - * @return result of call - */ - public abstract Object call(String methodName, Object args[]); - - /** - * Evaluate a JavaScript expression - * - * @param s JavaScript expression to evaluate - * @return evaluation result - */ - public abstract Object eval(String s); - - /** - * Retrieves a named member of a JavaScript object. - * - * @param name of member - * @return member - */ - public abstract Object getMember(String name); - - /** - * Retrieves an indexed member of a JavaScript object. - * - * @param index index of member slot - * @return member - */ - public abstract Object getSlot(int index); - - /** - * Remove a named member from a JavaScript object - * - * @param name name of member - */ - public abstract void removeMember(String name); - - /** - * Set a named member in a JavaScript object - * - * @param name name of member - * @param value value of member - */ - public abstract void setMember(String name, Object value); - - /** - * Set an indexed member in a JavaScript object - * - * @param index index of member slot - * @param value value of member - */ - public abstract void setSlot(int index, Object value); -} diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8008554.js --- a/nashorn/test/script/basic/JDK-8008554.js Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/test/script/basic/JDK-8008554.js Wed Jul 05 18:57:52 2017 +0200 @@ -32,5 +32,5 @@ var dir = __DIR__; var file = __FILE__.replace("JDK-8008554", "NASHORN-99"); load(file); -file = "file://" + __DIR__ + "NASHORN-99.js"; +file = "file:///" + __DIR__ + "NASHORN-99.js"; load(file); diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8010804.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8010804.js Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,86 @@ +/* + * 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-8010804: Review long and integer usage conventions + * + * @test + * @run + */ + +var x = []; +print(x.length); +x[4294967294] = 1; +print(x.length); +x[4294967295] = 1; +print(x.length); +print(x.slice(4294967293).length); +print(x.slice(4294967294).length); +print(x.slice(4294967295).length); +print(x.slice(4294967296).length); + +print(x.slice(-4294967293).length); +print(x.slice(-4294967294).length); +print(x.slice(-4294967295).length); +print(x.slice(-4294967296).length); + +print(x.slice(0, 4294967293).length); +print(x.slice(0, 4294967294).length); +print(x.slice(0, 4294967295).length); +print(x.slice(0, 4294967296).length); + +print(x.slice(0, -4294967293).length); +print(x.slice(0, -4294967294).length); +print(x.slice(0, -4294967295).length); +print(x.slice(0, -4294967296).length); + +print(x.slice(9223371036854775807).length); +print(x.slice(9223372036854775807).length); +print(x.slice(9223373036854775807).length); +print(x.slice(9223374036854775807).length); + +print(x.slice(-9223371036854775807).length); +print(x.slice(-9223372036854775807).length); +print(x.slice(-9223373036854775807).length); +print(x.slice(-9223374036854775807).length); + +print(x.slice(-9223371036854775807, 1).length); +print(x.slice(-9223372036854775807, 1).length); +print(x.slice(-9223373036854775807, 1).length); +print(x.slice(-9223374036854775807, 1).length); + +print(x.slice(-9223371036854775807, -1).length); +print(x.slice(-9223372036854775807, -1).length); +print(x.slice(-9223373036854775807, -1).length); +print(x.slice(-9223374036854775807, -1).length); + +print(x.slice(Infinity).length); +print(x.slice(Infinity, Infinity).length); +print(x.slice(Infinity, -Infinity).length); +print(x.slice(-Infinity).length); +print(x.slice(-Infinity, Infinity).length); +print(x.slice(-Infinity, -Infinity).length); + +var d = new Date(); +d.setYear(Infinity); +print(d); \ No newline at end of file diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8010804.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8010804.js.EXPECTED Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,42 @@ +0 +4294967295 +4294967295 +2 +1 +0 +0 +4294967293 +4294967294 +4294967295 +4294967295 +4294967293 +4294967294 +4294967295 +4294967295 +2 +1 +0 +0 +0 +0 +0 +0 +4294967295 +4294967295 +4294967295 +4294967295 +1 +1 +1 +1 +4294967294 +4294967294 +4294967294 +4294967294 +0 +0 +0 +4294967295 +4294967295 +0 +Invalid Date diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8011023.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8011023.js Wed Jul 05 18:57:52 2017 +0200 @@ -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. + */ + +/** + * Round should be ecma compliant + * + * @test + * @run + */ + +print(1/Math.round(-0.5)); +print(Math.round(9007199254740991)); +print(Math.round(9223372036854775807*2)); + diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8011023.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8011023.js.EXPECTED Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,3 @@ +-Infinity +9007199254740991 +18446744073709552000 diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8011718.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8011718.js Wed Jul 05 18:57:52 2017 +0200 @@ -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-8011718: binding already bound function with extra arguments fails. + * + * @test + * @run + */ + +var obj = { + hello:"From obj", +}; +var obj2 = { + hello:"From obj2", +}; + +function doit(cb){ + cb(); + var cb2 = cb.bind(obj2, "This one is not acccepted"); + cb2(); +} + +doit(function(){ + print(this.hello); + }.bind(obj)); diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8011718.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8011718.js.EXPECTED Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,2 @@ +From obj +From obj diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8012083.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8012083.js Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,70 @@ +/* + * 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-8012093 - array literals can only be subject to constant evaluation under very special + * circumstances. + * + * @test + * @run + */ + + +var w00t = 17; +print(+[w00t]); + +var empty = []; +print(empty == false); + +print([] == false); +print([] === false); +print(!![]); + +print(~[]); +print(![]); +print(![17]); +print(![17,1,2]); + +var one = 1; +var two = 2; +var a1 = [one]; +var a2 = [two]; +print(+a1 + +a2); //3 + +var x = 1; +print(+["apa"]); +print(+[]); //0 +print(+[1]); //1 +print(+[x]); //1 +print(+[1,2,3]); //NaN +var a = []; +var b = [1]; +print(a/b); +print(++[[]][+[]]+[+[]]); //10 +print(+[] == 0); + +var first = [![]+[]][+[]][+[]]+[![]+[]][+[]][+!+[]]+[!+[]+[]][+![]][+![]]+[![]+[]][+[]][+!+[]]+[![]+[]][+[]][+!+[]+!+[]]; +var second =(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]; + +print(first + " " + second); + diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8012083.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8012083.js.EXPECTED Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,19 @@ +17 +true +true +false +true +-1 +false +false +false +3 +NaN +0 +1 +1 +NaN +0 +10 +true +fatal fail diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8012305.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8012305.js Wed Jul 05 18:57:52 2017 +0200 @@ -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. + */ + +/** + * JDK-8012305: Function.bind can't be called on prototype function inside constructor + * + * @test + * @run + */ + +function MyObject() { + // If the call to bind is removed, then the function is properly printed. + print("function " + this._process); + this._process = this._process.bind(this); +} + +MyObject.prototype._process = function() { print("Message "); } + +var s = new MyObject(); diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8012305.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8012305.js.EXPECTED Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,1 @@ +function function() { print("Message "); } diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8013919.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8013919.js Wed Jul 05 18:57:52 2017 +0200 @@ -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. + */ + +/** + * JDK-8013913: finally cloning of function node declarations caused + * method collissions + * + * @test + * @run + */ + +try { + print("a"); +} finally { + var b = function() { + print("b"); + } + b(); +} diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8013919.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8013919.js.EXPECTED Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,2 @@ +a +b diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8014426.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8014426.js Wed Jul 05 18:57:52 2017 +0200 @@ -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. + */ + +/** + * Ensure catchall exceptions from finally inlining are rethrown as is + * + * @test + * @run + */ + +function runScriptEngine() { + var fac = new Packages.jdk.nashorn.api.scripting.NashornScriptEngineFactory(); + var engine = fac.getScriptEngine(); + engine.eval( +"try {\n\ + doIt();\n\ +} finally { \n\ + var x = 17;\n\ +}\n\ +function doIt() {\n\ + throw new TypeError('en stor graa noshoerning!');\n\ +}\n"); +} + +try { + runScriptEngine(); +} catch(e) { + print(e); +} diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8014426.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8014426.js.EXPECTED Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,1 @@ +javax.script.ScriptException: TypeError: en stor graa noshoerning! in at line number 7 at column number 2 diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8014647.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8014647.js Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,40 @@ +/* + * 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-8014647: Allow class-based overrides to be initialized with a ScriptFunction + * + * @test + * @run + */ + +var RunnableImpl1 = Java.extend(java.lang.Runnable, function() { print("I'm runnable 1!") }) +var RunnableImpl2 = Java.extend(java.lang.Runnable, function() { print("I'm runnable 2!") }) +var r1 = new RunnableImpl1() +var r2 = new RunnableImpl2() +var r3 = new RunnableImpl2(function() { print("I'm runnable 3!") }) +r1.run() +r2.run() +r3.run() +print("r1.class === r2.class: " + (r1.class === r2.class)) +print("r2.class === r3.class: " + (r2.class === r3.class)) diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8014647.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8014647.js.EXPECTED Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,5 @@ +I'm runnable 1! +I'm runnable 2! +I'm runnable 3! +r1.class === r2.class: false +r2.class === r3.class: true diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8014735.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8014735.js Wed Jul 05 18:57:52 2017 +0200 @@ -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. + */ + +/** + * JDK-8014735: Typed Array, BYTES_PER_ELEMENT should be a class property + * + * @test + * @run + */ + +function bytesPerElement(func) { + print(func.name + ".BYTES_PER_ELEMENT = " + func.BYTES_PER_ELEMENT); +} + +bytesPerElement(Int8Array); +bytesPerElement(Int16Array); +bytesPerElement(Int32Array); +bytesPerElement(Uint8Array); +bytesPerElement(Uint8ClampedArray); +bytesPerElement(Uint16Array); +bytesPerElement(Uint32Array); +bytesPerElement(Float32Array); +bytesPerElement(Float64Array); diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8014735.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8014735.js.EXPECTED Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,9 @@ +Int8Array.BYTES_PER_ELEMENT = 1 +Int16Array.BYTES_PER_ELEMENT = 2 +Int32Array.BYTES_PER_ELEMENT = 4 +Uint8Array.BYTES_PER_ELEMENT = 1 +Uint8ClampedArray.BYTES_PER_ELEMENT = 1 +Uint16Array.BYTES_PER_ELEMENT = 2 +Uint32Array.BYTES_PER_ELEMENT = 4 +Float32Array.BYTES_PER_ELEMENT = 4 +Float64Array.BYTES_PER_ELEMENT = 8 diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8014953.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8014953.js Wed Jul 05 18:57:52 2017 +0200 @@ -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-8014953: Have NativeJavaPackage throw a ClassNotFoundException when invoked with "new" + * + * @test + * @run + */ + +try { + new java.util.ArrrayList(16) +} catch(e) { + print("Invoked as constructor"); + print("e.class=" + e.class) + print("e.message=" + e.message); +} + +try { + java.util.ArrrayList(16) +} catch(e) { + print("Invoked as method"); + print("e.class=" + e.class) + print("e.message=" + e.message); +} diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8014953.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8014953.js.EXPECTED Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,6 @@ +Invoked as constructor +e.class=class java.lang.ClassNotFoundException +e.message=java.util.ArrrayList +Invoked as method +e.class=class java.lang.ClassNotFoundException +e.message=java.util.ArrrayList diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8015267.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8015267.js Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,109 @@ +/* + * 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-8015267: have a List/Deque adapter for JS array-like objects + * + * @test + * @run + */ + +var a = ['a', 'b', 'c', 'd'] + +var l = Java.to(a, java.util.List) +print(l instanceof java.util.List) +print(l instanceof java.util.Deque) + +print(l[0]) +print(l[1]) +print(l[2]) +print(l[3]) + +print(l.size()) + +l.push('x') +print(a) + +l.addLast('y') +print(a) + +print(l.pop()) +print(l.removeLast()) +print(a) + +l.add('e') +l.add(5, 'f') +print(a) + +l.add(0, 'z') +print(a) + +l.add(2, 'x') +print(a) + +l[7] = 'g' +print(a) + +try { l.add(15, '') } catch(e) { print(e.class) } +try { l.remove(15) } catch(e) { print(e.class) } +try { l.add(-1, '') } catch(e) { print(e.class) } +try { l.remove(-1) } catch(e) { print(e.class) } + +l.remove(7) +l.remove(2) +l.remove(0) +print(a) + +print(l.peek()) +print(l.peekFirst()) +print(l.peekLast()) + +print(l.element()) +print(l.getFirst()) +print(l.getLast()) + +l.offer('1') +l.offerFirst('2') +l.offerLast('3') +print(a) + +a = ['1', '2', 'x', '3', '4', 'x', '5', '6', 'x', '7', '8'] +print(a) +var l = Java.to(a, java.util.List) +l.removeFirstOccurrence('x') +print(a) +l.removeLastOccurrence('x') +print(a) + +var empty = Java.to([], java.util.List) +try { empty.pop() } catch(e) { print(e.class) } +try { empty.removeFirst() } catch(e) { print(e.class) } +try { empty.removeLast() } catch(e) { print(e.class) } + +try { empty.element() } catch(e) { print(e.class) } +try { empty.getFirst() } catch(e) { print(e.class) } +try { empty.getLast() } catch(e) { print(e.class) } + +print(empty.peek()) +print(empty.peekFirst()) +print(empty.peekLast()) diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8015267.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8015267.js.EXPECTED Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,40 @@ +true +true +a +b +c +d +4 +x,a,b,c,d +x,a,b,c,d,y +x +y +a,b,c,d +a,b,c,d,e,f +z,a,b,c,d,e,f +z,a,x,b,c,d,e,f +z,a,x,b,c,d,e,g +class java.lang.IndexOutOfBoundsException +class java.lang.IndexOutOfBoundsException +class java.lang.IndexOutOfBoundsException +class java.lang.IndexOutOfBoundsException +a,b,c,d,e +a +a +e +a +a +e +2,a,b,c,d,e,1,3 +1,2,x,3,4,x,5,6,x,7,8 +1,2,3,4,x,5,6,x,7,8 +1,2,3,4,x,5,6,7,8 +class java.util.NoSuchElementException +class java.util.NoSuchElementException +class java.util.NoSuchElementException +class java.util.NoSuchElementException +class java.util.NoSuchElementException +class java.util.NoSuchElementException +null +null +null diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8015348.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8015348.js Wed Jul 05 18:57:52 2017 +0200 @@ -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. + */ + +/** + * JDK-8015348: RegExp("[") results in StackOverflowError + * + * @test + * @run + */ + +try { + new RegExp('['); +} catch (error) { + print(error.name); +} diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8015348.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8015348.js.EXPECTED Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,1 @@ +SyntaxError diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8015349.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8015349.js Wed Jul 05 18:57:52 2017 +0200 @@ -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. + */ + +/** + * JDK-8015349: "abc".lastIndexOf("a",-1) should evaluate to 0 and not -1 + * + * @test + * @run + */ + +function printEval(code) { + print(code + " = " + eval(code)); +} + +printEval("'abc'.lastIndexOf('a', 4)"); +printEval("'abc'.lastIndexOf('b', Infinity)"); +printEval("'abc'.lastIndexOf('a', -1)"); +printEval("'abc'.lastIndexOf('a', -Infinity)"); +printEval("'oracle'.lastIndexOf('u')"); +printEval("'hello'.lastIndexOf('l')"); +printEval("'hello'.lastIndexOf('l', 2)"); +printEval("'hello'.lastIndexOf('l', 3)"); +printEval("'hello'.lastIndexOf('l', 1)"); diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8015349.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8015349.js.EXPECTED Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,9 @@ +'abc'.lastIndexOf('a', 4) = 0 +'abc'.lastIndexOf('b', Infinity) = 1 +'abc'.lastIndexOf('a', -1) = 0 +'abc'.lastIndexOf('a', -Infinity) = 0 +'oracle'.lastIndexOf('u') = -1 +'hello'.lastIndexOf('l') = 3 +'hello'.lastIndexOf('l', 2) = 2 +'hello'.lastIndexOf('l', 3) = 3 +'hello'.lastIndexOf('l', 1) = -1 diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8015352.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8015352.js Wed Jul 05 18:57:52 2017 +0200 @@ -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-8015352: "i".toUpperCase() => currently returns "İ", but should be "I" (with Turkish locale) + * + * @test + * @option --locale=tr-TR + * @run + */ + +if ("i".toUpperCase() != "I") { + fail("'i'.toUpperCase() is not 'I'"); +} + +if ("i".toUpperCase() == "i".toLocaleUpperCase()) { + fail("'i'.toUpperCase() == 'i'.toLocaleUpperCase()"); +} + +if ("I".toLowerCase() != "i") { + fail("'I'.toLowerCase() is not 'i'"); +} + +if ("I".toLowerCase() == "I".toLocaleLowerCase()) { + fail("'i'.toLowerCase() == 'i'.toLocaleLowerCase()"); +} diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/JDK-8015354.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8015354.js Wed Jul 05 18:57:52 2017 +0200 @@ -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-8015354: JSON.parse should not use [[Put]] but use [[DefineOwnProperty]] instead + * + * @test + * @run + */ + +Object.defineProperty(Object.prototype, + "", { + set: function(v) { + throw "set called"; + } +}); + +JSON.parse('{}',function(){}); + +Object.defineProperty(Object.prototype, + "foo",{ + set: function(v) { + throw "set called"; + } +}); +JSON.parse('{"foo": 1}'); diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/NASHORN-377.js --- a/nashorn/test/script/basic/NASHORN-377.js Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/test/script/basic/NASHORN-377.js Wed Jul 05 18:57:52 2017 +0200 @@ -43,7 +43,7 @@ function arrstr(a, n, w) { var s = ""; if (typeof n == "undefined") n = a.length; - if (typeof w == "undefined") w = a.BYTES_PER_ELEMENT * 2; + if (typeof w == "undefined") w = a.constructor.BYTES_PER_ELEMENT * 2; for (var i = 0; i < n; i++) { s += tohex(a[i], w); } @@ -96,7 +96,7 @@ var b = new ArrayBuffer(8); for (var i in types) { var x = new types[i](b); - print(x.byteOffset, x.byteLength, x.length, x.BYTES_PER_ELEMENT); + print(x.byteOffset, x.byteLength, x.length, x.constructor.BYTES_PER_ELEMENT); assertTrue(function(){ return x.constructor === types[i] }); } })(); diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/NASHORN-556.js --- a/nashorn/test/script/basic/NASHORN-556.js Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/test/script/basic/NASHORN-556.js Wed Jul 05 18:57:52 2017 +0200 @@ -47,7 +47,7 @@ // (NoTypeArrayData) var empty = {}; empty.length = 10; - Java.toJavaArray(empty); + Java.to(empty); delete empty[0]; Array.prototype.slice.call(empty, 0, 1); Array.prototype.pop.call(empty); @@ -63,7 +63,7 @@ function f2() { // DeletedArrayFilter var deleted = [,1,,2,,3,,4,,]; - assertEq(2, Java.toJavaArray(deleted)[3]); + assertEq(2, Java.to(deleted)[3]); assertEq(undefined, deleted.pop()); assertEq(4, deleted.pop()); deleted.unshift(5); @@ -78,7 +78,7 @@ function f3() { // DeletedRangeArrayFilter var delrange = [1,2,3,,,,,,,,,,]; - Java.toJavaArray(delrange); + Java.to(delrange); delrange.unshift(4); p.apply(null, delrange); print(delrange.slice(1,3), delrange.slice(2,6)); @@ -88,7 +88,7 @@ function f4() { // NumberArrayData var num = [1.1,2.2,3.3,4.4,5.5]; - Java.toJavaArray(num); + Java.to(num); assertEq(2, num[3] >>> 1); assertEq(5, num[4] | 0); assertEq(5.5, num.pop()); @@ -104,7 +104,7 @@ function f5() { // ObjectArrayData var obj = [2,"two",3.14,"pi",14,"fourteen"]; - Java.toJavaArray(obj); + Java.to(obj); assertEq(-12.86, obj[2] - 16); assertEq(7, obj[4] >>> 1); obj.unshift("one"); @@ -131,14 +131,14 @@ sparse.length = 1024*1024; sparse.push(sparse.length); delete sparse[sparse.length-1]; - //print(Java.toJavaArray(sparse).length); + //print(Java.to(sparse).length); (function(){}).apply(null, sparse); } function f7() { // UndefinedArrayFilter var undef = [1,2,3,4,5,undefined,7,8,9,19]; - Java.toJavaArray(undef); + Java.to(undef); assertEq(4, undef[8] >>> 1); var tmp = undef[9] >>> 1; undef[8] = tmp; @@ -154,8 +154,8 @@ function f8() { // LongArrayData - var j = Java.toJavaScriptArray(Java.toJavaArray([23,37,42,86,47], "long")); - Java.toJavaArray(j); + var j = Java.from(Java.to([23,37,42,86,47], "long[]")); + Java.to(j); p.apply(null, j); assertEq(43, j[3] >>> 1); assertEq(36, j[4] - 11); @@ -164,12 +164,12 @@ assertEq(7, j.shift()); assertEq(47, j.pop()); j.push("asdf"); - j = Java.toJavaScriptArray(Java.toJavaArray([23,37,42,86,47], "long")); + j = Java.from(Java.to([23,37,42,86,47], "long[]")); j.length = 3; j[0] = 13; - j = Java.toJavaScriptArray(Java.toJavaArray([23,37,42,86,47], "long")); + j = Java.from(Java.to([23,37,42,86,47], "long[]")); delete j[0]; - j = Java.toJavaScriptArray(Java.toJavaArray([23,37,42,86,47], "long")); + j = Java.from(Java.to([23,37,42,86,47], "long[]")); j.length = 20; j[0] = 13.37; } diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/allgettersetters.js --- a/nashorn/test/script/basic/allgettersetters.js Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/test/script/basic/allgettersetters.js Wed Jul 05 18:57:52 2017 +0200 @@ -34,6 +34,9 @@ for (var i in properties) { var prop = properties[i]; try { + if (!/\d.*/.test(prop)) { + eval("obj." + prop + " = " + "obj." + prop + ";"); + } obj[prop] = obj[prop]; } catch (e) { if (!expectError || !(e instanceof TypeError)) { diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/compile-octane.js.EXPECTED --- a/nashorn/test/script/basic/compile-octane.js.EXPECTED Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/test/script/basic/compile-octane.js.EXPECTED Wed Jul 05 18:57:52 2017 +0200 @@ -1,39 +1,13 @@ -Compiling... box2d.js -Compiled OK: box2d.js - -Compiling... code-load.js -Compiled OK: code-load.js - -Compiling... crypto.js -Compiled OK: crypto.js - -Compiling... deltablue.js -Compiled OK: deltablue.js - -Compiling... earley-boyer.js -Compiled OK: earley-boyer.js - -Compiling... gbemu.js -Compiled OK: gbemu.js - -Compiling... mandreel.js -Compiled OK: mandreel.js - -Compiling... navier-stokes.js -Compiled OK: navier-stokes.js - -Compiling... pdfjs.js -Compiled OK: pdfjs.js - -Compiling... raytrace.js -Compiled OK: raytrace.js - -Compiling... regexp.js -Compiled OK: regexp.js - -Compiling... richards.js -Compiled OK: richards.js - -Compiling... splay.js -Compiled OK: splay.js - +Compiled OK: box2d +Compiled OK: code-load +Compiled OK: crypto +Compiled OK: deltablue +Compiled OK: earley-boyer +Compiled OK: gbemu +Compiled OK: mandreel +Compiled OK: navier-stokes +Compiled OK: pdfjs +Compiled OK: raytrace +Compiled OK: regexp +Compiled OK: richards +Compiled OK: splay diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/javaarrayconversion.js --- a/nashorn/test/script/basic/javaarrayconversion.js Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/test/script/basic/javaarrayconversion.js Wed Jul 05 18:57:52 2017 +0200 @@ -34,7 +34,7 @@ var testCount = 0; function testF(inputValue, type, testFn) { - var x = Java.toJavaArray([inputValue], type)[0]; + var x = Java.to([inputValue], type + "[]")[0]; if(!testFn(x)) { throw ("unexpected value: " + x) } @@ -130,7 +130,7 @@ function assertCantConvert(sourceType, targetType) { try { - Java.toJavaArray([new Java.type(sourceType)()], targetType) + Java.to([new Java.type(sourceType)()], targetType + "[]") throw "no TypeError encountered" } catch(e) { if(!(e instanceof TypeError)) { @@ -164,7 +164,7 @@ intArray[0] = 1234; intArray[1] = 42; intArray[2] = 5; -var jsIntArray = Java.toJavaScriptArray(intArray) +var jsIntArray = Java.from(intArray) assert(jsIntArray instanceof Array); assert(jsIntArray[0] === 1234); assert(jsIntArray[1] === 42); @@ -179,7 +179,7 @@ var byteArray = new (Java.type("byte[]"))(2) byteArray[0] = -128; byteArray[1] = 127; -var jsByteArray = Java.toJavaScriptArray(byteArray) +var jsByteArray = Java.from(byteArray) assert(jsByteArray instanceof Array); assert(jsByteArray[0] === -128); assert(jsByteArray[1] === 127); @@ -187,7 +187,7 @@ var shortArray = new (Java.type("short[]"))(2) shortArray[0] = -32768; shortArray[1] = 32767; -var jsShortArray = Java.toJavaScriptArray(shortArray) +var jsShortArray = Java.from(shortArray) assert(jsShortArray instanceof Array); assert(jsShortArray[0] === -32768); assert(jsShortArray[1] === 32767); @@ -195,7 +195,7 @@ var floatArray = new (Java.type("float[]"))(2) floatArray[0] = java.lang.Float.MIN_VALUE; floatArray[1] = java.lang.Float.MAX_VALUE; -var jsFloatArray = Java.toJavaScriptArray(floatArray) +var jsFloatArray = Java.from(floatArray) assert(jsFloatArray instanceof Array); assert(jsFloatArray[0] == java.lang.Float.MIN_VALUE); assert(jsFloatArray[1] == java.lang.Float.MAX_VALUE); @@ -204,7 +204,7 @@ charArray[0] = "a"; charArray[1] = "b"; charArray[2] = "1"; -var jsCharArray = Java.toJavaScriptArray(charArray) +var jsCharArray = Java.from(charArray) assert(jsCharArray instanceof Array); assert(jsCharArray[0] === 97); assert(jsCharArray[1] === 98); @@ -213,7 +213,7 @@ var booleanArray = new (Java.type("boolean[]"))(2) booleanArray[0] = true; booleanArray[1] = false; -var jsBooleanArray = Java.toJavaScriptArray(booleanArray) +var jsBooleanArray = Java.from(booleanArray) assert(jsBooleanArray instanceof Array); assert(jsBooleanArray[0] === true); assert(jsBooleanArray[1] === false); diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/ranges_disabled.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/ranges_disabled.js Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,32 @@ +/* + * 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. + */ + +/** + * range analysis test. check that computation return values are correct + * both with and without range analysis + * + * @test + * @run + */ + +load(__DIR__ + "ranges_payload.js"); diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/ranges_disabled.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/ranges_disabled.js.EXPECTED Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,4 @@ +289 +11094405 +4294967293 +-4722 diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/ranges_enabled.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/ranges_enabled.js Wed Jul 05 18:57:52 2017 +0200 @@ -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. + */ + +/** + * range analysis test. check that computation return values are correct + * both with and without range analysis + * + * @test + * @option --range-analysis + * @run + */ + +load(__DIR__ + "ranges_payload.js"); diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/ranges_enabled.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/ranges_enabled.js.EXPECTED Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,4 @@ +289 +11094405 +4294967293 +-4722 diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/ranges_payload.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/ranges_payload.js Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,74 @@ +/* + * 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. + */ + +/** + * range analysis test. check that computation return values are correct + * both with and without range analysis + * + * @subtest + */ + +function f(c) { + var v = c & 0xffff; + var w = v & 0xfff; + var x = v * w; + return x; +} + +function g() { + var sum = 0; + for (var x = 0; x < 4711; x++) { + sum += x; + } + return sum; +} + +function g2() { + var sum = 0; + //make sure we overflow + var displacement = 0x7ffffffe; + for (var x = displacement; x < (displacement + 2); x++) { + sum += x; + } + return sum; +} + +//mostly provide code coverage for all the range operations +function h() { + var sum = 0; + sum += 4711; + sum &= 0xffff; + sum /= 2; + sum *= 2; + sum -= 4; + sum |= 2; + sum ^= 17; + sum = sum % 10000; + sum = -sum; + return sum +} + +print(f(17)); +print(g()); +print(g2()); +print(h()); diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/basic/run-octane.js --- a/nashorn/test/script/basic/run-octane.js Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/test/script/basic/run-octane.js Wed Jul 05 18:57:52 2017 +0200 @@ -26,36 +26,20 @@ */ var tests = [ - "box2d.js", - "code-load.js", - "crypto.js", - "deltablue.js", - "earley-boyer.js", - "gbemu.js", - "mandreel.js", - "navier-stokes.js", - "pdfjs.js", - "raytrace.js", - "regexp.js", - "richards.js", - "splay.js" + {file:"box2d",suite:"Box2DBenchmark"}, + {file:"code-load",suite:"CodeLoad"}, + {file:"crypto",suite:"Crypto"}, + {file:"deltablue",suite:"DeltaBlue"}, + {file:"earley-boyer", suite:"EarleyBoyer"}, + {file:"gbemu", suite:"GameboyBenchmark"}, + {file:"mandreel", suite:"MandreelBenchmark"}, + {file:"navier-stokes", suite:"NavierStokes"}, + {file:"pdfjs", suite:"PdfJS"}, + {file:"raytrace", suite:"RayTrace"}, + {file:"regexp", suite:"RegExpSuite"}, + {file:"richards", suite:"Richards"}, + {file:"splay", suite:"Splay"} ]; - -// hack, teardown breaks things defined in the global space, making it impossible -// to do multiple consecutive benchmark runs with the same harness. I think it's a bug -// that the setup and teardown aren't each others constructor and destructor but rather -// that the benchmarks rely on partial global state. For shame, Octane! -var ignoreTeardown = [ - { name: "box2d.js" }, - { name: "gbemu.js" }, -]; - - -//TODO mandreel can be compiled as a test, but not run multiple times unless modified to not have global state -var compileOnly = { - "mandreel.js" : true -}; - var dir = (typeof(__DIR__) == 'undefined') ? "test/script/basic/" : __DIR__; // TODO: why is this path hard coded when it's defined in project properties? @@ -71,110 +55,106 @@ } function should_compile_only(name) { - return (typeof compile_only !== 'undefined') || compileOnly[name] === true; + return (typeof compile_only !== 'undefined') } function run_one_benchmark(arg, iters) { - var file_name; - var file = arg.split('/'); - if (file.length == 1) { - file = arg.split('\\'); - } - - //trim off trailing path separators - while (file[file.length - 1].indexOf(".js") == -1) { - file.pop(); - } - file_name = file[file.length - 1]; - + var file = (arg.file + ".js").split('/'); + + file_name = path + file[file.length - 1]; + var compile_and_return = should_compile_only(file_name); if (compile_and_return) { if (typeof compile_only === 'undefined') { //for a run, skip compile onlies, don't even compile them return; } - print("Compiling... " + file_name); } - - load(path + 'base.js'); - load(arg); + + print_verbose("Loading... " + file_name); + load(file_name); if (compile_and_return) { - print("Compiled OK: " + file_name); - print(""); + print_always("Compiled OK: " + arg.file); return; } var success = true; - var hiscore = 0; - var loscore = 10e8; var current_name; - function PrintResult(name, result) { - current_name = name; - } - - function PrintError(name, error) { - current_name = name; - PrintResult(name, error); - success = false; - } - - function PrintScore(score) { - if (success) { - if (+score >= hiscore) { - hiscore = +score; - } - if (+score <= loscore) { - loscore = +score; - } - } - - if (verbose) { - print("Score: " + score); - } - } - if (iters == undefined) { iters = numberOfIterations; } else { numberOfIterations = iters; } - - print(runtime + ": running " + file_name + "..."); - - for (var i = 0; i < numberOfIterations; i++) { - var callbacks = - { NotifyResult: PrintResult, - NotifyError: PrintError, - NotifyScore: PrintScore }; - - for (j in ignoreTeardown) { - var ignore = ignoreTeardown[j]; - if (endsWith(arg, ignore.name)) { - var teardownOverride = ignore.teardown; - if (!teardownOverride) { - teardownOverride = function() {}; - } + + var benchmarks = eval(arg.suite + ".benchmarks"); + var min_score = 1e9; + var max_score = 0; + var mean_score = 0; - for (k in BenchmarkSuite.suites) { - var benchmarks = BenchmarkSuite.suites[k].benchmarks; - for (l in benchmarks) { - benchmarks[l].TearDown = teardownOverride; - } - } - break; - } + try { + for (var x = 0; x < benchmarks.length ; x++) { + benchmarks[x].Setup(); + } + print_verbose("Running '" + arg.file + "' for " + iters + " iterations of no less than " + min_time + " seconds (" + runtime + ")"); + + var scores = []; + + var min_time_ms = min_time * 1000; + var len = benchmarks.length; + + for (var it = 0; it < iters + 1; it++) { + //every iteration must take a minimum of 10 secs + var ops = 0; + var elapsed = 0; + var start = new Date; + do { + for (var i = 0; i < len; i++) { + benchmarks[i].run(); + } + ops += len; + elapsed = new Date - start; + } while (elapsed < min_time * 1000); + + var score = ops / elapsed * 1000 * 60; + scores.push(score); + var name = it == 0 ? "warmup" : "iteration " + it; + print_verbose("[" + arg.file + "] " + name + " finished " + score.toFixed(0) + " ops/minute"); } - - BenchmarkSuite.RunSuites(callbacks); + + for (var x = 0; x < benchmarks.length ; x++) { + benchmarks[x].TearDown(); + } + + for (var x = 1; x < iters + 1 ; x++) { + mean_score += scores[x]; + min_score = Math.min(min_score, scores[x]); + max_score = Math.max(max_score, scores[x]); + } + mean_score /= iters; + + } catch (e) { + print_always("*** Aborted and setting score to zero. Reason: " + e); + mean_score = min_score = max_score = 0; + scores = [0]; } - - var start = "Score: "; - if (runtime != "") { - start = runtime + ": "; - } - print(start + current_name + ' (version ' + BenchmarkSuite.version + '): ' + loscore + '-' + hiscore); + + var res = "[" + arg.file + "] " + mean_score.toFixed(0); + if (verbose) { + res += " ops/minute (" + min_score.toFixed(0) + "-" + max_score.toFixed(0) + "), warmup=" + scores[0].toFixed(0); + } + print_always(res); +} + +function print_always(x) { + print(x); +} + +function print_verbose(x) { + if (verbose) { + print(x); + } } function run_suite(tests, iters) { @@ -186,6 +166,7 @@ runtime = "command line"; var args = []; + if (typeof $ARGS !== 'undefined') { args = $ARGS; } else if (typeof arguments !== 'undefined' && arguments.length != 0) { @@ -211,6 +192,7 @@ var tests_found = []; var iters = undefined; +var min_time = 5; for (var i = 0; i < args.length; i++) { arg = args[i]; @@ -220,21 +202,41 @@ runtime = args[++i]; } else if (arg == "--verbose") { verbose = true; + } else if (arg == "--min-time") { + min_time = +args[++i]; } else if (arg == "") { continue; //skip } else { - tests_found.push(arg); + var found = false; + for (j in tests) { + if (tests[j].file === arg) { + tests_found.push(tests[j]); + found = true; + break; + } + } + if (!found) { + var str = "unknown test name: '" + arg + "' -- valid names are: "; + for (j in tests) { + if (j != 0) { + str += ", "; + } + str += "'" + tests[j].file + "'"; + } + throw str; + } } } if (tests_found.length == 0) { for (i in tests) { - tests_found.push(path + tests[i]); + tests_found.push(tests[i]); } } tests_found.sort(); +load(path + 'base.js'); run_suite(tests_found, iters); diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/currently-failing/logcoverage.js --- a/nashorn/test/script/currently-failing/logcoverage.js Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/test/script/currently-failing/logcoverage.js Wed Jul 05 18:57:52 2017 +0200 @@ -53,8 +53,7 @@ // set new standard err System.setErr(newErr); System.setOut(newOut); - var strType = Java.type("java.lang.String"); - var engine = fac.getScriptEngine(Java.toJavaArray(opts, strType)); + var engine = fac.getScriptEngine(Java.to(opts, "java.lang.String[]")); var reader = new java.io.FileReader(name); engine.eval(reader); newErr.flush(); diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/trusted/NASHORN-638.js --- a/nashorn/test/script/trusted/NASHORN-638.js Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/test/script/trusted/NASHORN-638.js Wed Jul 05 18:57:52 2017 +0200 @@ -47,8 +47,7 @@ try { // set new standard err System.setErr(newErr); - var strType = Java.type("java.lang.String"); - var engine = fac.getScriptEngine(Java.toJavaArray(opts, strType)); + var engine = fac.getScriptEngine(Java.to(opts, "java.lang.String[]")); engine.eval(code); newErr.flush(); return new java.lang.String(baos.toByteArray()); diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/script/trusted/NASHORN-653.js --- a/nashorn/test/script/trusted/NASHORN-653.js Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/test/script/trusted/NASHORN-653.js Wed Jul 05 18:57:52 2017 +0200 @@ -85,8 +85,7 @@ try { // set new standard err System.setErr(newErr); - var strType = Java.type("java.lang.String"); - var engine = fac.getScriptEngine(Java.toJavaArray(opts, strType)); + var engine = fac.getScriptEngine(Java.to(opts, "java.lang.String[]")); engine.eval(code); newErr.flush(); return new java.lang.String(baos.toByteArray()); diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java --- a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Thu May 30 10:58:13 2013 -0700 +++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Wed Jul 05 18:57:52 2017 +0200 @@ -47,7 +47,6 @@ import javax.script.ScriptEngineManager; import javax.script.ScriptException; import javax.script.SimpleScriptContext; -import netscape.javascript.JSObject; import org.testng.Assert; import org.testng.annotations.Test; diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/src/jdk/nashorn/internal/runtime/regexp/JdkRegExpTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/regexp/JdkRegExpTest.java Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,61 @@ +/* + * 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.regexp; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import jdk.nashorn.internal.runtime.ParserException; +import org.testng.annotations.Test; + +/** + * Basic tests for the JDK based RegExp implementation. + * + * @test + * @run testng jdk.nashorn.internal.runtime.regexp.JdkRegExpTest + */ +public class JdkRegExpTest { + + /** + * Compile a regular expression using the JDK implementation + */ + @Test + public void testMatcher() { + RegExp regexp = new RegExpFactory().compile("f(o)o", ""); + RegExpMatcher matcher = regexp.match("foo"); + assertNotNull(matcher); + assertTrue(matcher.search(0)); + assertEquals(matcher.getInput(), "foo"); + assertEquals(matcher.groupCount(), 1); + assertEquals(matcher.group(), "foo"); + assertEquals(matcher.start(), 0); + assertEquals(matcher.end(), 3); + assertEquals(matcher.group(1), "o"); + assertEquals(matcher.start(1), 1); + assertEquals(matcher.end(1), 2); + } +} diff -r a233c04832cf -r a08d0f5b08bc nashorn/test/src/jdk/nashorn/internal/runtime/regexp/joni/JoniTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/regexp/joni/JoniTest.java Wed Jul 05 18:57:52 2017 +0200 @@ -0,0 +1,52 @@ +/* + * 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.regexp.joni; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import org.testng.annotations.Test; + +/** + * Joni coverage tests + * + * @test + * @run testng jdk.nashorn.internal.runtime.regexp.joni.JoniTest + */ +public class JoniTest { + + @Test + public void testDump() { + new Regex("^a{3,}(.*)[z]++\\s\\1x$").dumpTree(); + new Regex("^a{3,}(.*)[z]++\\s\\1x$").dumpByteCode(); + new Regex("(abc){4,}{2,5}").dumpTree(); + new Regex("(abc){4,}{2,5}").dumpByteCode(); + new Regex("aaa|aa|bbbb|ccc").dumpTree(); + new Regex("aaa|aa|bbbb|ccc").dumpByteCode(); + new Regex("(?:ZFVR.(\\d+\\.\\d+))|(?:(?:Sversbk|TenaCnenqvfb|Vprjrnfry).(\\d+\\.\\d+))|(?:Bcren.(\\d+\\.\\d+))|(?:NccyrJroXvg.(\\d+(?:\\.\\d+)?))").dumpTree(); + new Regex("(?:ZFVR.(\\d+\\.\\d+))|(?:(?:Sversbk|TenaCnenqvfb|Vprjrnfry).(\\d+\\.\\d+))|(?:Bcren.(\\d+\\.\\d+))|(?:NccyrJroXvg.(\\d+(?:\\.\\d+)?))").dumpByteCode(); + } +}