Mercurial > people > rkennke > jdk9-shenandoah-final > nashorn
changeset 884:4a47b7cfecdf jdk9-b17
Merge
author | lana |
---|---|
date | Thu, 05 Jun 2014 19:38:45 -0700 |
parents | b9f9529ba775 (current diff) a43d59738770 (diff) |
children | 893c337bc95f d3cc5b704bfe |
files | bin/checkintest.sh bin/verbose_octane.bat bin/verbose_octane.sh src/jdk/nashorn/internal/codegen/Attr.java src/jdk/nashorn/internal/codegen/FinalizeTypes.java src/jdk/nashorn/internal/codegen/RangeAnalyzer.java src/jdk/nashorn/internal/codegen/types/Range.java src/jdk/nashorn/internal/ir/TemporarySymbols.java src/jdk/nashorn/internal/runtime/DebugLogger.java src/jdk/nashorn/internal/runtime/Logging.java test/script/basic/JDK-8010697.js test/script/basic/JDK-8010697.js.EXPECTED test/script/basic/arraysIntKey.js test/script/basic/arraysIntKey.js.EXPECTED test/script/basic/ranges_disabled.js test/script/basic/ranges_disabled.js.EXPECTED test/script/basic/ranges_enabled.js test/script/basic/ranges_enabled.js.EXPECTED test/script/basic/ranges_payload.js test/script/basic/runsunspider-eager.js test/script/basic/runsunspider-lazy.js test/script/basic/runsunspider-lazy.js.EXPECTED test/script/maptests/property_delete.js |
diffstat | 1406 files changed, 40510 insertions(+), 20575 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Wed Jun 04 20:20:44 2014 -0700 +++ b/.hgignore Thu Jun 05 19:38:45 2014 -0700 @@ -13,6 +13,8 @@ *.clazz *.log *.orig +*.rej +*~ genfiles.properties hotspot.log .DS_Store*
--- a/bin/checkintest.sh Wed Jun 04 20:20:44 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,266 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -#best pass rate at test 262 known -TEST262_PASS_AT_LEAST=435 - -RUN_TEST="true" -RUN_TEST262="true" -RUN_NODE="true" -KEEP_OUTPUT="true" -CLEAN_AND_BUILD_NASHORN="true" - -#the stable node version to sync against -NODE_LAST_STABLE=v0.6.18 - -#parse args -for arg in $* -do - if [ $arg = "--no-test" ]; then - RUN_TEST="false" - echo "**** WARNING - you have disabled 'ant test', which is a minimum checkin requirement..." - elif [ $arg = "--no-262" ]; then - RUN_TEST262="false" - elif [ $arg = "--no-node" ]; then - RUN_NODE="false" - elif [ $arg = "--no-build" ]; then - CLEAN_AND_BUILD_NASHORN="false" - elif [ $arg = "--no-logs" ]; then - KEEP_OUTPUT="false" - fi -done - -function lastpart() { - arr=$(echo $1 | tr "/" "\n") - for x in $arr - do - _last=$x - done - echo $_last -} - -function check_installed() { - which $1 >/dev/null - if [ $? -ne 0 ]; then - echo "Error $1 not installed: $?" - exit 2 - fi -} - -check_installed hg -check_installed git -check_installed mv -check_installed git - -PWD=$(pwd); - -while [ -z $NASHORN_ROOT ] -do - if [ -e $PWD/.hg ]; then - NASHORN_ROOT=${PWD} - break - fi - PWD=$(dirname ${PWD}) -done - -echo "Nashorn root detected at ${NASHORN_ROOT}" - -COMMON_ROOT=$(dirname $NASHORN_ROOT) -echo "Common root is ${COMMON_ROOT}" - -echo "Running checkintest..." - -ABSOLUTE_NASHORN_HOME=$COMMON_ROOT/$(lastpart $NASHORN_ROOT) - -if [ $CLEAN_AND_BUILD_NASHORN != "false" ]; then - echo "Cleaning and building nashorn at $ABSOLUTE_NASHORN_HOME/nashorn..." - $(cd $ABSOLUTE_NASHORN_HOME/nashorn; ant clean >/dev/null 2>/dev/null) - $(cd $ABSOLUTE_NASHORN_HOME/nashorn; ant jar >/dev/null 2>/dev/null) - echo "Done." -fi - -function failure_check() { - while read line - do - LINE=$(echo $line | grep "Tests run") - if [ "${LINE}" != "" ]; then - RESULT=$(echo $line | grep "Failures: 0" | grep "Errors: 0") - if [ "${RESULT}" == "" ]; then - TESTNAME=$2 - echo "There were errors in ${TESTNAME} : ${LINE}" - exit 1 - fi - fi - done < $1 -} - -function test() { - TEST_OUTPUT=$ABSOLUTE_NASHORN_HOME/$(mktemp tmp.XXXXX) - echo "Running 'ant test' on nashorn from ${ABSOLUTE_NASHORN_HOME}/nashorn..." - $(cd $ABSOLUTE_NASHORN_HOME/nashorn; ant test >$TEST_OUTPUT) - echo "Done." - - failure_check $TEST_OUTPUT - - echo "**** SUCCESS: 'ant test' successful" - - if [ $KEEP_OUTPUT == "true" ]; then - cp $TEST_OUTPUT ./checkintest.test.log - rm -fr $TEST_OUTPUT - fi -} - -if [ $RUN_TEST != "false" ]; then - test; -fi - -function test262() { - - echo "Running 'ant test262parallel' on nashorn from ${ABSOLUTE_NASHORN_HOME}/nashorn..." - TEST262_OUTPUT=$ABSOLUTE_NASHORN_HOME/$(mktemp tmp.XXXXX) - - echo "Looking for ${ABSOLUTE_NASHORN_HOME}/test/test262..." - - if [ ! -e $ABSOLUTE_NASHORN_HOME/nashorn/test/test262 ]; then - echo "test262 is missing... looking in $COMMON_ROOT..." - if [ ! -e $COMMON_ROOT/test262 ]; then - echo "... not there either... cloning from repo..." - hg clone http://hg.ecmascript.org/tests/test262 $COMMON_ROOT/test262 >/dev/null 2>/dev/null - echo "Done." - fi - echo "Adding soft link ${COMMON_ROOT}/test262 -> ${ABSOLUTE_NASHORN_HOME}/test/test262..." - ln -s $COMMON_ROOT/test262 $ABSOLUTE_NASHORN_HOME/nashorn/test/test262 - echo "Done." - fi - - echo "Ensuring test262 is up to date..." - $(cd $ABSOLUTE_NASHORN_HOME/nashorn/test/test262; hg pull -u >/dev/null 2>/dev/null) - echo "Done." - - echo "Running test262..." - $(cd $ABSOLUTE_NASHORN_HOME/nashorn; ant test262parallel > $TEST262_OUTPUT) - - FAILED=$(cat $TEST262_OUTPUT|grep "Tests run:"| cut -d ' ' -f 15 |tr -cd '"[[:digit:]]') - if [ $FAILED -gt $TEST262_PASS_AT_LEAST ]; then - echo "FAILURE: There are ${FAILED} failures in test262 and can be no more than ${TEST262_PASS_AT_LEAST}" - cp $TEST262_OUTPUT ./checkintest.test262.log - echo "See ./checkintest.test262.log" - echo "Terminating due to error" - exit 1 - elif [ $FAILED -lt $TEST262_PASS_AT_LEAST ]; then - echo "There seem to have been fixes to 262. ${FAILED} < ${TEST262_PASS_AT_LEAST}. Please update limit in bin/checkintest.sh" - fi - - echo "**** SUCCESS: Test262 passed with no more than ${TEST262_PASS_AT_LEAST} failures." - - if [ $KEEP_OUTPUT == "true" ]; then - cp $TEST262_OUTPUT ./checkintest.test262.log - rm -fr $TEST262_OUTPUT - fi -} - -if [ $RUN_TEST262 != "false" ]; then - test262; -fi; - -function testnode() { - TESTNODEJAR_OUTPUT=$ABSOLUTE_NASHORN_HOME/$(mktemp tmp.XXXXX) - - echo "Running node tests..." -#replace node jar properties nashorn with this nashorn - - NODEJAR_PROPERTIES=~/nodejar.properties - - NODE_HOME=$(cat $NODEJAR_PROPERTIES | grep ^node.home | cut -f2 -d=) - NASHORN_HOME=$(cat $NODEJAR_PROPERTIES | grep ^nashorn.home | cut -f2 -d=) - - ABSOLUTE_NODE_HOME=$COMMON_ROOT/$(lastpart $NODE_HOME) - - echo "Writing nodejar.properties..." - - cat > $NODEJAR_PROPERTIES << EOF -node.home=../node -nashorn.home=../$(lastpart $NASHORN_ROOT) -EOF - echo "Done." - echo "Checking node home ${ABSOLUTE_NODE_HOME}..." - - if [ ! -e $ABSOLUTE_NODE_HOME ]; then - echo "Node base dir not found. Cloning node..." - $(cd $COMMON_ROOT; git clone https://github.com/joyent/node.git $(lastpart $NODE_HOME) >/dev/null 2>/dev/null) - echo "Done." - echo "Updating to last stable version ${NODE_LAST_STABLE}..." - $(cd $ABSOLUTE_NODE_HOME; git checkout $NODE_LAST_STABLE >/dev/null 2>/dev/null) - echo "Done." - echo "Running configure..." - $(cd $ABSOLUTE_NODE_HOME; ./configure >/dev/null 2>/dev/null) - echo "Done." - fi - - echo "Ensuring node is built..." -#make sure node is built - $(cd $ABSOLUTE_NODE_HOME; make >/dev/null 2>/dev/null) - echo "Done." - - NODEJAR_HOME=$COMMON_ROOT/nodejar - - if [ ! -e $NODEJAR_HOME ]; then - echo "No node jar home found. cloning from depot..." - $(cd $COMMON_ROOT; hg clone https://hg.kenai.com/hg/nodejs~source nodejar >/dev/null 2>/dev/null) - $(cd $COMMON_ROOT/nodejar; ant >/dev/null) - echo "Done." - echo "Copying node files..." - $(cd $COMMON_ROOT/nodejar; ant copy-node-files >/dev/null 2>/dev/null) - echo "Patching node files..." - $(cd $COMMON_ROOT/nodejar; ant patch-node-files >/dev/null 2>/dev/null) - echo "Done." - fi - - echo "Ensuring node.jar is up to date from source depot..." - $(cd $COMMON_ROOT/nodejar; hg pull -u >/dev/null 2>/dev/null) - echo "Done." - - echo "Installing nashorn..." - $(cd $COMMON_ROOT/nodejar; ant >/dev/null) - echo "Done." - - echo "Running node.jar test..." - $(cd $COMMON_ROOT/nodejar; mvn clean verify >$TESTNODEJAR_OUTPUT) - echo "Done." - - failure_check $TESTNODEJAR_OUTPUT - - echo "**** SUCCESS: Node test successful." - - if [ $KEEP_OUTPUT == "true" ]; then - rm -fr $TESTNODEJAR_OUTPUT - cp $TESTNODEJAR_OUTPUT ./checkintest.nodejar.log - fi -} - -if [ $RUN_NODE != "false" ]; then - testnode; -fi; - -echo "Finished"
--- a/bin/fixwhitespace.sh Wed Jun 04 20:20:44 2014 -0700 +++ b/bin/fixwhitespace.sh Thu Jun 05 19:38:45 2014 -0700 @@ -22,9 +22,16 @@ # questions. # -#convert tabs to spaces -find . -name "*.java" -exec sed -i "" 's/ / /g' {} \; +fix() { + #convert tabs to spaces + find . -name $1 -exec sed -i "" 's/ / /g' {} \; + #remove trailing whitespace + find . -name $1 -exec sed -i "" 's/[ ]*$//' \{} \; +} -#remove trailing whitespace -find . -name "*.java" -exec sed -i "" 's/[ ]*$//' \{} \; - +if [ ! -z $1 ]; then + fix $1; +else + fix "*.java" + fix "*.js" +fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/run_octane.sh Thu Jun 05 19:38:45 2014 -0700 @@ -0,0 +1,51 @@ +#!/bin/bash +# +# Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +LOG="./octane_$(date|sed "s/ /_/g"|sed "s/:/_/g").log" + +run_one() { + sh ../bin/runopt.sh -scripting ../test/script/basic/run-octane.js -- $1 --verbose --iterations 25 | tee -a $LOG +} + +if [ -z $1 ]; then + + run_one "box2d" + run_one "code-load" + run_one "crypto" + run_one "deltablue" + run_one "earley-boyer" + run_one "gbemu" + run_one "mandreel" + run_one "navier-stokes" + run_one "pdfjs" + run_one "raytrace" + run_one "regexp" + run_one "richards" + run_one "splay" + run_one "typescript" + run_one "zlib" + +else + run_one $1 +fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/rundiff.sh Thu Jun 05 19:38:45 2014 -0700 @@ -0,0 +1,25 @@ +#!/bin/sh + +# do two runs of a script, one optimistic and one pessimistic, expect identical outputs +# if not, display and error message and a diff + +which opendiff >/dev/null +RES=$? +if [ $RES = 0 ]; then + DIFFTOOL=opendiff +else + DIFFTOOL=diff +fi + +OPTIMISTIC=out_optimistic +PESSIMISTIC=out_pessimistic +$JAVA_HOME/bin/java -ea -jar ../dist/nashorn.jar ${@} >$PESSIMISTIC +$JAVA_HOME/bin/java -ea -Dnashorn.optimistic -jar ../dist/nashorn.jar ${@} >$OPTIMISTIC + +if ! diff -q $PESSIMISTIC $OPTIMISTIC >/dev/null ; then + echo "Failure! Results are different" + echo "" + $DIFFTOOL $PESSIMISTIC $OPTIMISTIC +else + echo "OK - Results are identical" +fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/runopt.sh Thu Jun 05 19:38:45 2014 -0700 @@ -0,0 +1,110 @@ +#!/bin/sh +# +# Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +########################################################################################### +# This is a helper script to evaluate nashorn with optimistic types +# it produces a flight recording for every run, and uses the best +# known flags for performance for the current configration +########################################################################################### + +# Flags to instrument lambdaform computation, caching, interpretation and compilation +# Default compile threshold for lambdaforms is 30 +#FLAGS="-Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true" + + +# Flags to run trusted tests from the Nashorn test suite +#FLAGS="-Djava.security.manager -Djava.security.policy=../build/nashorn.policy -Dnashorn.debug" + + +# Unique timestamped file name for JFR recordings. For JFR, we also have to +# crank up the stack cutoff depth to 1024, because of ridiculously long lambda form +# stack traces. +# +# It is also recommended that you go into $JAVA_HOME/jre/lib/jfr/default.jfc and +# set the "method-sampling-interval" Normal and Maximum sample time as low as you +# can go (10 ms on most platforms). The default is normally higher. The increased +# sampling overhead is usually negligible for Nashorn runs, but the data is better + +JFR_FILENAME="./nashorn_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr" + + +# Directory where to look for nashorn.jar in a dist folder. The default is "..", assuming +# that we run the script from the make dir +DIR=.. +NASHORN_JAR=$DIR/dist/nashorn.jar + + +# The built Nashorn jar is placed first in the bootclasspath to override the JDK +# nashorn.jar in $JAVA_HOME/jre/lib/ext. Thus, we also need -esa, as assertions in +# nashorn count as system assertions in this configuration + +# Type profiling default level is 111, 222 adds some compile time, but is faster + +$JAVA_HOME/bin/java \ +$FLAGS \ +-ea \ +-esa \ +-Xbootclasspath/p:$NASHORN_JAR \ +-Xms2G -Xmx2G \ +-XX:TypeProfileLevel=222 \ +-cp $CLASSPATH:../build/test/classes/ \ +jdk.nashorn.tools.Shell ${@} + +# Below are flags that may come in handy, but aren't used for default runs + +# Testing out new code optimizations using the generic hotspot "new code" parameter +#-XX:+UnlockDiagnosticVMOptions \ +#-XX:+UseNewCode \ + +# Flight recorder +#-XX:+UnlockCommercialFeatures \ +#-XX:+FlightRecorder \ +#-XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$JFR_FILENAME,stackdepth=1024 \ + + +# Type specialization and math intrinsic replacement should be enabled by default in 8u20 and nine, +# keeping this flag around for experimental reasons. Replace + with - to switch it off +#-XX:+UseTypeSpeculation \ + + +# Same with math intrinsics. They should be enabled by default in 8u20 and 9 +#-XX:+UseMathExactIntrinsics \ + + +# Add -Dnashorn.time to time the compilation phases. +#-Dnashorn.time \ + + +# Add ShowHiddenFrames to get lambda form internals on the stack traces +#-XX:+ShowHiddenFrames \ + + +# Add print optoassembly to get an asm dump. This requires 1) a debug build, not product, +# That tired compilation is switched off, for C2 only output and that the number of +# compiler threads is set to 1 for determinsm. +#-XX:+PrintOptoAssembly -XX:-TieredCompilation -XX:CICompilerCount=1 \ + +# Tier compile threasholds. Default value is 10. (1-100 is useful for experiments) +# -XX:IncreaseFirstTierCompileThresholdAt=XX +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/runopt_noassert.sh Thu Jun 05 19:38:45 2014 -0700 @@ -0,0 +1,28 @@ +#!/bin/sh + +#FLAGS="-Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true" + +FILENAME="./optimistic_noassert_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr" + +DIR=.. +NASHORN_JAR=$DIR/dist/nashorn.jar + +$JAVA_HOME/bin/java \ +$FLAGS \ +-Xbootclasspath/p:$NASHORN_JAR \ +-Xms2G -Xmx2G \ +-XX:+UnlockCommercialFeatures \ +-XX:+FlightRecorder \ +-XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$FILENAME,stackdepth=1024 \ +-XX:TypeProfileLevel=222 \ +-XX:+UnlockExperimentalVMOptions \ +-XX:+UseTypeSpeculation \ +-XX:+UseMathExactIntrinsics \ +-XX:+UnlockDiagnosticVMOptions \ +-cp $CLASSPATH:../build/test/classes/ \ +jdk.nashorn.tools.Shell ${@} + +#-XX:+ShowHiddenFrames \ +#-XX:+PrintOptoAssembly \ +#-XX:-TieredCompilation \ +#-XX:CICompilerCount=1 \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/runopt_nojfr.sh Thu Jun 05 19:38:45 2014 -0700 @@ -0,0 +1,27 @@ +#!/bin/sh + +#FLAGS="-Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true" + +DIR=.. +NASHORN_JAR=$DIR/dist/nashorn.jar + +$JAVA_HOME/bin/java \ +$FLAGS \ +-ea \ +-esa \ +-Xbootclasspath/p:$NASHORN_JAR \ +-Xms2G -Xmx2G \ +-XX:+UnlockCommercialFeatures \ +-XX:TypeProfileLevel=222 \ +-XX:+UnlockExperimentalVMOptions \ +-XX:+UseTypeSpeculation \ +-XX:+UseMathExactIntrinsics \ +-XX:+UnlockDiagnosticVMOptions \ +-XX:+UseNewCode \ +-cp $CLASSPATH:../build/test/classes/ \ +jdk.nashorn.tools.Shell ${@} + +#-XX:+ShowHiddenFrames \ +#-XX:+PrintOptoAssembly \ +#-XX:-TieredCompilation \ +#-XX:CICompilerCount=1 \
--- a/bin/verbose_octane.bat Wed Jun 04 20:20:44 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -rem -rem Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. -rem DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -rem -rem This code is free software; you can redistribute it and/or modify it -rem under the terms of the GNU General Public License version 2 only, as -rem published by the Free Software Foundation. -rem -rem This code is distributed in the hope that it will be useful, but WITHOUT -rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -rem version 2 for more details (a copy is included in the LICENSE file that -rem accompanied this code). -rem -rem You should have received a copy of the GNU General Public License version -rem 2 along with this work; if not, write to the Free Software Foundation, -rem Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -rem -rem Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -rem or visit www.oracle.com if you need additional information or have any -rem questions. -rem -@echo off - -if "%JAVA_HOME%" neq "" ( - call :run "%JAVA_HOME%/bin/java" -) else ( - call :run java -) -goto :EOF - -:run -setlocal -set NASHORN_JAR=dist/nashorn.jar -set JVM_FLAGS=-Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -jar %NASHORN_JAR% -set JVM_FLAGS7=-Xbootclasspath/p:%NASHORN_JAR% %JVM_FLAGS% -set OCTANE_ARGS=--verbose --iterations 7 - -%1 -fullversion 2>&1 | findstr /L /C:"version ""1.7" -if %errorlevel% equ 0 ( - set CMD=%1 %JVM_FLAGS7% -) else ( - %1 -fullversion - set CMD=%1 %JVM_FLAGS% -) - -%CMD% test/script/basic/run-octane.js -- test/script/external/octane/box2d.js %OCTANE_ARGS% -%CMD% test/script/basic/run-octane.js -- test/script/external/octane/code-load.js %OCTANE_ARGS% -%CMD% test/script/basic/run-octane.js -- test/script/external/octane/crypto.js %OCTANE_ARGS% -%CMD% test/script/basic/run-octane.js -- test/script/external/octane/deltablue.js %OCTANE_ARGS% -%CMD% test/script/basic/run-octane.js -- test/script/external/octane/gbemu.js %OCTANE_ARGS% -%CMD% test/script/basic/run-octane.js -- test/script/external/octane/navier-stokes.js %OCTANE_ARGS% -%CMD% test/script/basic/run-octane.js -- test/script/external/octane/pdfjs.js %OCTANE_ARGS% -%CMD% test/script/basic/run-octane.js -- test/script/external/octane/raytrace.js %OCTANE_ARGS% -%CMD% test/script/basic/run-octane.js -- test/script/external/octane/regexp.js %OCTANE_ARGS% -%CMD% test/script/basic/run-octane.js -- test/script/external/octane/richards.js %OCTANE_ARGS% -%CMD% test/script/basic/run-octane.js -- test/script/external/octane/splay.js %OCTANE_ARGS% -endlocal -goto :EOF
--- a/bin/verbose_octane.sh Wed Jun 04 20:20:44 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -#!/bin/bash -# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -ITERS=$1 -if [ -z $ITERS ]; then - ITERS=7 -fi -NASHORN_JAR=dist/nashorn.jar -JVM_FLAGS="-Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+UnlockDiagnosticVMOptions -Dnashorn.unstable.relink.threshold=8 -Xms2G -Xmx2G -XX:+TieredCompilation -server -jar ${NASHORN_JAR}" -JVM_FLAGS7="-Xbootclasspath/p:${NASHORN_JAR} ${JVM_FLAGS}" -OCTANE_ARGS="--verbose --iterations ${ITERS}" - -BENCHMARKS=( "box2d.js" "code-load.js" "crypto.js" "deltablue.js" "earley-boyer.js" "gbemu.js" "navier-stokes.js" "pdfjs.js" "raytrace.js" "regexp.js" "richards.js" "splay.js" ) -# TODO mandreel.js has metaspace issues - -if [ ! -z $JAVA7_HOME ]; then - echo "running ${ITERS} iterations with java7 using JAVA_HOME=${JAVA7_HOME}..." - for BENCHMARK in "${BENCHMARKS[@]}" - do - CMD="${JAVA7_HOME}/bin/java ${JVM_FLAGS} test/script/basic/run-octane.js -- test/script/external/octane/${BENCHMARK} ${OCTANE_ARGS}" - $CMD - done -else - echo "no JAVA7_HOME set. skipping java7" -fi - -if [ ! -z $JAVA8_HOME ]; then - echo "running ${ITERS} iterations with java8 using JAVA_HOME=${JAVA8_HOME}..." - for BENCHMARK in "${BENCHMARKS[@]}" - do - CMD="${JAVA8_HOME}/bin/java ${JVM_FLAGS} test/script/basic/run-octane.js -- test/script/external/octane/${BENCHMARK} ${OCTANE_ARGS}" - $CMD - done -else - echo "no JAVA8_HOME set." -fi - -echo "Done"
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java Wed Jun 04 20:20:44 2014 -0700 +++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java Thu Jun 05 19:38:45 2014 -0700 @@ -31,29 +31,29 @@ import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKEVIRTUAL; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.ACCESSORPROPERTY_CREATE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.ACCESSORPROPERTY_CREATE_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.ACCESSORPROPERTY_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.ARRAYLIST_INIT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.ARRAYLIST_TYPE; import static jdk.nashorn.internal.tools.nasgen.StringConstants.CLINIT; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTIONS_EMPTY_LIST; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTIONS_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTION_ADD; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTION_ADD_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTION_TYPE; import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.GETTER_PREFIX; import static jdk.nashorn.internal.tools.nasgen.StringConstants.GET_CLASS_NAME; import static jdk.nashorn.internal.tools.nasgen.StringConstants.GET_CLASS_NAME_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.ACCESSORPROPERTY_CREATE; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.ACCESSORPROPERTY_CREATE_DESC; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.ACCESSORPROPERTY_TYPE; import static jdk.nashorn.internal.tools.nasgen.StringConstants.LIST_DESC; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.ARRAYLIST_TYPE; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.ARRAYLIST_INIT_DESC; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTION_TYPE; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTION_ADD; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTION_ADD_DESC; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTIONS_TYPE; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTIONS_EMPTY_LIST; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_FIELD_NAME; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_NEWMAP; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_NEWMAP_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_TYPE; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION; import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC;
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java Wed Jun 04 20:20:44 2014 -0700 +++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java Thu Jun 05 19:38:45 2014 -0700 @@ -32,9 +32,9 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.CONSTRUCTOR_SUFFIX; import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_FIELD_NAME; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_TYPE;
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java Wed Jun 04 20:20:44 2014 -0700 +++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java Thu Jun 05 19:38:45 2014 -0700 @@ -319,7 +319,7 @@ break; case FUNCTION: { final Type returnType = Type.getReturnType(javaDesc); - if (!isValidJSType(returnType)) { + if (!(isValidJSType(returnType) || Type.VOID_TYPE == returnType)) { error("return value of a @Function method should be a valid JS type, found " + returnType); } final Type[] argTypes = Type.getArgumentTypes(javaDesc); @@ -351,7 +351,7 @@ break; case SPECIALIZED_FUNCTION: { final Type returnType = Type.getReturnType(javaDesc); - if (!isValidJSType(returnType)) { + if (!(isValidJSType(returnType) || Type.VOID_TYPE == returnType)) { error("return value of a @SpecializedFunction method should be a valid JS type, found " + returnType); } final Type[] argTypes = Type.getArgumentTypes(javaDesc); @@ -371,9 +371,8 @@ error("first argument of a @Getter method should be of Object type, found: " + argTypes[0]); } - final Type returnType = Type.getReturnType(javaDesc); - if (!isJavaLangObject(returnType)) { - error("return type of a @Getter method should be Object, found: " + javaDesc); + if (Type.getReturnType(javaDesc).equals(Type.VOID_TYPE)) { + error("return type of getter should not be void"); } } break;
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java Wed Jun 04 20:20:44 2014 -0700 +++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java Thu Jun 05 19:38:45 2014 -0700 @@ -413,7 +413,8 @@ super.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", - "(Ljava/lang/String;)V", false); + "(Ljava/lang/String;)V", + false); } // print the object on the top of the stack @@ -426,6 +427,7 @@ super.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", - "(Ljava/lang/Object;)V", false); + "(Ljava/lang/Object;)V", + false); } }
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java Wed Jun 04 20:20:44 2014 -0700 +++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java Thu Jun 05 19:38:45 2014 -0700 @@ -31,9 +31,9 @@ import static jdk.internal.org.objectweb.asm.Opcodes.V1_7; import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_FIELD_NAME; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_TYPE; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPE_SUFFIX; import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC;
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java Wed Jun 04 20:20:44 2014 -0700 +++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java Thu Jun 05 19:38:45 2014 -0700 @@ -26,9 +26,8 @@ package jdk.nashorn.internal.tools.nasgen; import java.lang.invoke.MethodHandle; -import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.Collection; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import jdk.internal.org.objectweb.asm.Type;
--- a/docs/DEVELOPER_README Wed Jun 04 20:20:44 2014 -0700 +++ b/docs/DEVELOPER_README Thu Jun 05 19:38:45 2014 -0700 @@ -737,26 +737,6 @@ the JRuby project. The default value for this flag is "joni" -SYSTEM PROPERTY: -Dnashorn.time - -This enables timers for various phases of script compilation. The timers -will be dumped when the Nashorn process exits. We see a percentage value -of how much time was spent not executing bytecode (i.e. compilation and -internal tasks) at the end of the report. - -Here is an example: - -[JavaScript Parsing] 61 ms -[Constant Folding] 11 ms -[Control Flow Lowering] 26 ms -[Type Attribution] 81 ms -[Range Analysis] 0 ms -[Code Splitting] 29 ms -[Type Finalization] 19 ms -[Bytecode Generation] 189 ms -[Code Installation] 7 ms -Total runtime: 508 ms (Non-runtime: 423 ms [83%]) - =============== 2. The loggers. =============== @@ -887,6 +867,34 @@ (Object in the normal case, unless running with the dual field representation) +* time + +This enables timers for various phases of script compilation. The timers +will be dumped when the Nashorn process exits. We see a percentage value +of how much time was spent not executing bytecode (i.e. compilation and +internal tasks) at the end of the report. + +A finer level than "info" will show individual compilation timings as they +happen. + +Here is an example: + +[time] Accumulated complation phase Timings: +[time] +[time] 'JavaScript Parsing' 1076 ms +[time] 'Constant Folding' 159 ms +[time] 'Control Flow Lowering' 303 ms +[time] 'Program Point Calculation' 282 ms +[time] 'Builtin Replacement' 71 ms +[time] 'Code Splitting' 670 ms +[time] 'Symbol Assignment' 474 ms +[time] 'Scope Depth Computation' 249 ms +[time] 'Optimistic Type Assignment' 186 ms +[time] 'Local Variable Type Calculation' 526 ms +[time] 'Bytecode Generation' 5177 ms +[time] 'Class Installation' 1854 ms +[time] +[time] Total runtime: 11994 ms (Non-runtime: 11027 ms [91%]) ======================= 3. Undocumented options @@ -914,11 +922,10 @@ -cp, -classpath (-cp path. Specify where to find user class files.) - -co, --compile-only (Compile script without running. Exit after compilation) + -co, --compile-only (Compile without running.) param: [true|false] default: false - -d, --dump-debug-dir (specify a destination directory to dump class files. - This must be combined with the --compile-only option to work) + -d, --dump-debug-dir (specify a destination directory to dump class files.) param: <path> --debug-lines (Generate line number table in .class files.) @@ -954,10 +961,6 @@ -h, -help (Print help for command line flags.) param: [true|false] default: false - --lazy-compilation (EXPERIMENTAL: Use lazy code generation strategies - do not compile - the entire script at once.) - param: [true|false] default: false - --loader-per-compile (Create a new class loader per compile.) param: [true|false] default: true @@ -965,16 +968,16 @@ param: <locale> default: en-US --log (Enable logging of a given level for a given number of sub systems. - [for example: --log=fields:finest,codegen:info]) + [for example: --log=fields:finest,codegen:info].) param: <module:level>,* - -nj, --no-java (No Java support) + -nj, --no-java (Disable Java support.) param: [true|false] default: false - -nse, --no-syntax-extensions (No non-standard syntax extensions) + -nse, --no-syntax-extensions (Disallow non-standard syntax extensions.) param: [true|false] default: false - -nta, --no-typed-arrays (No Typed arrays support) + -nta, --no-typed-arrays (Disable typed arrays support.) param: [true|false] default: false --parse-only (Parse without compiling.) @@ -983,13 +986,15 @@ --print-ast (Print abstract syntax tree.) param: [true|false] default: false - --print-code (Print bytecode.) - param: [true|false] default: false + -pc, --print-code (Print generated bytecode. If a directory is specified, nothing will + be dumped to stderr. Also, in that case, .dot files will be generated + for all functions or for the function with the specified name only.) + param: [dir:<output-dir>,function:<name>] --print-lower-ast (Print lowered abstract syntax tree.) param: [true|false] default: false - --print-lower-parse (Print the parse tree after lowering.) + -plp, --print-lower-parse (Print the parse tree after lowering.) param: [true|false] default: false --print-mem-usage (Print memory usage of IR after each compile stage.) @@ -998,7 +1003,7 @@ --print-no-newline (Print function will not print new line char.) param: [true|false] default: false - --print-parse (Print the parse tree.) + -pp, --print-parse (Print the parse tree.) param: [true|false] default: false --print-symbols (Print the symbol table.) @@ -1007,21 +1012,13 @@ -pcs, --profile-callsites (Dump callsite profile data.) param: [true|false] default: false - --range-analysis (EXPERIMENTAL: Do range analysis using known compile time types, - and try to narrow number types) - param: [true|false] default: false - -scripting (Enable scripting features.) param: [true|false] default: false - --specialize-calls (EXPERIMENTAL: Specialize all or a set of method according - to callsite parameter types) - param: [=function_1,...,function_n] - - --stderr (Redirect stderr to a filename or to another tty, e.g. stdout) + --stderr (Redirect stderr to a filename or to another tty, e.g. stdout.) param: <output console> - --stdout (Redirect stdout to a filename or to another tty, e.g. stderr) + --stdout (Redirect stdout to a filename or to another tty, e.g. stderr.) param: <output console> -strict (Run scripts in strict mode.) @@ -1031,7 +1028,7 @@ param: <timezone> default: Europe/Stockholm -tcs, --trace-callsites (Enable callsite trace mode. Options are: miss [trace callsite misses] - enterexit [trace callsite enter/exit], objects [print object properties]) + enterexit [trace callsite enter/exit], objects [print object properties].) param: [=[option,]*] --verify-code (Verify byte code before running.)
--- a/make/build-benchmark.xml Wed Jun 04 20:20:44 2014 -0700 +++ b/make/build-benchmark.xml Thu Jun 05 19:38:45 2014 -0700 @@ -1,384 +1,333 @@ <?xml version="1.0" encoding="UTF-8"?> + <!-- - 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. + Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + + This code is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License version 2 only, as + published by the Free Software Foundation. + + This code is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + version 2 for more details (a copy is included in the LICENSE file that + accompanied this code). + + You should have received a copy of the GNU General Public License version + 2 along with this work; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + + Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + or visit www.oracle.com if you need additional information or have any + questions. --> -<project name="nashorn-benchmarks" default="all" basedir=".."> + + +<project + name="nashorn-benchmarks" + default="all" + basedir=".." + xmlns:if="ant:if"> - <target name="octane-init" depends="jar"> - <property name="octane-tests" value="box2d code-load crypto deltablue earley-boyer gbemu navier-stokes pdfjs raytrace regexp richards splay"/> + <!-- + Below are the octane benchmarks that should be run. + The ones that are excluded, as Nashorn currently has + some issues with them (functionality or performance) + are commented out + --> + + <!-- box2d --> + <target name="octane-box2d" depends="octane-box2d-nashorn"/> + <target name="octane-box2d-nashorn" depends="jar"> + <run-one cond="octane.benchmark.box2d" runtime="nashorn"/> </target> - - <!-- ignore benchmarks where rhino crashes --> - <target name="octane-init-rhino" depends="jar"> - <property name="octane-tests" value="box2d code-load crypto deltablue earley-boyer gbemu navier-stokes raytrace regexp richards splay"/> + <target name="octane-box2d-v8" depends="jar"> + <run-one cond="octane.benchmark.box2d" runtime="v8"/> + </target> + <target name="octane-box2d-rhino" depends="jar"> + <run-one cond="octane.benchmark.box2d" runtime="rhino"/> </target> - <!-- box2d --> - <target name="octane-box2d" depends="jar"> - <antcall target="run-octane"> - <param name="octane-tests" value="box2d"/> - </antcall> + <!-- code-load --> + <target name="octane-code-load" depends="octane-code-load-nashorn"/> + <target name="octane-code-load-nashorn" depends="jar"> + <run-one cond="octane.benchmark.code-load" runtime="nashorn"/> + </target> + <target name="octane-code-load-v8" depends="jar"> + <run-one cond="octane.benchmark.code-load" runtime="v8"/> + </target> + <target name="octane-code-load-rhino" depends="jar"> + <run-one cond="octane.benchmark.code-load" runtime="rhino"/> </target> - <target name="octane-box2d-v8" depends="jar"> - <antcall target="run-octane-v8"> - <param name="octane-tests" value="box2d"/> - </antcall> + <!-- crypto --> + <target name="octane-crypto" depends="octane-crypto-nashorn"/> + <target name="octane-crypto-nashorn" depends="jar"> + <run-one cond="octane.benchmark.crypto" runtime="nashorn"/> + </target> + <target name="octane-crypto-v8" depends="jar"> + <run-one cond="octane.benchmark.crypto" runtime="v8"/> + </target> + <target name="octane-crypto-rhino" depends="jar"> + <run-one cond="octane.benchmark.crypto" runtime="rhino"/> </target> - <target name="octane-box2d-rhino" depends="jar"> - <antcall target="run-octane-rhino"> - <param name="octane-tests" value="box2d"/> - </antcall> + <!-- deltablue --> + <target name="octane-deltablue" depends="octane-deltablue-nashorn"/> + <target name="octane-deltablue-nashorn" depends="jar"> + <run-one cond="octane.benchmark.deltablue" runtime="nashorn"/> </target> - - - <!-- code-load --> - <target name="octane-code-load" depends="jar"> - <antcall target="run-octane"> - <param name="octane-tests" value="code-load"/> - </antcall> + <target name="octane-deltablue-v8" depends="jar"> + <run-one cond="octane.benchmark.deltablue" runtime="v8"/> + </target> + <target name="octane-deltablue-rhino" depends="jar"> + <run-one cond="octane.benchmark.deltablue" runtime="rhino"/> </target> - <target name="octane-code-load-v8" depends="jar"> - <antcall target="run-octane-v8"> - <param name="octane-tests" value="code-load"/> - </antcall> + <!-- earley-boyer --> + <target name="octane-earley-boyer" depends="octane-earley-boyer-nashorn"/> + <target name="octane-earley-boyer-nashorn" depends="jar"> + <run-one cond="octane.benchmark.earley-boyer" runtime="nashorn"/> + </target> + <target name="octane-earley-boyer-v8" depends="jar"> + <run-one cond="octane.benchmark.earley-boyer" runtime="v8"/> + </target> + <target name="octane-earley-boyer-rhino" depends="jar"> + <run-one cond="octane.benchmark.earley-boyer" runtime="rhino"/> </target> - - <target name="octane-code-load-rhino" depends="jar"> - <antcall target="run-octane-rhino"> - <param name="octane-tests" value="code-load"/> - </antcall> + + <!-- gbemu --> + <target name="octane-gbemu" depends="octane-gbemu-nashorn"/> + <target name="octane-gbemu-nashorn" depends="jar"> + <run-one cond="octane.benchmark.gbemu" runtime="nashorn"/> + </target> + <target name="octane-gbemu-v8" depends="jar"> + <run-one cond="octane.benchmark.gbemu" runtime="v8"/> + </target> + <target name="octane-gbemu-rhino" depends="jar"> + <run-one cond="octane.benchmark.gbemu" runtime="rhino"/> </target> - - <!-- crypto --> - <target name="octane-crypto" depends="jar"> - <antcall target="run-octane"> - <param name="octane-tests" value="crypto"/> - </antcall> + <!-- mandreel --> + <target name="octane-mandreel" depends="octane-mandreel-nashorn"/> + <target name="octane-mandreel-nashorn" depends="jar"> + <run-one cond="octane.benchmark.mandreel" runtime="nashorn"/> + </target> + <target name="octane-mandreel-v8" depends="jar"> + <run-one cond="octane.benchmark.mandreel" runtime="v8"/> + </target> + <target name="octane-mandreel-rhino" depends="jar"> + <run-one cond="octane.benchmark.mandreel" runtime="rhino"/> </target> - <target name="octane-crypto-v8" depends="jar"> - <antcall target="run-octane-v8"> - <param name="octane-tests" value="crypto"/> - </antcall> + <!-- navier-stokes --> + <target name="octane-navier-stokes" depends="octane-navier-stokes-nashorn"/> + <target name="octane-navier-stokes-nashorn" depends="jar"> + <run-one cond="octane.benchmark.navier-stokes" runtime="nashorn"/> + </target> + <target name="octane-navier-stokes-v8" depends="jar"> + <run-one cond="octane.benchmark.navier-stokes" runtime="v8"/> + </target> + <target name="octane-navier-stokes-rhino" depends="jar"> + <run-one cond="octane.benchmark.navier-stokes" runtime="rhino"/> </target> - <target name="octane-crypto-rhino" depends="jar"> - <antcall target="run-octane-rhino"> - <param name="octane-tests" value="crypto"/> - </antcall> + <!-- pdfjs --> + <target name="octane-pdfjs" depends="octane-pdfjs-nashorn"/> + <target name="octane-pdfjs-nashorn" depends="jar"> + <run-one cond="octane.benchmark.pdfjs" runtime="nashorn"/> + </target> + <target name="octane-pdfjs-v8" depends="jar"> + <run-one cond="octane.benchmark.pdfjs" runtime="v8"/> + </target> + <target name="octane-pdfjs-rhino" depends="jar"> + <run-one cond="octane.benchmark.pdfjs" runtime="rhino"/> </target> - - <!-- deltablue --> - <target name="octane-deltablue" depends="jar"> - <antcall target="run-octane"> - <param name="octane-tests" value="deltablue"/> - </antcall> + <!-- raytrace --> + <target name="octane-raytrace" depends="octane-raytrace-nashorn"/> + <target name="octane-raytrace-nashorn" depends="jar"> + <run-one cond="octane.benchmark.raytrace" runtime="nashorn"/> </target> - - <target name="octane-deltablue-v8" depends="jar"> - <antcall target="run-octane-v8"> - <param name="octane-tests" value="deltablue"/> - </antcall> + <target name="octane-raytrace-v8" depends="jar"> + <run-one cond="octane.benchmark.raytrace" runtime="v8"/> + </target> + <target name="octane-raytrace-rhino" depends="jar"> + <run-one cond="octane.benchmark.raytrace" runtime="rhino"/> </target> - <target name="octane-deltablue-rhino" depends="jar"> - <antcall target="run-octane-rhino"> - <param name="octane-tests" value="deltablue"/> - </antcall> + <!-- regexp --> + <target name="octane-regexp" depends="octane-regexp-nashorn"/> + <target name="octane-regexp-nashorn" depends="jar"> + <run-one cond="octane.benchmark.regexp" runtime="nashorn"/> + </target> + <target name="octane-regexp-v8" depends="jar"> + <run-one cond="octane.benchmark.regexp" runtime="v8"/> + </target> + <target name="octane-regexp-rhino" depends="jar"> + <run-one cond="octane.benchmark.regexp" runtime="rhino"/> </target> - - <!-- earley-boyer --> - <target name="octane-earley-boyer" depends="jar"> - <antcall target="run-octane"> - <param name="octane-tests" value="earley-boyer"/> - </antcall> + <!-- richards --> + <target name="octane-richards" depends="octane-richards-nashorn"/> + <target name="octane-richards-nashorn" depends="jar"> + <run-one cond="octane.benchmark.richards" runtime="nashorn"/> + </target> + <target name="octane-richards-v8" depends="jar"> + <run-one cond="octane.benchmark.richards" runtime="v8"/> + </target> + <target name="octane-richards-rhino" depends="jar"> + <run-one cond="octane.benchmark.richards" runtime="rhino"/> </target> - <target name="octane-earley-boyer-v8" depends="jar"> - <antcall target="run-octane-v8"> - <param name="octane-tests" value="earley-boyer"/> - </antcall> + <!-- splay --> + <target name="octane-splay" depends="octane-splay-nashorn"/> + <target name="octane-splay-nashorn" depends="jar"> + <run-one cond="octane.benchmark.splay" runtime="nashorn"/> </target> - - <target name="octane-earley-boyer-rhino" depends="jar"> - <antcall target="run-octane-rhino"> - <param name="octane-tests" value="earley-boyer"/> - </antcall> + <target name="octane-splay-v8" depends="jar"> + <run-one cond="octane.benchmark.splay" runtime="v8"/> + </target> + <target name="octane-splay-rhino" depends="jar"> + <run-one cond="octane.benchmark.splay" runtime="rhino"/> </target> - - <!-- gbemu --> - <target name="octane-gbemu" depends="jar"> - <antcall target="run-octane"> - <param name="octane-tests" value="gbemu"/> - </antcall> + <!-- typescript --> + <target name="octane-typescript" depends="octane-typescript-nashorn"/> + <target name="octane-typescript-nashorn" depends="jar"> + <run-one cond="octane.benchmark.typescript" runtime="nashorn"/> + </target> + <target name="octane-typescript-v8" depends="jar"> + <run-one cond="octane.benchmark.typescript" runtime="v8"/> + </target> + <target name="octane-typescript-rhino" depends="jar"> + <run-one cond="octane.benchmark.typescript" runtime="rhino"/> </target> - <target name="octane-gbemu-v8" depends="jar"> - <antcall target="run-octane-v8"> - <param name="octane-tests" value="gbemu"/> - </antcall> + <!-- zlib --> + <target name="octane-zlib" depends="octane-zlib-nashorn"/> + <target name="octane-zlib-nashorn" depends="jar"> + <run-one cond="octane.benchmark.zlib" runtime="nashorn"/> </target> - - <target name="octane-gbemu-rhino" depends="jar"> - <antcall target="run-octane-rhino"> - <param name="octane-tests" value="gbemu"/> - </antcall> + <target name="octane-zlib-v8" depends="jar"> + <run-one cond="octane.benchmark.zlib" runtime="v8"/> + </target> + <target name="octane-zlib-rhino" depends="jar"> + <run-one cond="octane.benchmark.zlib" runtime="rhino"/> </target> + <!-- + Benchmark runners for one or more benchmarks, single + or multiple process + --> - <!-- mandreel --> - <target name="octane-mandreel" depends="jar"> - <antcall target="run-octane"> - <param name="octane-tests" value="mandreel"/> - </antcall> + <target name="octane-process-separate" if="${octane-test-sys-prop.separate.process}"> + <echo message="Running each benchmark in separate processes, starting new JVMs for each."/> + <script language="javascript"><![CDATA[ + var props = []; + + for (var prop in project.getProperties()) { + if (prop.startsWith("octane.benchmark.")) { + props.push(prop); + } + } + + //sort benchmark props in alphabetical order by name + props.sort(function(a, b) { + if (a < b) { + return -1; + } else if (a > b) { + return 1; + } else { + return 0; + } + }); + + var runtime = project.getProperty("runtime"); + + for (var i in props) { + var task = project.createTask("run-one"); + // workaround for https://issues.apache.org/bugzilla/show_bug.cgi?id=53831, still not fixed + if (task.getOwningTarget() == null) { + task.setOwningTarget(self.getOwningTarget()); + } + var prop = props[i]; + task.setDynamicAttribute("cond", prop); + task.setDynamicAttribute("runtime", runtime); + task.perform(); + } + ]]></script> </target> - <target name="octane-mandreel-v8" depends="jar"> - <antcall target="run-octane-v8"> - <param name="octane-tests" value="mandreel"/> - </antcall> - </target> - - <target name="octane-mandreel-rhino" depends="jar"> - <antcall target="run-octane-rhino"> - <param name="octane-tests" value="mandreel"/> - </antcall> - </target> - - - <!-- navier-stokes --> - <target name="octane-navier-stokes" depends="jar"> - <antcall target="run-octane"> - <param name="octane-tests" value="navier-stokes"/> + <target name="octane-process-single" unless="${octane-test-sys-prop.separate.process}"> + <echo message="Running all benchmarks in the same process."/> + <pathconvert property="octane.benchmarks" pathsep=" "> + <propertyset> + <propertyref prefix="octane.benchmark."/> + </propertyset> + </pathconvert> + <antcall target="run-octane${runtime}"> + <param name="octane-tests" value="${octane.benchmarks}"/> </antcall> </target> - <target name="octane-navier-stokes-v8" depends="jar"> - <antcall target="run-octane-v8"> - <param name="octane-tests" value="navier-stokes"/> - </antcall> - </target> - - <target name="octane-navier-stokes-rhino" depends="jar"> - <antcall target="run-octane-rhino"> - <param name="octane-tests" value="navier-stokes"/> - </antcall> - </target> - - - <!-- pdfjs --> - <target name="octane-pdfjs" depends="jar"> - <antcall target="run-octane"> - <param name="octane-tests" value="pdfjs"/> - </antcall> - </target> - - <target name="octane-pdfjs-v8" depends="jar"> - <antcall target="run-octane-v8"> - <param name="octane-tests" value="pdfjs"/> - </antcall> - </target> - - <target name="octane-pdfjs-rhino" depends="jar"> - <antcall target="run-octane-rhino"> - <param name="octane-tests" value="pdfjs"/> - </antcall> - </target> - - - <!-- raytrace --> - <target name="octane-raytrace" depends="jar"> - <antcall target="run-octane"> - <param name="octane-tests" value="raytrace"/> - </antcall> - </target> - - <target name="octane-raytrace-v8" depends="jar"> - <antcall target="run-octane-v8"> - <param name="octane-tests" value="raytrace"/> - </antcall> - </target> - - <target name="octane-raytrace-rhino" depends="jar"> - <antcall target="run-octane-rhino"> - <param name="octane-tests" value="raytrace"/> - </antcall> - </target> - - - <!-- regexp --> - <target name="octane-regexp" depends="jar"> - <antcall target="run-octane"> - <param name="octane-tests" value="regexp"/> - </antcall> - </target> - - <target name="octane-regexp-v8" depends="jar"> - <antcall target="run-octane-v8"> - <param name="octane-tests" value="regexp"/> - </antcall> - </target> - - <target name="octane-regexp-rhino" depends="jar"> - <antcall target="run-octane-rhino"> - <param name="octane-tests" value="regexp"/> - </antcall> - </target> - - - <!-- richards --> - <target name="octane-richards" depends="jar"> - <antcall target="run-octane"> - <param name="octane-tests" value="richards"/> - </antcall> - </target> - - <target name="octane-richards-v8" depends="jar"> - <antcall target="run-octane-v8"> - <param name="octane-tests" value="richards"/> - </antcall> + <!-- + run 'octane' in single or separate processes based on config + This uses nashorn as the default runtime + --> + <target name="octane-nashorn" depends="jar"> + <property name="runtime" value="nashorn"/> + <antcall target="octane-process-separate"/> + <antcall target="octane-process-single"/> </target> - <target name="octane-richards-rhino" depends="jar"> - <antcall target="run-octane-rhino"> - <param name="octane-tests" value="richards"/> - </antcall> - </target> - - - <!-- splay --> - <target name="octane-splay" depends="jar"> - <antcall target="run-octane"> - <param name="octane-tests" value="splay"/> - </antcall> - </target> - - <target name="octane-splay-v8" depends="jar"> - <antcall target="run-octane-v8"> - <param name="octane-tests" value="splay"/> - </antcall> - </target> - - <target name="octane-splay-rhino" depends="jar"> - <antcall target="run-octane-rhino"> - <param name="octane-tests" value="splay"/> - </antcall> - </target> - - <!-- splay --> - <target name="octane-typescript" depends="jar"> - <antcall target="run-octane"> - <param name="octane-tests" value="typescript"/> - </antcall> - </target> - - <target name="octane-typescript-v8" depends="jar"> - <antcall target="run-octane-v8"> - <param name="octane-typescript" value="typescript"/> - </antcall> - </target> - - <target name="octane-typescript-rhino" depends="jar"> - <antcall target="run-octane-rhino"> - <param name="octane-tests" value="typescript"/> - </antcall> - </target> - - <!-- zlib --> - <target name="octane-zlib" depends="jar"> - <antcall target="run-octane"> - <param name="octane-tests" value="zlib"/> - </antcall> - </target> - - <target name="octane-zlib-v8" depends="jar"> - <antcall target="run-octane-v8"> - <param name="octane-typescript" value="zlib"/> - </antcall> - </target> - - <target name="octane-zlib-rhino" depends="jar"> - <antcall target="run-octane-rhino"> - <param name="octane-tests" value="zlib"/> - </antcall> - </target> - - <!-- run octane benchmarks in a single process --> - <target name="octane-single-process" depends="octane-init"> - <antcall target="run-octane"/> - </target> - - <!-- zlib excluded due to missing implementation of 'read' --> - <target name="octane-separate-process" depends= - "octane-box2d, octane-code-load, octane-crypto, - octane-deltablue, octane-earley-boyer, octane-gbemu, - octane-mandreel, octane-navier-stokes, octane-pdfjs, - octane-raytrace, octane-regexp, octane-richards, - octane-splay, octane-typescript"/> - - <target name="--single-process" unless="${octane-test-sys-prop.separate.process}"> - <antcall target="octane-single-process"/> - </target> - <target name="--separate-process" if="${octane-test-sys-prop.separate.process}"> - <antcall target="octane-separate-process"/> - </target> - - <!-- run 'octane' in single or separate processes based on config --> - <target name="octane" depends="init, --single-process, --separate-process"/> + <!-- alias for 'octane' --> + <target name="octane" depends="octane-nashorn"/> <!-- run octane benchmarks using octane as runtime --> - <target name="octane-v8" depends="octane-init"> - <antcall target="run-octane-v8"/> + <target name="octane-v8" depends="jar"> + <property name="runtime" value="v8"/> + <antcall target="octane-process-separate"/> + <antcall target="octane-process-single"/> </target> <!-- run octane benchmarks using Rhino as runtime --> - <target name="octane-rhino" depends="octane-init-rhino"> - <antcall target="run-octane-rhino"/> + <target name="octane-rhino" depends="jar"> + <property name="runtime" value="rhino"/> + <antcall target="octane-process-separate"/> + <antcall target="octane-process-single"/> </target> - - <target name="run-octane"> + + <macrodef name="run-one"> + <attribute name="cond"/> + <attribute name="runtime" default=""/> + <sequential> + <antcall target="run-octane-@{runtime}" if:set="@{cond}"> + <param name="octane-tests" value="${@{cond}}"/> + </antcall> + </sequential> + </macrodef> + + <target name="run-octane-nashorn"> <java classname="${nashorn.shell.tool}" classpath="${run.test.classpath}" fork="true" dir="."> <jvmarg line="${ext.class.path}"/> <jvmarg line="${run.test.jvmargs.octane} -Xms${run.test.xms} -Xmx${run.test.xmx}"/> + <!-- pass on all properties prefixed with 'nashorn' to the runtime --> <syspropertyset> <propertyref prefix="nashorn."/> </syspropertyset> <arg value="${octane-test-sys-prop.test.js.framework}"/> + <arg value="-scripting"/> <arg value="--"/> <arg value="${octane-tests}"/> <arg value="--runtime"/> - <arg value="Nashorn"/> + <arg value="nashorn"/> <arg value="--verbose"/> - <arg value="--iterations 8"/> + <arg value="--iterations ${octane.iterations}"/> </java> </target> @@ -386,11 +335,11 @@ <exec executable="${v8.shell}"> <arg value="${octane-test-sys-prop.test.js.framework}"/> <arg value="--"/> - <arg value="${octane-tests}"/> + <arg value="${octane-tests}"/> <arg value="--runtime"/> <arg value="v8"/> <arg value="--verbose"/> - <arg value="--iterations 8"/> + <arg value="--iterations ${octane.iterations}"/> </exec> </target> @@ -400,12 +349,14 @@ fork="true" dir="."> <jvmarg line="${run.test.jvmargs.octane} -Xms${run.test.xms} -Xmx${run.test.xmx}"/> + <arg value="-opt"/> + <arg value="9"/> <arg value="${octane-test-sys-prop.test.js.framework}"/> <arg value="${octane-tests}"/> <arg value="--runtime"/> - <arg value="Rhino"/> + <arg value="rhino"/> <arg value="--verbose"/> - <arg value="--iterations 8"/> + <arg value="--iterations ${octane.iterations}"/> </java> </target> @@ -416,18 +367,22 @@ <arg value="${octane-tests}/"/> </exec> </target> - + <target name="sunspider-init" depends="jar"> <fileset id="sunspider-set" - dir="${sunspider-test-sys-prop.test.js.roots}" - excludes="${sunspider-test-sys-prop.test.js.exclude.list}"> + dir="${sunspider-test-sys-prop.test.js.roots}" + excludes="${sunspider-test-sys-prop.test.js.exclude.list}"> <include name="**/*.js"/> </fileset> <pathconvert pathsep=" " property="sunspider-tests" refid="sunspider-set"/> </target> + <!--- SUNSPIDER JOB BELOW --> + <!-- run sunspider with Nashorn --> - <target name="sunspider" depends="sunspider-init"> + <target name="sunspider" depends="sunspider-nashorn"/> + + <target name="sunspider-nashorn" depends="sunspider-init"> <java classname="${nashorn.shell.tool}" classpath="${run.test.classpath}" fork="true" @@ -439,6 +394,9 @@ <arg value="${sunspider-test-sys-prop.test.js.framework}"/> <arg value="--"/> <arg value="${sunspider-tests}/"/> + <arg value="--verbose"/> + <arg value="--times"/> + <arg value="${sunspider.iterations}"/> </java> </target> @@ -448,6 +406,9 @@ <arg value="${sunspider-test-sys-prop.test.js.framework}"/> <arg value="--"/> <arg value="${sunspider-tests}/"/> + <arg value="--verbose"/> + <arg value="--times"/> + <arg value="${sunspider.iterations}"/> </exec> </target> @@ -458,8 +419,13 @@ fork="true" dir="."> <jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx}"/> + <arg value="-opt"/> + <arg value="9"/> <arg value="${sunspider-test-sys-prop.test.js.framework}"/> <arg value="${sunspider-tests}/"/> + <arg value="--verbose"/> + <arg value="--times"/> + <arg value="${sunspider.iterations}"/> </java> </target>
--- a/make/build.xml Wed Jun 04 20:20:44 2014 -0700 +++ b/make/build.xml Thu Jun 05 19:38:45 2014 -0700 @@ -1,4 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> + <!-- Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -21,12 +22,11 @@ or visit www.oracle.com if you need additional information or have any questions. --> + <project name="nashorn" default="test" basedir=".."> <import file="build-nasgen.xml"/> - <import file="build-benchmark.xml"/> <import file="code_coverage.xml"/> - <target name="init-conditions"> <!-- loading locally defined resources and properties. NB they owerwrite default ones defined later --> <property file="${user.home}/.nashorn.project.local.properties"/> @@ -51,7 +51,7 @@ <available property="testng.available" file="${file.reference.testng.jar}"/> <!-- check if Jemmy ang testng.jar are avaiable --> <condition property="jemmy.jfx.testng.available" value="true"> - <and> + <and> <available file="${file.reference.jemmyfx.jar}"/> <available file="${file.reference.jemmycore.jar}"/> <available file="${file.reference.jemmyawtinput.jar}"/> @@ -364,6 +364,7 @@ </target> <target name="test" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available"> + <delete dir="${build.dir}/nashorn_code_cache"/> <fileset id="test.classes" dir="${build.test.classes.dir}"> <include name="**/api/javaaccess/*Test.class"/> <include name="**/api/scripting/*Test.class"/> @@ -395,6 +396,7 @@ <pathelement path="${run.test.classpath}"/> </classpath> </testng> + <testng outputdir="${build.nosecurity.test.results.dir}" classfilesetref="test.nosecurity.classes" verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}"> <jvmarg line="${ext.class.path}"/> @@ -412,18 +414,6 @@ </testng> </target> - <target name="test-basicparallel" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file"> - <!-- use just build.test.classes.dir to avoid referring to TestNG --> - <java classname="${parallel.test.runner}" dir="${basedir}" classpath="${build.test.classes.dir}" failonerror="true" fork="true"> - <jvmarg line="${ext.class.path}"/> - <jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx} ${run.test.jvmsecurityargs}"/> - <syspropertyset> - <propertyref prefix="test-sys-prop."/> - <mapper type="glob" from="test-sys-prop.*" to="*"/> - </syspropertyset> - </java> - </target> - <target name="check-jemmy.jfx.testng" unless="jemmy.jfx.testng.available"> <echo message="WARNING: Jemmy or JavaFX or TestNG not available, will not run tests. Please copy testng.jar, JemmyCore.jar, JemmyFX.jar, JemmyAWTInput.jar under test${file.separator}lib directory. And make sure you have jfxrt.jar in ${java.home}${file.separator}lib${file.separator}ext dir."/> </target> @@ -432,15 +422,15 @@ <fileset id="test.classes" dir="${build.test.classes.dir}"> <include name="**/framework/*Test.class"/> </fileset> - + <copy file="${file.reference.jfxrt.jar}" todir="dist"/> - + <condition property="jfx.prism.order" value="-Dprism.order=j2d" else=" "> - <not> + <not> <os family="mac"/> </not> - </condition> - + </condition> + <testng outputdir="${build.test.results.dir}" classfilesetref="test.classes" verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}"> <jvmarg line="${ext.class.path}"/> @@ -455,7 +445,7 @@ </classpath> </testng> </target> - + <target name="testmarkdown" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available"> <fileset id="test.classes" dir="${build.test.classes.dir}"> <include name="**/framework/*Test.class"/> @@ -474,7 +464,7 @@ </classpath> </testng> </target> - + <target name="test262" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available"> <fileset id="test.classes" dir="${build.test.classes.dir}"> <include name="**/framework/*Test.class"/> @@ -514,6 +504,26 @@ </java> </target> + <target name="testparallel" depends="test-parallel"/> + + <target name="test-parallel" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available"> + <!-- use just build.test.classes.dir to avoid referring to TestNG --> + <java classname="${parallel.test.runner}" dir="${basedir}" + failonerror="true" + fork="true"> + <jvmarg line="${ext.class.path}"/> + <jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx} ${run.test.jvmsecurityargs}"/> + <classpath> + <pathelement path="${run.test.classpath}"/> + <pathelement path="${build.test.classes.dir}"/> + </classpath> + <syspropertyset> + <propertyref prefix="test-sys-prop."/> + <mapper type="glob" from="test-sys-prop.*" to="*"/> + </syspropertyset> + </java> + </target> + <target name="all" depends="test, docs" description="Build, test and generate docs for nashorn"/> @@ -621,7 +631,7 @@ <mkdir dir="${test.external.dir}/yui"/> <get src="http://yui.yahooapis.com/3.5.1/build/yui/yui.js" dest="${test.external.dir}/yui" skipexisting="true" ignoreerrors="true"/> <get src="http://yui.yahooapis.com/3.5.1/build/yui/yui-min.js" dest="${test.external.dir}/yui" skipexisting="true" ignoreerrors="true"/> - + <!-- showdown --> <mkdir dir="${test.external.dir}/showdown"/> <get src="https://raw.github.com/coreyti/showdown/master/src/showdown.js" dest="${test.external.dir}/showdown" skipexisting="true" ignoreerrors="true"/> @@ -642,4 +652,6 @@ <target name="alltests" depends="exit-if-no-testng, externals, update-externals, test, test262parallel, perf"/> + <import file="build-benchmark.xml"/> + </project>
--- a/make/nbproject/ide-targets.xml Wed Jun 04 20:20:44 2014 -0700 +++ b/make/nbproject/ide-targets.xml Thu Jun 05 19:38:45 2014 -0700 @@ -31,9 +31,10 @@ <classpath path="${run.test.classpath}"/> </nbjpdastart> <java classname="jdk.nashorn.tools.Shell" classpath="${run.test.classpath}" dir="samples" fork="true"> + <jvmarg line="-Dnashorn.optimistic"/> <jvmarg line="${ext.class.path}"/> <jvmarg line="${run.test.jvmargs}"/> - <arg value="test.js"/> + <arg value="../make/str.js"/> <jvmarg value="-Xdebug"/> <jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/> </java>
--- a/make/project.properties Wed Jun 04 20:20:44 2014 -0700 +++ b/make/project.properties Thu Jun 05 19:38:45 2014 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -53,6 +53,7 @@ # test classes directory build.test.classes.dir=${build.dir}/test/classes + # nashorn test jar - internal tests jar and api tests jar nashorn.internal.tests.jar=${build.dir}/nashorn-internal-tests.jar nashorn.api.tests.jar=${build.dir}/nashorn-api-tests.jar @@ -60,6 +61,7 @@ # test results directory build.test.results.dir=${build.dir}/test/reports build.nosecurity.test.results.dir=${build.dir}/test/nosecurity/reports +build.nooptimistic.test.results.dir=${build.dir}/test/nooptimistic/reports # This directory is removed when the project is cleaned: dist.dir=dist @@ -167,21 +169,14 @@ # test root for octane octane-test-sys-prop.test.js.roots=${test.external.dir}/octane/ -# run octane benchmars in separate processes? +# run octane benchmars in separate processes? (recommended) octane-test-sys-prop.separate.process=true # framework root for octane octane-test-sys-prop.test.js.framework=${test.basic.dir}/run-octane.js -# list of tests to be excluded -# mandreel excluded due to OOM -octane-test-sys-prop.test.js.exclude.list=\ - base.js \ - run.js \ - mandreel.js - # test root for sunspider -sunspider-test-sys-prop.test.js.roots=${test.external.dir}/sunspider/tests/sunspider-1.0/ +sunspider-test-sys-prop.test.js.roots=${test.external.dir}/sunspider/tests/sunspider-1.0.2/ # framework root for sunspider sunspider-test-sys-prop.test.js.framework=${test.basic.dir}/runsunspider.js @@ -197,6 +192,7 @@ # test262 test root test262-test-sys-prop.test.js.roots=${test262.suite.dir} + # test262 enable/disable strict mode tests test262-test-sys-prop.test.js.enable.strict.mode=true @@ -268,48 +264,113 @@ run.test.xmx=2G run.test.xms=2G +# uncomment this jfr.args to enable light recordings. the stack needs to be cranked up to 1024 frames, +# or everything will as of the now drown in lambda forms and be cut off. +# +#jfr.args=-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath="test_suite.jfr",stackdepth=1024 \ + +jfr.args= + run.test.user.language=tr run.test.user.country=TR -run.test.jvmargs.common=-server -XX:+TieredCompilation -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 -# -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods +run.test.jvmargs.common=\ + -server \ + -Dfile.encoding=UTF-8 \ + -Duser.language=${run.test.user.language} \ + -Duser.country=${run.test.user.country} \ + ${jfr.args} \ + -XX:+HeapDumpOnOutOfMemoryError # turn on assertions for tests -run.test.jvmargs.main=${run.test.jvmargs.common} -ea +run.test.jvmargs.main=${run.test.jvmargs.common} -ea -Dnashorn.lazy -#-XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M -run.test.jvmargs.octane.main=${run.test.jvmargs.common} +# extra jvmargs that might be useful for debugging +# +# -XX:+UnlockDiagnosticVMOptions +# +# turn off compressed class pointers in metaspace +# -XX:-UseCompressedKlassPointers +# +# dump the heap after every GC +# -XX:+PrintHeapAtGC +# +# manually set a metaspace size for class data +# -XX:ClassMetaspaceSize=300M +# +# print out methods compiled +# -XX:+PrintCompilation +# +# print all compiled nmethods with oopmaps and lots of other info +# -XX:+PrintNMethods +# Use best known performance options for octane +run.test.jvmargs.octane.main=${run.test.jvmargs.common} -Dnashorn.lazy -XX:+UnlockDiagnosticVMOptions -XX:+UseNewCode -XX:TypeProfileLevel=222 + +# Security manager args - make sure that we run with the nashorn.policy that the build creates run.test.jvmsecurityargs=-Xverify:all -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy # VM options for script tests with @fork option test-sys-prop.test.fork.jvm.options=${run.test.jvmargs.main} -Xmx${run.test.xmx} ${run.test.jvmsecurityargs} -cp ${run.test.classpath} # path of rhino.jar for benchmarks -rhino.jar= +rhino.dir= +rhino.jar=${rhino.dir}/js.jar v8.shell=d8 +# How many iterations should 'ant octane' run for each +# benchmark +octane.iterations=25 + +# List of octane tests to run, as properties prefixed with +# "octane.benchmark." mapping to the benchmark name in +# the test harness +# +# Octane tests that are disabled should have their entire line +# commented out Tests may be disabled for functionality reasons when +# they have bugs or when the runtime doesn't handle them (yet) +octane.benchmark.box2d=box2d +#octane.benchmark.code-load=code-load +octane.benchmark.crypto=crypto +octane.benchmark.deltablue=deltablue +octane.benchmark.earley-boyer=earley-boyer +octane.benchmark.gbemu=gbemu +octane.benchmark.navier-stokes=navier-stokes +octane.benchmark.mandreel=mandreel +octane.benchmark.pdfjs=pdfjs +octane.benchmark.raytrace=raytrace +octane.benchmark.regexp=regexp +octane.benchmark.richards=richards +octane.benchmark.splay=splay +#octane.benchmark.typescript=typescript +#octane.benchmark.zlib=zlib + #path to rhino jar file octaneperf-sys-prop.rhino.jar=${rhino.jar} #timeout for performance tests in minutes octaneperf-sys-prop.timeout.value=10 -################ -# codecoverage # -################ - #enable/disable code coverage; please redifine in the ${user.home}/.nashorn.project.local.properties +#how many iterations to run sunspider after warmup +sunspider.iterations=3000 + +################# +# code coverage # +################# + +#enable/disable code coverage; please redifine in the ${user.home}/.nashorn.project.local.properties make.code.coverage=false - #type of codecoverage; one of static or dynamic. Now only dynamic is supported + +#type of codecoverage; one of static or dynamic. Now only dynamic is supported jcov=dynamic - #naming of CC results - #NB directory specified in the cc.dir will be cleaned up!!! + +#naming of CC results +#NB directory specified in the cc.dir will be cleaned up!!! cc.dir=${basedir}/../Codecoverage_Nashorn cc.result.file.name=CC_${jcov}_nashorn.xml - #dynamic CC parameters; please redefine in the ${user.home}/.nashorn.project.local.properties + +#dynamic CC parameters; please redefine in the ${user.home}/.nashorn.project.local.properties jcov2.lib.dir=${basedir}/../jcov2/lib jcov.jar=${jcov2.lib.dir}/jcov.jar cc.include=jdk\.nashorn\.*
--- a/src/jdk/internal/dynalink/ChainedCallSite.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/ChainedCallSite.java Thu Jun 05 19:38:45 2014 -0700 @@ -103,8 +103,27 @@ * handle is always at the start of the chain. */ public class ChainedCallSite extends AbstractRelinkableCallSite { - private static final MethodHandle PRUNE = Lookup.findOwnSpecial(MethodHandles.lookup(), "prune", MethodHandle.class, - MethodHandle.class); + private static final MethodHandle PRUNE_CATCHES = + MethodHandles.insertArguments( + Lookup.findOwnSpecial( + MethodHandles.lookup(), + "prune", + MethodHandle.class, + MethodHandle.class, + boolean.class), + 2, + true); + + private static final MethodHandle PRUNE_SWITCHPOINTS = + MethodHandles.insertArguments( + Lookup.findOwnSpecial( + MethodHandles.lookup(), + "prune", + MethodHandle.class, + MethodHandle.class, + boolean.class), + 2, + false); private final AtomicReference<LinkedList<GuardedInvocation>> invocations = new AtomicReference<>(); @@ -112,7 +131,7 @@ * Creates a new chained call site. * @param descriptor the descriptor for the call site. */ - public ChainedCallSite(CallSiteDescriptor descriptor) { + public ChainedCallSite(final CallSiteDescriptor descriptor) { super(descriptor); } @@ -126,24 +145,26 @@ } @Override - public void relink(GuardedInvocation guardedInvocation, MethodHandle fallback) { - relinkInternal(guardedInvocation, fallback, false); + public void relink(final GuardedInvocation guardedInvocation, final MethodHandle fallback) { + relinkInternal(guardedInvocation, fallback, false, false); } @Override - public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle fallback) { - relinkInternal(guardedInvocation, fallback, true); + public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle fallback) { + relinkInternal(guardedInvocation, fallback, true, false); } - private MethodHandle relinkInternal(GuardedInvocation invocation, MethodHandle relink, boolean reset) { + private MethodHandle relinkInternal(final GuardedInvocation invocation, final MethodHandle relink, final boolean reset, final boolean removeCatches) { final LinkedList<GuardedInvocation> currentInvocations = invocations.get(); @SuppressWarnings({ "unchecked", "rawtypes" }) final LinkedList<GuardedInvocation> newInvocations = currentInvocations == null || reset ? new LinkedList<>() : (LinkedList)currentInvocations.clone(); - // First, prune the chain of invalidated switchpoints. - for(Iterator<GuardedInvocation> it = newInvocations.iterator(); it.hasNext();) { - if(it.next().hasBeenInvalidated()) { + // First, prune the chain of invalidated switchpoints, we always do this + // We also remove any catches if the remove catches flag is set + for(final Iterator<GuardedInvocation> it = newInvocations.iterator(); it.hasNext();) { + final GuardedInvocation inv = it.next(); + if(inv.hasBeenInvalidated() || (removeCatches && inv.getException() != null)) { it.remove(); } } @@ -160,12 +181,13 @@ // prune-and-invoke is used as the fallback for invalidated switchpoints. If a switchpoint gets invalidated, we // rebuild the chain and get rid of all invalidated switchpoints instead of letting them linger. - final MethodHandle pruneAndInvoke = makePruneAndInvokeMethod(relink); + final MethodHandle pruneAndInvokeSwitchPoints = makePruneAndInvokeMethod(relink, getPruneSwitchpoints()); + final MethodHandle pruneAndInvokeCatches = makePruneAndInvokeMethod(relink, getPruneCatches()); // Fold the new chain MethodHandle target = relink; - for(GuardedInvocation inv: newInvocations) { - target = inv.compose(pruneAndInvoke, target); + for(final GuardedInvocation inv: newInvocations) { + target = inv.compose(target, pruneAndInvokeSwitchPoints, pruneAndInvokeCatches); } // If nobody else updated the call site while we were rebuilding the chain, set the target to our chain. In case @@ -178,14 +200,30 @@ } /** + * Get the switchpoint pruning function for a chained call site + * @return function that removes invalidated switchpoints tied to callsite guard chain and relinks + */ + protected MethodHandle getPruneSwitchpoints() { + return PRUNE_SWITCHPOINTS; + } + + /** + * Get the catch pruning function for a chained call site + * @return function that removes all catches tied to callsite guard chain and relinks + */ + protected MethodHandle getPruneCatches() { + return PRUNE_CATCHES; + } + + /** * Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that * chain. * @param relink the ultimate fallback for the chain (the {@code DynamicLinker}'s relink). * @return a method handle for prune-and-invoke */ - private MethodHandle makePruneAndInvokeMethod(MethodHandle relink) { + private MethodHandle makePruneAndInvokeMethod(final MethodHandle relink, final MethodHandle prune) { // Bind prune to (this, relink) - final MethodHandle boundPrune = MethodHandles.insertArguments(PRUNE, 0, this, relink); + final MethodHandle boundPrune = MethodHandles.insertArguments(prune, 0, this, relink); // Make it ignore all incoming arguments final MethodHandle ignoreArgsPrune = MethodHandles.dropArguments(boundPrune, 0, type().parameterList()); // Invoke prune, then invoke the call site target with original arguments @@ -193,7 +231,7 @@ } @SuppressWarnings("unused") - private MethodHandle prune(MethodHandle relink) { - return relinkInternal(null, relink, false); + private MethodHandle prune(final MethodHandle relink, final boolean catches) { + return relinkInternal(null, relink, false, catches); } }
--- a/src/jdk/internal/dynalink/DefaultBootstrapper.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/DefaultBootstrapper.java Thu Jun 05 19:38:45 2014 -0700 @@ -117,7 +117,7 @@ * @param type the method signature at the call site * @return a new {@link MonomorphicCallSite} linked with the default dynamic linker. */ - public static CallSite bootstrap(MethodHandles.Lookup caller, String name, MethodType type) { + public static CallSite bootstrap(final MethodHandles.Lookup caller, final String name, final MethodType type) { return bootstrapInternal(caller, name, type); } @@ -133,11 +133,11 @@ * @param type the method signature at the call site * @return a new {@link MonomorphicCallSite} linked with the default dynamic linker. */ - public static CallSite publicBootstrap(MethodHandles.Lookup caller, String name, MethodType type) { + public static CallSite publicBootstrap(final MethodHandles.Lookup caller, final String name, final MethodType type) { return bootstrapInternal(MethodHandles.publicLookup(), name, type); } - private static CallSite bootstrapInternal(MethodHandles.Lookup caller, String name, MethodType type) { + private static CallSite bootstrapInternal(final MethodHandles.Lookup caller, final String name, final MethodType type) { return dynamicLinker.link(new MonomorphicCallSite(CallSiteDescriptorFactory.create(caller, name, type))); } }
--- a/src/jdk/internal/dynalink/DynamicLinker.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/DynamicLinker.java Thu Jun 05 19:38:45 2014 -0700 @@ -140,7 +140,6 @@ * @author Attila Szegedi */ public class DynamicLinker { - private static final String CLASS_NAME = DynamicLinker.class.getName(); private static final String RELINK_METHOD_NAME = "relink"; @@ -148,6 +147,7 @@ private static final String INITIAL_LINK_METHOD_NAME = "linkCallSite"; private final LinkerServices linkerServices; + private final GuardedInvocationFilter prelinkFilter; private final int runtimeContextArgCount; private final boolean syncOnRelink; private final int unstableRelinkThreshold; @@ -156,18 +156,20 @@ * Creates a new dynamic linker. * * @param linkerServices the linkerServices used by the linker, created by the factory. + * @param prelinkFilter see {@link DynamicLinkerFactory#setPrelinkFilter(GuardedInvocationFilter)} * @param runtimeContextArgCount see {@link DynamicLinkerFactory#setRuntimeContextArgCount(int)} */ - DynamicLinker(LinkerServices linkerServices, int runtimeContextArgCount, boolean syncOnRelink, - int unstableRelinkThreshold) { + DynamicLinker(final LinkerServices linkerServices, final GuardedInvocationFilter prelinkFilter, final int runtimeContextArgCount, + final boolean syncOnRelink, final int unstableRelinkThreshold) { if(runtimeContextArgCount < 0) { throw new IllegalArgumentException("runtimeContextArgCount < 0"); } if(unstableRelinkThreshold < 0) { throw new IllegalArgumentException("unstableRelinkThreshold < 0"); } + this.linkerServices = linkerServices; + this.prelinkFilter = prelinkFilter; this.runtimeContextArgCount = runtimeContextArgCount; - this.linkerServices = linkerServices; this.syncOnRelink = syncOnRelink; this.unstableRelinkThreshold = unstableRelinkThreshold; } @@ -199,7 +201,7 @@ private static final MethodHandle RELINK = Lookup.findOwnSpecial(MethodHandles.lookup(), RELINK_METHOD_NAME, MethodHandle.class, RelinkableCallSite.class, int.class, Object[].class); - private MethodHandle createRelinkAndInvokeMethod(final RelinkableCallSite callSite, int relinkCount) { + private MethodHandle createRelinkAndInvokeMethod(final RelinkableCallSite callSite, final int relinkCount) { // Make a bound MH of invoke() for this linker and call site final MethodHandle boundRelinker = MethodHandles.insertArguments(RELINK, 0, this, callSite, Integer.valueOf( relinkCount)); @@ -219,16 +221,15 @@ * @throws Exception rethrows any exception thrown by the linkers */ @SuppressWarnings("unused") - private MethodHandle relink(RelinkableCallSite callSite, int relinkCount, Object... arguments) throws Exception { + private MethodHandle relink(final RelinkableCallSite callSite, final int relinkCount, final Object... arguments) throws Exception { final CallSiteDescriptor callSiteDescriptor = callSite.getDescriptor(); final boolean unstableDetectionEnabled = unstableRelinkThreshold > 0; final boolean callSiteUnstable = unstableDetectionEnabled && relinkCount >= unstableRelinkThreshold; final LinkRequest linkRequest = - runtimeContextArgCount == 0 ? new LinkRequestImpl(callSiteDescriptor, callSiteUnstable, arguments) - : new RuntimeContextLinkRequestImpl(callSiteDescriptor, callSiteUnstable, arguments, - runtimeContextArgCount); + runtimeContextArgCount == 0 ? + new LinkRequestImpl(callSiteDescriptor, callSite, relinkCount, callSiteUnstable, arguments) : + new RuntimeContextLinkRequestImpl(callSiteDescriptor, callSite, relinkCount, callSiteUnstable, arguments, runtimeContextArgCount); - // Find a suitable method handle with a guard GuardedInvocation guardedInvocation = linkerServices.getGuardedInvocation(linkRequest); // None found - throw an exception @@ -248,6 +249,11 @@ } } + // Make sure we filter the invocation before linking it into the call site. This is typically used to match the + // return type of the invocation to the call site. + guardedInvocation = prelinkFilter.filter(guardedInvocation, linkRequest, linkerServices); + guardedInvocation.getClass(); // null pointer check + int newRelinkCount = relinkCount; // Note that the short-circuited "&&" evaluation below ensures we'll increment the relinkCount until // threshold + 1 but not beyond that. Threshold + 1 is treated as a special value to signal that resetAndRelink
--- a/src/jdk/internal/dynalink/DynamicLinkerFactory.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/DynamicLinkerFactory.java Thu Jun 05 19:38:45 2014 -0700 @@ -102,14 +102,15 @@ import jdk.internal.dynalink.support.ClassLoaderGetterContextProvider; import jdk.internal.dynalink.support.CompositeGuardingDynamicLinker; import jdk.internal.dynalink.support.CompositeTypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.support.DefaultPrelinkFilter; import jdk.internal.dynalink.support.LinkerServicesImpl; import jdk.internal.dynalink.support.TypeConverterFactory; /** * A factory class for creating {@link DynamicLinker}s. The most usual dynamic linker is a linker that is a composition * of all {@link GuardingDynamicLinker}s known and pre-created by the caller as well as any - * {@link AutoDiscovery automatically discovered} guarding linkers and the standard fallback {@link BeansLinker}. See - * {@link DynamicLinker} documentation for tips on how to use this class. + * {@link AutoDiscovery automatically discovered} guarding linkers and the standard fallback {@link BeansLinker} and a + * {@link DefaultPrelinkFilter}. See {@link DynamicLinker} documentation for tips on how to use this class. * * @author Attila Szegedi */ @@ -128,6 +129,7 @@ private int runtimeContextArgCount = 0; private boolean syncOnRelink = false; private int unstableRelinkThreshold = DEFAULT_UNSTABLE_RELINK_THRESHOLD; + private GuardedInvocationFilter prelinkFilter; /** * Sets the class loader for automatic discovery of available linkers. If not set explicitly, then the thread @@ -135,7 +137,7 @@ * * @param classLoader the class loader used for the autodiscovery of available linkers. */ - public void setClassLoader(ClassLoader classLoader) { + public void setClassLoader(final ClassLoader classLoader) { this.classLoader = classLoader; classLoaderExplicitlySet = true; } @@ -149,7 +151,7 @@ * @param prioritizedLinkers the list of prioritized linkers. Null can be passed to indicate no prioritized linkers * (this is also the default value). */ - public void setPrioritizedLinkers(List<? extends GuardingDynamicLinker> prioritizedLinkers) { + public void setPrioritizedLinkers(final List<? extends GuardingDynamicLinker> prioritizedLinkers) { this.prioritizedLinkers = prioritizedLinkers == null ? null : new ArrayList<>(prioritizedLinkers); } @@ -162,7 +164,7 @@ * * @param prioritizedLinkers a list of prioritized linkers. */ - public void setPrioritizedLinkers(GuardingDynamicLinker... prioritizedLinkers) { + public void setPrioritizedLinkers(final GuardingDynamicLinker... prioritizedLinkers) { setPrioritizedLinkers(Arrays.asList(prioritizedLinkers)); } @@ -173,7 +175,7 @@ * @param prioritizedLinker the single prioritized linker. Must not be null. * @throws IllegalArgumentException if null is passed. */ - public void setPrioritizedLinker(GuardingDynamicLinker prioritizedLinker) { + public void setPrioritizedLinker(final GuardingDynamicLinker prioritizedLinker) { if(prioritizedLinker == null) { throw new IllegalArgumentException("prioritizedLinker == null"); } @@ -188,7 +190,7 @@ * @param fallbackLinkers the list of fallback linkers. Can be empty to indicate the caller wishes to set no * fallback linkers. */ - public void setFallbackLinkers(List<? extends GuardingDynamicLinker> fallbackLinkers) { + public void setFallbackLinkers(final List<? extends GuardingDynamicLinker> fallbackLinkers) { this.fallbackLinkers = fallbackLinkers == null ? null : new ArrayList<>(fallbackLinkers); } @@ -200,7 +202,7 @@ * @param fallbackLinkers the list of fallback linkers. Can be empty to indicate the caller wishes to set no * fallback linkers. If it is left as null, the standard fallback {@link BeansLinker} will be used. */ - public void setFallbackLinkers(GuardingDynamicLinker... fallbackLinkers) { + public void setFallbackLinkers(final GuardingDynamicLinker... fallbackLinkers) { setFallbackLinkers(Arrays.asList(fallbackLinkers)); } @@ -214,7 +216,7 @@ * * @param runtimeContextArgCount the number of language runtime context arguments in call sites. */ - public void setRuntimeContextArgCount(int runtimeContextArgCount) { + public void setRuntimeContextArgCount(final int runtimeContextArgCount) { if(runtimeContextArgCount < 0) { throw new IllegalArgumentException("runtimeContextArgCount < 0"); } @@ -227,7 +229,7 @@ * multithreaded execution of dynamically linked code. * @param syncOnRelink true for invoking sync on relink, false otherwise. */ - public void setSyncOnRelink(boolean syncOnRelink) { + public void setSyncOnRelink(final boolean syncOnRelink) { this.syncOnRelink = syncOnRelink; } @@ -238,7 +240,7 @@ * call sites will never be considered unstable. * @see LinkRequest#isCallSiteUnstable() */ - public void setUnstableRelinkThreshold(int unstableRelinkThreshold) { + public void setUnstableRelinkThreshold(final int unstableRelinkThreshold) { if(unstableRelinkThreshold < 0) { throw new IllegalArgumentException("unstableRelinkThreshold < 0"); } @@ -246,7 +248,19 @@ } /** - * Creates a new dynamic linker consisting of all the prioritized, autodiscovered, and fallback linkers. + * Set the pre-link filter. This is a {@link GuardedInvocationFilter} that will get the final chance to modify the + * guarded invocation after it has been created by a component linker and before the dynamic linker links it into + * the call site. It is normally used to adapt the return value type of the invocation to the type of the call site. + * When not set explicitly, {@link DefaultPrelinkFilter} will be used. + * @param prelinkFilter the pre-link filter for the dynamic linker. + */ + public void setPrelinkFilter(final GuardedInvocationFilter prelinkFilter) { + this.prelinkFilter = prelinkFilter; + } + + /** + * Creates a new dynamic linker consisting of all the prioritized, autodiscovered, and fallback linkers as well as + * the pre-link filter. * * @return the new dynamic Linker */ @@ -275,7 +289,7 @@ // ... prioritized linkers, ... linkers.addAll(prioritizedLinkers); // ... filtered discovered linkers, ... - for(GuardingDynamicLinker linker: discovered) { + for(final GuardingDynamicLinker linker: discovered) { if(!knownLinkerClasses.contains(linker.getClass())) { linkers.add(linker); } @@ -300,14 +314,18 @@ } final List<GuardingTypeConverterFactory> typeConverters = new LinkedList<>(); - for(GuardingDynamicLinker linker: linkers) { + for(final GuardingDynamicLinker linker: linkers) { if(linker instanceof GuardingTypeConverterFactory) { typeConverters.add((GuardingTypeConverterFactory)linker); } } + if(prelinkFilter == null) { + prelinkFilter = new DefaultPrelinkFilter(); + } + return new DynamicLinker(new LinkerServicesImpl(new TypeConverterFactory(typeConverters), composite), - runtimeContextArgCount, syncOnRelink, unstableRelinkThreshold); + prelinkFilter, runtimeContextArgCount, syncOnRelink, unstableRelinkThreshold); } private static ClassLoader getThreadContextClassLoader() { @@ -319,9 +337,9 @@ }, ClassLoaderGetterContextProvider.GET_CLASS_LOADER_CONTEXT); } - private static void addClasses(Set<Class<? extends GuardingDynamicLinker>> knownLinkerClasses, - List<? extends GuardingDynamicLinker> linkers) { - for(GuardingDynamicLinker linker: linkers) { + private static void addClasses(final Set<Class<? extends GuardingDynamicLinker>> knownLinkerClasses, + final List<? extends GuardingDynamicLinker> linkers) { + for(final GuardingDynamicLinker linker: linkers) { knownLinkerClasses.add(linker.getClass()); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk/internal/dynalink/GuardedInvocationFilter.java Thu Jun 05 19:38:45 2014 -0700 @@ -0,0 +1,105 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache 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. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the names of + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package jdk.internal.dynalink; + +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; + +/** + * Interface for objects that are used to transform one guarded invocation into another one. Typical usage is for + * implementing {@link DynamicLinkerFactory#setPrelinkFilter(GuardedInvocationFilter) pre-link filters}. + */ +public interface GuardedInvocationFilter { + /** + * Given a guarded invocation, return a potentially different guarded invocation. + * @param inv the original guarded invocation. Null is never passed. + * @param linkRequest the link request for which the invocation was generated (usually by some linker). + * @param linkerServices the linker services that can be used during creation of a new invocation. + * @return either the passed guarded invocation or a different one, with the difference usually determined based on + * information in the link request and the differing invocation created with the assistance of the linker services. + * Whether or not {@code null} is an accepted return value is dependent on the user of the filter. + */ + public GuardedInvocation filter(GuardedInvocation inv, LinkRequest linkRequest, LinkerServices linkerServices); +}
--- a/src/jdk/internal/dynalink/MonomorphicCallSite.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/MonomorphicCallSite.java Thu Jun 05 19:38:45 2014 -0700 @@ -99,17 +99,17 @@ * Creates a new call site with monomorphic inline caching strategy. * @param descriptor the descriptor for this call site */ - public MonomorphicCallSite(CallSiteDescriptor descriptor) { + public MonomorphicCallSite(final CallSiteDescriptor descriptor) { super(descriptor); } @Override - public void relink(GuardedInvocation guardedInvocation, MethodHandle relink) { + public void relink(final GuardedInvocation guardedInvocation, final MethodHandle relink) { setTarget(guardedInvocation.compose(relink)); } @Override - public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle relink) { + public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle relink) { relink(guardedInvocation, relink); } }
--- a/src/jdk/internal/dynalink/NoSuchDynamicMethodException.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/NoSuchDynamicMethodException.java Thu Jun 05 19:38:45 2014 -0700 @@ -97,7 +97,7 @@ * Creates a new NoSuchDynamicMethodException * @param message the message of the exception. */ - public NoSuchDynamicMethodException(String message) { + public NoSuchDynamicMethodException(final String message) { super(message); } }
--- a/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java Thu Jun 05 19:38:45 2014 -0700 @@ -97,7 +97,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; - import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType; import jdk.internal.dynalink.linker.GuardedInvocation; @@ -107,6 +106,7 @@ import jdk.internal.dynalink.support.CallSiteDescriptorFactory; import jdk.internal.dynalink.support.Guards; import jdk.internal.dynalink.support.Lookup; +import jdk.internal.dynalink.support.TypeUtilities; /** * A base class for both {@link StaticClassLinker} and {@link BeanLinker}. Deals with common aspects of property @@ -123,18 +123,18 @@ private final Map<String, DynamicMethod> propertySetters = new HashMap<>(); private final Map<String, DynamicMethod> methods = new HashMap<>(); - AbstractJavaLinker(Class<?> clazz, MethodHandle classGuard) { + AbstractJavaLinker(final Class<?> clazz, final MethodHandle classGuard) { this(clazz, classGuard, classGuard); } - AbstractJavaLinker(Class<?> clazz, MethodHandle classGuard, MethodHandle assignableGuard) { + AbstractJavaLinker(final Class<?> clazz, final MethodHandle classGuard, final MethodHandle assignableGuard) { this.clazz = clazz; this.classGuard = classGuard; this.assignableGuard = assignableGuard; final FacetIntrospector introspector = createFacetIntrospector(); // Add methods and properties - for(Method method: introspector.getMethods()) { + for(final Method method: introspector.getMethods()) { final String name = method.getName(); // Add method addMember(name, method, methods); @@ -153,7 +153,7 @@ } // Add field getter/setters as property getters/setters. - for(Field field: introspector.getFields()) { + for(final Field field: introspector.getFields()) { final String name = field.getName(); // Only add a property getter when one is not defined already as a getXxx()/isXxx() method. if(!propertyGetters.containsKey(name)) { @@ -166,7 +166,7 @@ } // Add inner classes, but only those for which we don't hide a property with it - for(Map.Entry<String, MethodHandle> innerClassSpec: introspector.getInnerClassGetters().entrySet()) { + for(final Map.Entry<String, MethodHandle> innerClassSpec: introspector.getInnerClassGetters().entrySet()) { final String name = innerClassSpec.getKey(); if(!propertyGetters.containsKey(name)) { setPropertyGetter(name, innerClassSpec.getValue(), ValidationType.EXACT_CLASS); @@ -174,7 +174,7 @@ } } - private static String decapitalize(String str) { + private static String decapitalize(final String str) { assert str != null; if(str.isEmpty()) { return str; @@ -209,7 +209,7 @@ return getUnmodifiableKeys(methods); } - private static Collection<String> getUnmodifiableKeys(Map<String, ?> m) { + private static Collection<String> getUnmodifiableKeys(final Map<String, ?> m) { return Collections.unmodifiableCollection(m.keySet()); } @@ -222,7 +222,7 @@ * @param handle the method handle that implements the property getter * @param validationType the validation type for the property */ - private void setPropertyGetter(String name, SingleDynamicMethod handle, ValidationType validationType) { + private void setPropertyGetter(final String name, final SingleDynamicMethod handle, final ValidationType validationType) { propertyGetters.put(name, new AnnotatedDynamicMethod(handle, validationType)); } @@ -232,7 +232,7 @@ * @param prefixLen the getter prefix in the method name; should be 3 for getter names starting with "get" and 2 for * names starting with "is". */ - private void setPropertyGetter(Method getter, int prefixLen) { + private void setPropertyGetter(final Method getter, final int prefixLen) { setPropertyGetter(decapitalize(getter.getName().substring(prefixLen)), createDynamicMethod( getMostGenericGetter(getter)), ValidationType.INSTANCE_OF); } @@ -246,15 +246,15 @@ * @param handle the method handle that implements the property getter * @param validationType the validation type for the property */ - void setPropertyGetter(String name, MethodHandle handle, ValidationType validationType) { + void setPropertyGetter(final String name, final MethodHandle handle, final ValidationType validationType) { setPropertyGetter(name, new SimpleDynamicMethod(handle, clazz, name), validationType); } - private void addMember(String name, AccessibleObject ao, Map<String, DynamicMethod> methodMap) { + private void addMember(final String name, final AccessibleObject ao, final Map<String, DynamicMethod> methodMap) { addMember(name, createDynamicMethod(ao), methodMap); } - private void addMember(String name, SingleDynamicMethod method, Map<String, DynamicMethod> methodMap) { + private void addMember(final String name, final SingleDynamicMethod method, final Map<String, DynamicMethod> methodMap) { final DynamicMethod existingMethod = methodMap.get(name); final DynamicMethod newMethod = mergeMethods(method, existingMethod, clazz, name); if(newMethod != existingMethod) { @@ -270,9 +270,9 @@ * @param name the common name of the reflective members. * @return a dynamic method representing all the specified reflective members. */ - static DynamicMethod createDynamicMethod(Iterable<? extends AccessibleObject> members, Class<?> clazz, String name) { + static DynamicMethod createDynamicMethod(final Iterable<? extends AccessibleObject> members, final Class<?> clazz, final String name) { DynamicMethod dynMethod = null; - for(AccessibleObject method: members) { + for(final AccessibleObject method: members) { dynMethod = mergeMethods(createDynamicMethod(method), dynMethod, clazz, name); } return dynMethod; @@ -285,7 +285,7 @@ * @param m the reflective member * @return the single dynamic method representing the reflective member */ - private static SingleDynamicMethod createDynamicMethod(AccessibleObject m) { + private static SingleDynamicMethod createDynamicMethod(final AccessibleObject m) { if(CallerSensitiveDetector.isCallerSensitive(m)) { return new CallerSensitiveDynamicMethod(m); } @@ -301,7 +301,7 @@ * @param m the method or constructor * @return the method handle */ - private static MethodHandle unreflectSafely(AccessibleObject m) { + private static MethodHandle unreflectSafely(final AccessibleObject m) { if(m instanceof Method) { final Method reflMethod = (Method)m; final MethodHandle handle = Lookup.PUBLIC.unreflect(reflMethod); @@ -313,7 +313,7 @@ return StaticClassIntrospector.editConstructorMethodHandle(Lookup.PUBLIC.unreflectConstructor((Constructor<?>)m)); } - private static DynamicMethod mergeMethods(SingleDynamicMethod method, DynamicMethod existing, Class<?> clazz, String name) { + private static DynamicMethod mergeMethods(final SingleDynamicMethod method, final DynamicMethod existing, final Class<?> clazz, final String name) { if(existing == null) { return method; } else if(existing.contains(method)) { @@ -331,7 +331,7 @@ } @Override - public GuardedInvocation getGuardedInvocation(LinkRequest request, final LinkerServices linkerServices) + public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices) throws Exception { final LinkRequest ncrequest = request.withoutRuntimeContext(); // BeansLinker already checked that the name is at least 2 elements long and the first element is "dyn". @@ -353,8 +353,8 @@ return null; } - protected GuardedInvocationComponent getGuardedInvocationComponent(CallSiteDescriptor callSiteDescriptor, - LinkerServices linkerServices, List<String> operations) throws Exception { + protected GuardedInvocationComponent getGuardedInvocationComponent(final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, final List<String> operations) throws Exception { if(operations.isEmpty()) { return null; } @@ -374,27 +374,27 @@ return null; } - static final <T> List<T> pop(List<T> l) { + static final <T> List<T> pop(final List<T> l) { return l.subList(1, l.size()); } - MethodHandle getClassGuard(CallSiteDescriptor desc) { + MethodHandle getClassGuard(final CallSiteDescriptor desc) { return getClassGuard(desc.getMethodType()); } - MethodHandle getClassGuard(MethodType type) { + MethodHandle getClassGuard(final MethodType type) { return Guards.asType(classGuard, type); } - GuardedInvocationComponent getClassGuardedInvocationComponent(MethodHandle invocation, MethodType type) { + GuardedInvocationComponent getClassGuardedInvocationComponent(final MethodHandle invocation, final MethodType type) { return new GuardedInvocationComponent(invocation, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); } - private MethodHandle getAssignableGuard(MethodType type) { + private MethodHandle getAssignableGuard(final MethodType type) { return Guards.asType(assignableGuard, type); } - private GuardedInvocation getCallPropWithThis(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) { + private GuardedInvocation getCallPropWithThis(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) { switch(callSiteDescriptor.getNameTokenCount()) { case 3: { return createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices, @@ -406,25 +406,25 @@ } } - private GuardedInvocation createGuardedDynamicMethodInvocation(CallSiteDescriptor callSiteDescriptor, - LinkerServices linkerServices, String methodName, Map<String, DynamicMethod> methodMap){ + private GuardedInvocation createGuardedDynamicMethodInvocation(final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, final String methodName, final Map<String, DynamicMethod> methodMap){ final MethodHandle inv = getDynamicMethodInvocation(callSiteDescriptor, linkerServices, methodName, methodMap); return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteDescriptor.getMethodType())); } - private static MethodHandle getDynamicMethodInvocation(CallSiteDescriptor callSiteDescriptor, - LinkerServices linkerServices, String methodName, Map<String, DynamicMethod> methodMap) { + private static MethodHandle getDynamicMethodInvocation(final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, final String methodName, final Map<String, DynamicMethod> methodMap) { final DynamicMethod dynaMethod = getDynamicMethod(methodName, methodMap); return dynaMethod != null ? dynaMethod.getInvocation(callSiteDescriptor, linkerServices) : null; } - private static DynamicMethod getDynamicMethod(String methodName, Map<String, DynamicMethod> methodMap) { + private static DynamicMethod getDynamicMethod(final String methodName, final Map<String, DynamicMethod> methodMap) { final DynamicMethod dynaMethod = methodMap.get(methodName); return dynaMethod != null ? dynaMethod : getExplicitSignatureDynamicMethod(methodName, methodMap); } - private static SingleDynamicMethod getExplicitSignatureDynamicMethod(String methodName, - Map<String, DynamicMethod> methodsMap) { + private static SingleDynamicMethod getExplicitSignatureDynamicMethod(final String methodName, + final Map<String, DynamicMethod> methodsMap) { // What's below is meant to support the "name(type, type, ...)" syntax that programmers can use in a method name // to manually pin down an exact overloaded variant. This is not usually required, as the overloaded method // resolution works correctly in almost every situation. However, in presence of many language-specific @@ -457,14 +457,18 @@ private static final MethodHandle CONSTANT_NULL_DROP_METHOD_HANDLE = MethodHandles.dropArguments( MethodHandles.constant(Object.class, null), 0, MethodHandle.class); - private GuardedInvocationComponent getPropertySetter(CallSiteDescriptor callSiteDescriptor, - LinkerServices linkerServices, List<String> operations) throws Exception { - final MethodType type = callSiteDescriptor.getMethodType(); + private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, final List<String> operations) throws Exception { switch(callSiteDescriptor.getNameTokenCount()) { case 2: { // Must have three arguments: target object, property name, and property value. assertParameterCount(callSiteDescriptor, 3); + // We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be + // valid for us to convert return values proactively. Also, since we don't know what setters will be + // invoked, we'll conservatively presume Object return type. + final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class); + // What's below is basically: // foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation), // get_setter_handle(type, linkerServices)) @@ -473,8 +477,8 @@ // component's invocation. // Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll - // abbreviate to R(O, N, V) going forward. - // We want setters that conform to "R(O, V)" + // abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using + // Object return type). final MethodType setterType = type.dropParameterTypes(1, 2); // Bind property setter handle to the expected setter type and linker services. Type is // MethodHandle(Object, String, Object) @@ -495,11 +499,11 @@ final MethodHandle fallbackFolded; if(nextComponent == null) { - // Object(MethodHandle)->R(MethodHandle, O, N, V); returns constant null + // Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1, type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class)); } else { - // R(O, N, V)->R(MethodHandle, O, N, V); adapts the next component's invocation to drop the + // Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the // extra argument resulting from fold fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(), 0, MethodHandle.class); @@ -543,11 +547,14 @@ "getTarget", MethodType.methodType(MethodHandle.class, MethodHandles.Lookup.class)); private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class)); - private GuardedInvocationComponent getPropertyGetter(CallSiteDescriptor callSiteDescriptor, - LinkerServices linkerServices, List<String> ops) throws Exception { - final MethodType type = callSiteDescriptor.getMethodType(); + private GuardedInvocationComponent getPropertyGetter(final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, final List<String> ops) throws Exception { switch(callSiteDescriptor.getNameTokenCount()) { case 2: { + // Since we can't know what kind of a getter we'll get back on different invocations, we'll just + // conservatively presume Object. Note we can't just coerce to a narrower call site type as the linking + // runtime might not allow coercing at that call site. + final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class); // Must have exactly two arguments: receiver and name assertParameterCount(callSiteDescriptor, 2); @@ -563,11 +570,11 @@ GET_ANNOTATED_METHOD, 1, callSiteDescriptor.getLookup()); final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0, callSiteBoundMethodGetter); - // Object(AnnotatedDynamicMethod, Object)->R(AnnotatedDynamicMethod, T0) + // Object(AnnotatedDynamicMethod, Object)->Object(AnnotatedDynamicMethod, T0) final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker, MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0))); // Since it's in the target of a fold, drop the unnecessary second argument - // R(AnnotatedDynamicMethod, T0)->R(AnnotatedDynamicMethod, T0, T1) + // Object(AnnotatedDynamicMethod, T0)->Object(AnnotatedDynamicMethod, T0, T1) final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2, type.parameterType(1)); final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, @@ -575,17 +582,19 @@ final MethodHandle fallbackFolded; if(nextComponent == null) { - // Object(AnnotatedDynamicMethod)->R(AnnotatedDynamicMethod, T0, T1); returns constant null + // Object(AnnotatedDynamicMethod)->Object(AnnotatedDynamicMethod, T0, T1); returns constant null fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1, type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class)); } else { - // R(T0, T1)->R(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to drop the - // extra argument resulting from fold - fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(), - 0, AnnotatedDynamicMethod.class); + // Object(T0, T1)->Object(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to + // drop the extra argument resulting from fold and to change its return type to Object. + final MethodHandle nextInvocation = nextComponent.getGuardedInvocation().getInvocation(); + final MethodType nextType = nextInvocation.type(); + fallbackFolded = MethodHandles.dropArguments(nextInvocation.asType( + nextType.changeReturnType(Object.class)), 0, AnnotatedDynamicMethod.class); } - // fold(R(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1)) + // fold(Object(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1)) final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); if(nextComponent == null) { @@ -612,8 +621,8 @@ // value is null. final ValidationType validationType = annGetter.validationType; // TODO: we aren't using the type that declares the most generic getter here! - return new GuardedInvocationComponent(linkerServices.asType(getter, type), getGuard(validationType, - type), clazz, validationType); + return new GuardedInvocationComponent(getter, getGuard(validationType, + callSiteDescriptor.getMethodType()), clazz, validationType); } default: { // Can't do anything with more than 3 name components @@ -622,7 +631,7 @@ } } - private MethodHandle getGuard(ValidationType validationType, MethodType methodType) { + private MethodHandle getGuard(final ValidationType validationType, final MethodType methodType) { switch(validationType) { case EXACT_CLASS: { return getClassGuard(methodType); @@ -642,21 +651,25 @@ } } - private static final MethodHandle IS_DYNAMIC_METHOD_NOT_NULL = Guards.asType(Guards.isNotNull(), - MethodType.methodType(boolean.class, DynamicMethod.class)); - private static final MethodHandle DYNAMIC_METHOD_IDENTITY = MethodHandles.identity(DynamicMethod.class); + private static final MethodHandle IS_DYNAMIC_METHOD = Guards.isInstance(DynamicMethod.class, + MethodType.methodType(boolean.class, Object.class)); + private static final MethodHandle OBJECT_IDENTITY = MethodHandles.identity(Object.class); - private GuardedInvocationComponent getMethodGetter(CallSiteDescriptor callSiteDescriptor, - LinkerServices linkerServices, List<String> ops) throws Exception { - final MethodType type = callSiteDescriptor.getMethodType(); + private GuardedInvocationComponent getMethodGetter(final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, final List<String> ops) throws Exception { + // The created method handle will always return a DynamicMethod (or null), but since we don't want that type to + // be visible outside of this linker, declare it to return Object. + final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class); switch(callSiteDescriptor.getNameTokenCount()) { case 2: { // Must have exactly two arguments: receiver and name assertParameterCount(callSiteDescriptor, 2); final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops); - if(nextComponent == null) { - // No next component operation; just return a component for this operation. + if(nextComponent == null || !TypeUtilities.areAssignable(DynamicMethod.class, + nextComponent.getGuardedInvocation().getInvocation().type().returnType())) { + // No next component operation, or it can never produce a dynamic method; just return a component + // for this operation. return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type); } @@ -665,21 +678,20 @@ // bunch of method signature adjustments. Basically, execute method getter; if it returns a non-null // DynamicMethod, use identity to return it, otherwise delegate to nextComponent's invocation. - final MethodHandle typedGetter = linkerServices.asType(getDynamicMethod, type.changeReturnType( - DynamicMethod.class)); + final MethodHandle typedGetter = linkerServices.asType(getDynamicMethod, type); // Since it is part of the foldArgument() target, it will have extra args that we need to drop. final MethodHandle returnMethodHandle = linkerServices.asType(MethodHandles.dropArguments( - DYNAMIC_METHOD_IDENTITY, 1, type.parameterList()), type.insertParameterTypes(0, - DynamicMethod.class)); + OBJECT_IDENTITY, 1, type.parameterList()), type.insertParameterTypes(0, Object.class)); final MethodHandle nextComponentInvocation = nextComponent.getGuardedInvocation().getInvocation(); - // The assumption is that getGuardedInvocationComponent() already asType()'d it correctly - assert nextComponentInvocation.type().equals(type); + // The assumption is that getGuardedInvocationComponent() already asType()'d it correctly modulo the + // return type. + assert nextComponentInvocation.type().changeReturnType(type.returnType()).equals(type); // Since it is part of the foldArgument() target, we have to drop an extra arg it receives. final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0, - DynamicMethod.class); + Object.class); // Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get) final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( - IS_DYNAMIC_METHOD_NOT_NULL, returnMethodHandle, nextCombinedInvocation), typedGetter); + IS_DYNAMIC_METHOD, returnMethodHandle, nextCombinedInvocation), typedGetter); return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); } @@ -695,7 +707,7 @@ // No delegation to the next component of the composite operation; if we have a method with that name, // we'll always return it at this point. return getClassGuardedInvocationComponent(linkerServices.asType(MethodHandles.dropArguments( - MethodHandles.constant(DynamicMethod.class, method), 0, type.parameterType(0)), type), type); + MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type); } default: { // Can't do anything with more than 3 name components @@ -704,7 +716,31 @@ } } - private static void assertParameterCount(CallSiteDescriptor descriptor, int paramCount) { + static class MethodPair { + final MethodHandle method1; + final MethodHandle method2; + + MethodPair(final MethodHandle method1, final MethodHandle method2) { + this.method1 = method1; + this.method2 = method2; + } + + MethodHandle guardWithTest(final MethodHandle test) { + return MethodHandles.guardWithTest(test, method1, method2); + } + } + + static MethodPair matchReturnTypes(final MethodHandle m1, final MethodHandle m2) { + final MethodType type1 = m1.type(); + final MethodType type2 = m2.type(); + final Class<?> commonRetType = TypeUtilities.getCommonLosslessConversionType(type1.returnType(), + type2.returnType()); + return new MethodPair( + m1.asType(type1.changeReturnType(commonRetType)), + m2.asType(type2.changeReturnType(commonRetType))); + } + + private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) { if(descriptor.getMethodType().parameterCount() != paramCount) { throw new BootstrapMethodError(descriptor.getName() + " must have exactly " + paramCount + " parameters."); } @@ -719,7 +755,7 @@ * @return the method handle for retrieving the property, or null if the property does not exist */ @SuppressWarnings("unused") - private Object getPropertyGetterHandle(Object id) { + private Object getPropertyGetterHandle(final Object id) { return propertyGetters.get(id); } @@ -733,17 +769,20 @@ private final MethodHandle getPropertySetterHandle = GET_PROPERTY_SETTER_HANDLE.bindTo(this); @SuppressWarnings("unused") - private MethodHandle getPropertySetterHandle(CallSiteDescriptor setterDescriptor, LinkerServices linkerServices, - Object id) { + private MethodHandle getPropertySetterHandle(final CallSiteDescriptor setterDescriptor, final LinkerServices linkerServices, + final Object id) { return getDynamicMethodInvocation(setterDescriptor, linkerServices, String.valueOf(id), propertySetters); } private static MethodHandle GET_DYNAMIC_METHOD = MethodHandles.dropArguments(privateLookup.findOwnSpecial( - "getDynamicMethod", DynamicMethod.class, Object.class), 1, Object.class); + "getDynamicMethod", Object.class, Object.class), 1, Object.class); private final MethodHandle getDynamicMethod = GET_DYNAMIC_METHOD.bindTo(this); @SuppressWarnings("unused") - private DynamicMethod getDynamicMethod(Object name) { + // This method is marked to return Object instead of DynamicMethod as it's used as a linking component and we don't + // want to make the DynamicMethod type observable externally (e.g. as the return type of a MethodHandle returned for + // "dyn:getMethod" linking). + private Object getDynamicMethod(final Object name) { return getDynamicMethod(String.valueOf(name), methods); } @@ -754,7 +793,7 @@ * @return the dynamic method (either {@link SimpleDynamicMethod} or {@link OverloadedDynamicMethod}, or null if the * method with the specified name does not exist. */ - DynamicMethod getDynamicMethod(String name) { + DynamicMethod getDynamicMethod(final String name) { return getDynamicMethod(name, methods); } @@ -765,16 +804,16 @@ * @param getter the getter * @return getter with same name, declared on the most generic superclass/interface of the declaring class */ - private static Method getMostGenericGetter(Method getter) { + private static Method getMostGenericGetter(final Method getter) { return getMostGenericGetter(getter.getName(), getter.getReturnType(), getter.getDeclaringClass()); } - private static Method getMostGenericGetter(String name, Class<?> returnType, Class<?> declaringClass) { + private static Method getMostGenericGetter(final String name, final Class<?> returnType, final Class<?> declaringClass) { if(declaringClass == null) { return null; } // Prefer interfaces - for(Class<?> itf: declaringClass.getInterfaces()) { + for(final Class<?> itf: declaringClass.getInterfaces()) { final Method itfGetter = getMostGenericGetter(name, returnType, itf); if(itfGetter != null) { return itfGetter; @@ -787,7 +826,7 @@ if(!CheckRestrictedPackage.isRestrictedClass(declaringClass)) { try { return declaringClass.getMethod(name); - } catch(NoSuchMethodException e) { + } catch(final NoSuchMethodException e) { // Intentionally ignored, meant to fall through } } @@ -798,18 +837,18 @@ private final SingleDynamicMethod method; /*private*/ final ValidationType validationType; - AnnotatedDynamicMethod(SingleDynamicMethod method, ValidationType validationType) { + AnnotatedDynamicMethod(final SingleDynamicMethod method, final ValidationType validationType) { this.method = method; this.validationType = validationType; } - MethodHandle getInvocation(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) { + MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) { return method.getInvocation(callSiteDescriptor, linkerServices); } @SuppressWarnings("unused") - MethodHandle getTarget(MethodHandles.Lookup lookup) { - MethodHandle inv = method.getTarget(lookup); + MethodHandle getTarget(final MethodHandles.Lookup lookup) { + final MethodHandle inv = method.getTarget(lookup); assert inv != null; return inv; }
--- a/src/jdk/internal/dynalink/beans/AccessibleMembersLookup.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/AccessibleMembersLookup.java Thu Jun 05 19:38:45 2014 -0700 @@ -104,7 +104,7 @@ class AccessibleMembersLookup { private final Map<MethodSignature, Method> methods; private final Set<Class<?>> innerClasses; - private boolean instance; + private final boolean instance; /** * Creates a mapping for all accessible methods and inner classes on a class. @@ -112,7 +112,7 @@ * @param clazz the inspected class * @param instance true to inspect instance methods, false to inspect static methods. */ - AccessibleMembersLookup(final Class<?> clazz, boolean instance) { + AccessibleMembersLookup(final Class<?> clazz, final boolean instance) { this.methods = new HashMap<>(); this.innerClasses = new LinkedHashSet<>(); this.instance = instance; @@ -153,7 +153,7 @@ * @param name the name of the method this signature represents. * @param args the argument types of the method. */ - MethodSignature(String name, Class<?>[] args) { + MethodSignature(final String name, final Class<?>[] args) { this.name = name; this.args = args; } @@ -210,7 +210,7 @@ if(!CheckRestrictedPackage.isRestrictedClass(clazz)) { searchSuperTypes = false; - for(Method method: clazz.getMethods()) { + for(final Method method: clazz.getMethods()) { final boolean isStatic = Modifier.isStatic(method.getModifiers()); if(instance != isStatic) { final MethodSignature sig = new MethodSignature(method); @@ -237,7 +237,7 @@ } } } - for(Class<?> innerClass: clazz.getClasses()) { + for(final Class<?> innerClass: clazz.getClasses()) { // Add both static and non-static classes, regardless of instance flag. StaticClassLinker will just // expose non-static classes with explicit constructor outer class argument. // NOTE: getting inner class objects through getClasses() does not resolve them, so if those classes
--- a/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java Thu Jun 05 19:38:45 2014 -0700 @@ -108,7 +108,7 @@ ApplicableOverloadedMethods(final List<SingleDynamicMethod> methods, final MethodType callSiteType, final ApplicabilityTest test) { this.methods = new LinkedList<>(); - for(SingleDynamicMethod m: methods) { + for(final SingleDynamicMethod m: methods) { if(test.isApplicable(callSiteType, m)) { this.methods.add(m); } @@ -143,7 +143,7 @@ */ static final ApplicabilityTest APPLICABLE_BY_SUBTYPING = new ApplicabilityTest() { @Override - boolean isApplicable(MethodType callSiteType, SingleDynamicMethod method) { + boolean isApplicable(final MethodType callSiteType, final SingleDynamicMethod method) { final MethodType methodType = method.getMethodType(); final int methodArity = methodType.parameterCount(); if(methodArity != callSiteType.parameterCount()) { @@ -165,7 +165,7 @@ */ static final ApplicabilityTest APPLICABLE_BY_METHOD_INVOCATION_CONVERSION = new ApplicabilityTest() { @Override - boolean isApplicable(MethodType callSiteType, SingleDynamicMethod method) { + boolean isApplicable(final MethodType callSiteType, final SingleDynamicMethod method) { final MethodType methodType = method.getMethodType(); final int methodArity = methodType.parameterCount(); if(methodArity != callSiteType.parameterCount()) { @@ -188,7 +188,7 @@ */ static final ApplicabilityTest APPLICABLE_BY_VARIABLE_ARITY = new ApplicabilityTest() { @Override - boolean isApplicable(MethodType callSiteType, SingleDynamicMethod method) { + boolean isApplicable(final MethodType callSiteType, final SingleDynamicMethod method) { if(!method.isVarArgs()) { return false; }
--- a/src/jdk/internal/dynalink/beans/BeanIntrospector.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/BeanIntrospector.java Thu Jun 05 19:38:45 2014 -0700 @@ -88,7 +88,7 @@ import java.util.Map; class BeanIntrospector extends FacetIntrospector { - BeanIntrospector(Class<?> clazz) { + BeanIntrospector(final Class<?> clazz) { super(clazz, true); } @@ -98,7 +98,7 @@ } @Override - MethodHandle editMethodHandle(MethodHandle mh) { + MethodHandle editMethodHandle(final MethodHandle mh) { return mh; } }
--- a/src/jdk/internal/dynalink/beans/BeanLinker.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/BeanLinker.java Thu Jun 05 19:38:45 2014 -0700 @@ -106,7 +106,7 @@ * @author Attila Szegedi */ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicLinker { - BeanLinker(Class<?> clazz) { + BeanLinker(final Class<?> clazz) { super(clazz, Guards.getClassGuard(clazz), Guards.getInstanceOfGuard(clazz)); if(clazz.isArray()) { // Some languages won't have a notion of manipulating collections. Exposing "length" on arrays as an @@ -119,7 +119,7 @@ } @Override - public boolean canLinkType(Class<?> type) { + public boolean canLinkType(final Class<?> type) { return type == clazz; } @@ -129,8 +129,8 @@ } @Override - protected GuardedInvocationComponent getGuardedInvocationComponent(CallSiteDescriptor callSiteDescriptor, - LinkerServices linkerServices, List<String> operations) throws Exception { + protected GuardedInvocationComponent getGuardedInvocationComponent(final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, final List<String> operations) throws Exception { final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations); if(superGic != null) { @@ -166,7 +166,7 @@ private static MethodHandle MAP_GUARD = Guards.getInstanceOfGuard(Map.class); private GuardedInvocationComponent getElementGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, List<String> operations) throws Exception { + final LinkerServices linkerServices, final List<String> operations) throws Exception { final MethodType callSiteType = callSiteDescriptor.getMethodType(); final Class<?> declaredType = callSiteType.parameterType(0); final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, @@ -237,8 +237,9 @@ } else { checkGuard = convertArgToInt(RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor); } - return nextComponent.compose(MethodHandles.guardWithTest(binder.bindTest(checkGuard), - binder.bind(invocation), nextComponent.getGuardedInvocation().getInvocation()), gi.getGuard(), + final MethodPair matchedInvocations = matchReturnTypes(binder.bind(invocation), + nextComponent.getGuardedInvocation().getInvocation()); + return nextComponent.compose(matchedInvocations.guardWithTest(binder.bindTest(checkGuard)), gi.getGuard(), gic.getValidatorClass(), gic.getValidationType()); } @@ -247,7 +248,7 @@ CallSiteDescriptor.NAME_OPERAND); } - private static Object convertKeyToInteger(String fixedKey, LinkerServices linkerServices) throws Exception { + private static Object convertKeyToInteger(final String fixedKey, final LinkerServices linkerServices) throws Exception { try { if(linkerServices.canConvert(String.class, Number.class)) { try { @@ -267,18 +268,18 @@ return Integer.valueOf(intIndex); } catch(Exception|Error e) { throw e; - } catch(Throwable t) { + } catch(final Throwable t) { throw new RuntimeException(t); } } return Integer.valueOf(fixedKey); - } catch(NumberFormatException e) { + } catch(final NumberFormatException e) { // key is not a number return null; } } - private static MethodHandle convertArgToInt(MethodHandle mh, LinkerServices ls, CallSiteDescriptor desc) { + private static MethodHandle convertArgToInt(final MethodHandle mh, final LinkerServices ls, final CallSiteDescriptor desc) { final Class<?> sourceType = desc.getMethodType().parameterType(1); if(TypeUtilities.isMethodInvocationConvertible(sourceType, Number.class)) { return mh; @@ -301,21 +302,21 @@ private final MethodType methodType; private final Object fixedKey; - Binder(LinkerServices linkerServices, MethodType methodType, Object fixedKey) { + Binder(final LinkerServices linkerServices, final MethodType methodType, final Object fixedKey) { this.linkerServices = linkerServices; this.methodType = fixedKey == null ? methodType : methodType.insertParameterTypes(1, fixedKey.getClass()); this.fixedKey = fixedKey; } - /*private*/ MethodHandle bind(MethodHandle handle) { - return bindToFixedKey(linkerServices.asType(handle, methodType)); + /*private*/ MethodHandle bind(final MethodHandle handle) { + return bindToFixedKey(linkerServices.asTypeLosslessReturn(handle, methodType)); } - /*private*/ MethodHandle bindTest(MethodHandle handle) { + /*private*/ MethodHandle bindTest(final MethodHandle handle) { return bindToFixedKey(Guards.asType(handle, methodType)); } - private MethodHandle bindToFixedKey(MethodHandle handle) { + private MethodHandle bindToFixedKey(final MethodHandle handle) { return fixedKey == null ? handle : MethodHandles.insertArguments(handle, 1, fixedKey); } } @@ -325,12 +326,12 @@ private static MethodHandle CONTAINS_MAP = Lookup.PUBLIC.findVirtual(Map.class, "containsKey", MethodType.methodType(boolean.class, Object.class)); - private static MethodHandle findRangeCheck(Class<?> collectionType) { + private static MethodHandle findRangeCheck(final Class<?> collectionType) { return Lookup.findOwnStatic(MethodHandles.lookup(), "rangeCheck", boolean.class, collectionType, Object.class); } @SuppressWarnings("unused") - private static final boolean rangeCheck(Object array, Object index) { + private static final boolean rangeCheck(final Object array, final Object index) { if(!(index instanceof Number)) { return false; } @@ -347,7 +348,7 @@ } @SuppressWarnings("unused") - private static final boolean rangeCheck(List<?> list, Object index) { + private static final boolean rangeCheck(final List<?> list, final Object index) { if(!(index instanceof Number)) { return false; } @@ -369,8 +370,8 @@ private static MethodHandle PUT_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "put", MethodType.methodType(Object.class, Object.class, Object.class)); - private GuardedInvocationComponent getElementSetter(CallSiteDescriptor callSiteDescriptor, - LinkerServices linkerServices, List<String> operations) throws Exception { + private GuardedInvocationComponent getElementSetter(final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, final List<String> operations) throws Exception { final MethodType callSiteType = callSiteDescriptor.getMethodType(); final Class<?> declaredType = callSiteType.parameterType(0); @@ -440,8 +441,9 @@ final MethodHandle checkGuard = convertArgToInt(invocation == SET_LIST_ELEMENT ? RANGE_CHECK_LIST : RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor); - return nextComponent.compose(MethodHandles.guardWithTest(binder.bindTest(checkGuard), - binder.bind(invocation), nextComponent.getGuardedInvocation().getInvocation()), gi.getGuard(), + final MethodPair matchedInvocations = matchReturnTypes(binder.bind(invocation), + nextComponent.getGuardedInvocation().getInvocation()); + return nextComponent.compose(matchedInvocations.guardWithTest(binder.bindTest(checkGuard)), gi.getGuard(), gic.getValidatorClass(), gic.getValidationType()); } @@ -456,7 +458,7 @@ private static MethodHandle COLLECTION_GUARD = Guards.getInstanceOfGuard(Collection.class); - private GuardedInvocationComponent getLengthGetter(CallSiteDescriptor callSiteDescriptor) { + private GuardedInvocationComponent getLengthGetter(final CallSiteDescriptor callSiteDescriptor) { assertParameterCount(callSiteDescriptor, 1); final MethodType callSiteType = callSiteDescriptor.getMethodType(); final Class<?> declaredType = callSiteType.parameterType(0); @@ -486,7 +488,7 @@ return null; } - private static void assertParameterCount(CallSiteDescriptor descriptor, int paramCount) { + private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) { if(descriptor.getMethodType().parameterCount() != paramCount) { throw new BootstrapMethodError(descriptor.getName() + " must have exactly " + paramCount + " parameters."); }
--- a/src/jdk/internal/dynalink/beans/BeansLinker.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/BeansLinker.java Thu Jun 05 19:38:45 2014 -0700 @@ -131,7 +131,7 @@ public class BeansLinker implements GuardingDynamicLinker { private static final ClassValue<TypeBasedGuardingDynamicLinker> linkers = new ClassValue<TypeBasedGuardingDynamicLinker>() { @Override - protected TypeBasedGuardingDynamicLinker computeValue(Class<?> clazz) { + protected TypeBasedGuardingDynamicLinker computeValue(final Class<?> clazz) { // If ClassValue.put() were public, we could just pre-populate with these known mappings... return clazz == Class.class ? new ClassLinker() : @@ -154,7 +154,7 @@ * @param clazz the class * @return a bean linker for that class */ - public static TypeBasedGuardingDynamicLinker getLinkerForClass(Class<?> clazz) { + public static TypeBasedGuardingDynamicLinker getLinkerForClass(final Class<?> clazz) { return linkers.get(clazz); } @@ -173,8 +173,8 @@ * @param clazz the class * @return a collection of names of all readable instance properties of a class. */ - public static Collection<String> getReadableInstancePropertyNames(Class<?> clazz) { - TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz); + public static Collection<String> getReadableInstancePropertyNames(final Class<?> clazz) { + final TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz); if(linker instanceof BeanLinker) { return ((BeanLinker)linker).getReadablePropertyNames(); } @@ -186,8 +186,8 @@ * @param clazz the class * @return a collection of names of all writable instance properties of a class. */ - public static Collection<String> getWritableInstancePropertyNames(Class<?> clazz) { - TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz); + public static Collection<String> getWritableInstancePropertyNames(final Class<?> clazz) { + final TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz); if(linker instanceof BeanLinker) { return ((BeanLinker)linker).getWritablePropertyNames(); } @@ -199,8 +199,8 @@ * @param clazz the class * @return a collection of names of all instance methods of a class. */ - public static Collection<String> getInstanceMethodNames(Class<?> clazz) { - TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz); + public static Collection<String> getInstanceMethodNames(final Class<?> clazz) { + final TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz); if(linker instanceof BeanLinker) { return ((BeanLinker)linker).getMethodNames(); } @@ -212,7 +212,7 @@ * @param clazz the class * @return a collection of names of all readable static properties of a class. */ - public static Collection<String> getReadableStaticPropertyNames(Class<?> clazz) { + public static Collection<String> getReadableStaticPropertyNames(final Class<?> clazz) { return StaticClassLinker.getReadableStaticPropertyNames(clazz); } @@ -221,7 +221,7 @@ * @param clazz the class * @return a collection of names of all writable static properties of a class. */ - public static Collection<String> getWritableStaticPropertyNames(Class<?> clazz) { + public static Collection<String> getWritableStaticPropertyNames(final Class<?> clazz) { return StaticClassLinker.getWritableStaticPropertyNames(clazz); } @@ -230,12 +230,12 @@ * @param clazz the class * @return a collection of names of all static methods of a class. */ - public static Collection<String> getStaticMethodNames(Class<?> clazz) { + public static Collection<String> getStaticMethodNames(final Class<?> clazz) { return StaticClassLinker.getStaticMethodNames(clazz); } @Override - public GuardedInvocation getGuardedInvocation(LinkRequest request, final LinkerServices linkerServices) + public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices) throws Exception { final CallSiteDescriptor callSiteDescriptor = request.getCallSiteDescriptor(); final int l = callSiteDescriptor.getNameTokenCount();
--- a/src/jdk/internal/dynalink/beans/CallerSensitiveDetector.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/CallerSensitiveDetector.java Thu Jun 05 19:38:45 2014 -0700 @@ -107,14 +107,14 @@ private static final DetectionStrategy DETECTION_STRATEGY = getDetectionStrategy(); - static boolean isCallerSensitive(AccessibleObject ao) { + static boolean isCallerSensitive(final AccessibleObject ao) { return DETECTION_STRATEGY.isCallerSensitive(ao); } private static DetectionStrategy getDetectionStrategy() { try { return new PrivilegedDetectionStrategy(); - } catch(Throwable t) { + } catch(final Throwable t) { return new UnprivilegedDetectionStrategy(); } } @@ -127,7 +127,7 @@ private static final Class<? extends Annotation> CALLER_SENSITIVE_ANNOTATION_CLASS = CallerSensitive.class; @Override - boolean isCallerSensitive(AccessibleObject ao) { + boolean isCallerSensitive(final AccessibleObject ao) { return ao.getAnnotation(CALLER_SENSITIVE_ANNOTATION_CLASS) != null; } } @@ -136,8 +136,8 @@ private static final String CALLER_SENSITIVE_ANNOTATION_STRING = "@sun.reflect.CallerSensitive()"; @Override - boolean isCallerSensitive(AccessibleObject o) { - for(Annotation a: o.getAnnotations()) { + boolean isCallerSensitive(final AccessibleObject o) { + for(final Annotation a: o.getAnnotations()) { if(String.valueOf(a).equals(CALLER_SENSITIVE_ANNOTATION_STRING)) { return true; }
--- a/src/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java Thu Jun 05 19:38:45 2014 -0700 @@ -107,13 +107,13 @@ private final AccessibleObject target; private final MethodType type; - public CallerSensitiveDynamicMethod(AccessibleObject target) { + public CallerSensitiveDynamicMethod(final AccessibleObject target) { super(getName(target)); this.target = target; this.type = getMethodType(target); } - private static String getName(AccessibleObject target) { + private static String getName(final AccessibleObject target) { final Member m = (Member)target; return getMethodNameWithSignature(getMethodType(target), getClassAndMethodName(m.getDeclaringClass(), m.getName())); @@ -124,7 +124,7 @@ return type; } - private static MethodType getMethodType(AccessibleObject ao) { + private static MethodType getMethodType(final AccessibleObject ao) { final boolean isMethod = ao instanceof Method; final Class<?> rtype = isMethod ? ((Method)ao).getReturnType() : ((Constructor<?>)ao).getDeclaringClass(); final Class<?>[] ptypes = isMethod ? ((Method)ao).getParameterTypes() : ((Constructor<?>)ao).getParameterTypes(); @@ -144,7 +144,7 @@ } @Override - MethodHandle getTarget(MethodHandles.Lookup lookup) { + MethodHandle getTarget(final MethodHandles.Lookup lookup) { if(target instanceof Method) { final MethodHandle mh = Lookup.unreflect(lookup, (Method)target); if(Modifier.isStatic(((Member)target).getModifiers())) {
--- a/src/jdk/internal/dynalink/beans/CheckRestrictedPackage.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/CheckRestrictedPackage.java Thu Jun 05 19:38:45 2014 -0700 @@ -101,7 +101,7 @@ * @param clazz the class to test * @return true if the class is either not public, or it resides in a package with restricted access. */ - static boolean isRestrictedClass(Class<?> clazz) { + static boolean isRestrictedClass(final Class<?> clazz) { if(!Modifier.isPublic(clazz.getModifiers())) { // Non-public classes are always restricted return true; @@ -126,7 +126,7 @@ return null; } }, NO_PERMISSIONS_CONTEXT); - } catch(SecurityException e) { + } catch(final SecurityException e) { return true; } return false;
--- a/src/jdk/internal/dynalink/beans/ClassString.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/ClassString.java Thu Jun 05 19:38:45 2014 -0700 @@ -104,16 +104,16 @@ private final Class<?>[] classes; private int hashCode; - ClassString(Class<?>[] classes) { + ClassString(final Class<?>[] classes) { this.classes = classes; } - ClassString(MethodType type) { + ClassString(final MethodType type) { this(type.parameterArray()); } @Override - public boolean equals(Object other) { + public boolean equals(final Object other) { if(!(other instanceof ClassString)) { return false; } @@ -150,7 +150,7 @@ return true; } - List<MethodHandle> getMaximallySpecifics(List<MethodHandle> methods, LinkerServices linkerServices, boolean varArg) { + List<MethodHandle> getMaximallySpecifics(final List<MethodHandle> methods, final LinkerServices linkerServices, final boolean varArg) { return MaximallySpecific.getMaximallySpecificMethodHandles(getApplicables(methods, linkerServices, varArg), varArg, classes, linkerServices); } @@ -158,7 +158,7 @@ /** * Returns all methods that are applicable to actual parameter classes represented by this ClassString object. */ - LinkedList<MethodHandle> getApplicables(List<MethodHandle> methods, LinkerServices linkerServices, boolean varArg) { + LinkedList<MethodHandle> getApplicables(final List<MethodHandle> methods, final LinkerServices linkerServices, final boolean varArg) { final LinkedList<MethodHandle> list = new LinkedList<>(); for(final MethodHandle member: methods) { if(isApplicable(member, linkerServices, varArg)) { @@ -173,7 +173,7 @@ * object. * */ - private boolean isApplicable(MethodHandle method, LinkerServices linkerServices, boolean varArg) { + private boolean isApplicable(final MethodHandle method, final LinkerServices linkerServices, final boolean varArg) { final Class<?>[] formalTypes = method.type().parameterArray(); final int cl = classes.length; final int fl = formalTypes.length - (varArg ? 1 : 0); @@ -203,7 +203,7 @@ return true; } - private static boolean canConvert(LinkerServices ls, Class<?> from, Class<?> to) { + private static boolean canConvert(final LinkerServices ls, final Class<?> from, final Class<?> to) { if(from == NULL_CLASS) { return !to.isPrimitive(); }
--- a/src/jdk/internal/dynalink/beans/DynamicMethod.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/DynamicMethod.java Thu Jun 05 19:38:45 2014 -0700 @@ -99,7 +99,7 @@ abstract class DynamicMethod { private final String name; - DynamicMethod(String name) { + DynamicMethod(final String name) { this.name = name; } @@ -138,7 +138,7 @@ */ abstract boolean contains(SingleDynamicMethod method); - static String getClassAndMethodName(Class<?> clazz, String name) { + static String getClassAndMethodName(final Class<?> clazz, final String name) { final String clazzName = clazz.getCanonicalName(); return (clazzName == null ? clazz.getName() : clazzName) + "." + name; }
--- a/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java Thu Jun 05 19:38:45 2014 -0700 @@ -99,12 +99,12 @@ */ class DynamicMethodLinker implements TypeBasedGuardingDynamicLinker { @Override - public boolean canLinkType(Class<?> type) { + public boolean canLinkType(final Class<?> type) { return DynamicMethod.class.isAssignableFrom(type); } @Override - public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, LinkerServices linkerServices) { + public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) { final Object receiver = linkRequest.getReceiver(); if(!(receiver instanceof DynamicMethod)) { return null;
--- a/src/jdk/internal/dynalink/beans/FacetIntrospector.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/FacetIntrospector.java Thu Jun 05 19:38:45 2014 -0700 @@ -106,7 +106,7 @@ protected final AccessibleMembersLookup membersLookup; - FacetIntrospector(Class<?> clazz, boolean instance) { + FacetIntrospector(final Class<?> clazz, final boolean instance) { this.clazz = clazz; this.instance = instance; isRestricted = CheckRestrictedPackage.isRestrictedClass(clazz); @@ -135,7 +135,7 @@ final Field[] fields = clazz.getFields(); final Collection<Field> cfields = new ArrayList<>(fields.length); - for(Field field: fields) { + for(final Field field: fields) { final boolean isStatic = Modifier.isStatic(field.getModifiers()); if(isStatic && clazz != field.getDeclaringClass()) { // ignore inherited static fields @@ -149,7 +149,7 @@ return cfields; } - boolean isAccessible(Member m) { + boolean isAccessible(final Member m) { final Class<?> declaring = m.getDeclaringClass(); // (declaring == clazz) is just an optimization - we're calling this only from code that operates on a // non-restriced class, so if the declaring class is identical to the class being inspected, then forego @@ -166,11 +166,11 @@ } - MethodHandle unreflectGetter(Field field) { + MethodHandle unreflectGetter(final Field field) { return editMethodHandle(Lookup.PUBLIC.unreflectGetter(field)); } - MethodHandle unreflectSetter(Field field) { + MethodHandle unreflectSetter(final Field field) { return editMethodHandle(Lookup.PUBLIC.unreflectSetter(field)); }
--- a/src/jdk/internal/dynalink/beans/GuardedInvocationComponent.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/GuardedInvocationComponent.java Thu Jun 05 19:38:45 2014 -0700 @@ -105,38 +105,38 @@ private final GuardedInvocation guardedInvocation; private final Validator validator; - GuardedInvocationComponent(MethodHandle invocation) { + GuardedInvocationComponent(final MethodHandle invocation) { this(invocation, null, ValidationType.NONE); } - GuardedInvocationComponent(MethodHandle invocation, MethodHandle guard, ValidationType validationType) { + GuardedInvocationComponent(final MethodHandle invocation, final MethodHandle guard, final ValidationType validationType) { this(invocation, guard, null, validationType); } - GuardedInvocationComponent(MethodHandle invocation, MethodHandle guard, Class<?> validatorClass, - ValidationType validationType) { + GuardedInvocationComponent(final MethodHandle invocation, final MethodHandle guard, final Class<?> validatorClass, + final ValidationType validationType) { this(invocation, guard, new Validator(validatorClass, validationType)); } - GuardedInvocationComponent(GuardedInvocation guardedInvocation, Class<?> validatorClass, - ValidationType validationType) { + GuardedInvocationComponent(final GuardedInvocation guardedInvocation, final Class<?> validatorClass, + final ValidationType validationType) { this(guardedInvocation, new Validator(validatorClass, validationType)); } - GuardedInvocationComponent replaceInvocation(MethodHandle newInvocation) { + GuardedInvocationComponent replaceInvocation(final MethodHandle newInvocation) { return replaceInvocation(newInvocation, guardedInvocation.getGuard()); } - GuardedInvocationComponent replaceInvocation(MethodHandle newInvocation, MethodHandle newGuard) { + GuardedInvocationComponent replaceInvocation(final MethodHandle newInvocation, final MethodHandle newGuard) { return new GuardedInvocationComponent(guardedInvocation.replaceMethods(newInvocation, newGuard), validator); } - private GuardedInvocationComponent(MethodHandle invocation, MethodHandle guard, Validator validator) { + private GuardedInvocationComponent(final MethodHandle invocation, final MethodHandle guard, final Validator validator) { this(new GuardedInvocation(invocation, guard), validator); } - private GuardedInvocationComponent(GuardedInvocation guardedInvocation, Validator validator) { + private GuardedInvocationComponent(final GuardedInvocation guardedInvocation, final Validator validator) { this.guardedInvocation = guardedInvocation; this.validator = validator; } @@ -153,8 +153,8 @@ return validator.validationType; } - GuardedInvocationComponent compose(MethodHandle compositeInvocation, MethodHandle otherGuard, - Class<?> otherValidatorClass, ValidationType otherValidationType) { + GuardedInvocationComponent compose(final MethodHandle compositeInvocation, final MethodHandle otherGuard, + final Class<?> otherValidatorClass, final ValidationType otherValidationType) { final Validator compositeValidator = validator.compose(new Validator(otherValidatorClass, otherValidationType)); final MethodHandle compositeGuard = compositeValidator == validator ? guardedInvocation.getGuard() : otherGuard; return new GuardedInvocationComponent(compositeInvocation, compositeGuard, compositeValidator); @@ -164,12 +164,12 @@ /*private*/ final Class<?> validatorClass; /*private*/ final ValidationType validationType; - Validator(Class<?> validatorClass, ValidationType validationType) { + Validator(final Class<?> validatorClass, final ValidationType validationType) { this.validatorClass = validatorClass; this.validationType = validationType; } - Validator compose(Validator other) { + Validator compose(final Validator other) { if(other.validationType == ValidationType.NONE) { return this; } @@ -240,7 +240,7 @@ throw new AssertionError("Incompatible composition " + this + " vs " + other); } - private boolean isAssignableFrom(Validator other) { + private boolean isAssignableFrom(final Validator other) { return validatorClass.isAssignableFrom(other.validatorClass); }
--- a/src/jdk/internal/dynalink/beans/MaximallySpecific.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/MaximallySpecific.java Thu Jun 05 19:38:45 2014 -0700 @@ -105,7 +105,7 @@ * @param varArgs whether to assume the methods are varargs * @return the list of maximally specific methods. */ - static List<SingleDynamicMethod> getMaximallySpecificMethods(List<SingleDynamicMethod> methods, boolean varArgs) { + static List<SingleDynamicMethod> getMaximallySpecificMethods(final List<SingleDynamicMethod> methods, final boolean varArgs) { return getMaximallySpecificSingleDynamicMethods(methods, varArgs, null, null); } @@ -116,7 +116,7 @@ private static final MethodTypeGetter<MethodHandle> METHOD_HANDLE_TYPE_GETTER = new MethodTypeGetter<MethodHandle>() { @Override - MethodType getMethodType(MethodHandle t) { + MethodType getMethodType(final MethodHandle t) { return t.type(); } }; @@ -124,7 +124,7 @@ private static final MethodTypeGetter<SingleDynamicMethod> DYNAMIC_METHOD_TYPE_GETTER = new MethodTypeGetter<SingleDynamicMethod>() { @Override - MethodType getMethodType(SingleDynamicMethod t) { + MethodType getMethodType(final SingleDynamicMethod t) { return t.getMethodType(); } }; @@ -138,8 +138,8 @@ * @param argTypes concrete argument types for the invocation * @return the list of maximally specific method handles. */ - static List<MethodHandle> getMaximallySpecificMethodHandles(List<MethodHandle> methods, boolean varArgs, - Class<?>[] argTypes, LinkerServices ls) { + static List<MethodHandle> getMaximallySpecificMethodHandles(final List<MethodHandle> methods, final boolean varArgs, + final Class<?>[] argTypes, final LinkerServices ls) { return getMaximallySpecificMethods(methods, varArgs, argTypes, ls, METHOD_HANDLE_TYPE_GETTER); } @@ -152,8 +152,8 @@ * @param argTypes concrete argument types for the invocation * @return the list of maximally specific methods. */ - static List<SingleDynamicMethod> getMaximallySpecificSingleDynamicMethods(List<SingleDynamicMethod> methods, - boolean varArgs, Class<?>[] argTypes, LinkerServices ls) { + static List<SingleDynamicMethod> getMaximallySpecificSingleDynamicMethods(final List<SingleDynamicMethod> methods, + final boolean varArgs, final Class<?>[] argTypes, final LinkerServices ls) { return getMaximallySpecificMethods(methods, varArgs, argTypes, ls, DYNAMIC_METHOD_TYPE_GETTER); } @@ -166,16 +166,16 @@ * @param argTypes concrete argument types for the invocation * @return the list of maximally specific methods. */ - private static <T> List<T> getMaximallySpecificMethods(List<T> methods, boolean varArgs, - Class<?>[] argTypes, LinkerServices ls, MethodTypeGetter<T> methodTypeGetter) { + private static <T> List<T> getMaximallySpecificMethods(final List<T> methods, final boolean varArgs, + final Class<?>[] argTypes, final LinkerServices ls, final MethodTypeGetter<T> methodTypeGetter) { if(methods.size() < 2) { return methods; } final LinkedList<T> maximals = new LinkedList<>(); - for(T m: methods) { + for(final T m: methods) { final MethodType methodType = methodTypeGetter.getMethodType(m); boolean lessSpecific = false; - for(Iterator<T> maximal = maximals.iterator(); maximal.hasNext();) { + for(final Iterator<T> maximal = maximals.iterator(); maximal.hasNext();) { final T max = maximal.next(); switch(isMoreSpecific(methodType, methodTypeGetter.getMethodType(max), varArgs, argTypes, ls)) { case TYPE_1_BETTER: { @@ -202,8 +202,8 @@ return maximals; } - private static Comparison isMoreSpecific(MethodType t1, MethodType t2, boolean varArgs, Class<?>[] argTypes, - LinkerServices ls) { + private static Comparison isMoreSpecific(final MethodType t1, final MethodType t2, final boolean varArgs, final Class<?>[] argTypes, + final LinkerServices ls) { final int pc1 = t1.parameterCount(); final int pc2 = t2.parameterCount(); assert varArgs || (pc1 == pc2) && (argTypes == null || argTypes.length == pc1); @@ -241,7 +241,7 @@ return Comparison.INDETERMINATE; } - private static Comparison compare(Class<?> c1, Class<?> c2, Class<?>[] argTypes, int i, LinkerServices cmp) { + private static Comparison compare(final Class<?> c1, final Class<?> c2, final Class<?>[] argTypes, final int i, final LinkerServices cmp) { if(cmp != null) { final Comparison c = cmp.compareConversion(argTypes[i], c1, c2); if(c != Comparison.INDETERMINATE) { @@ -256,7 +256,7 @@ return Comparison.INDETERMINATE; } - private static Class<?> getParameterClass(MethodType t, int l, int i, boolean varArgs) { + private static Class<?> getParameterClass(final MethodType t, final int l, final int i, final boolean varArgs) { return varArgs && i >= l - 1 ? t.parameterType(l - 1).getComponentType() : t.parameterType(i); } }
--- a/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java Thu Jun 05 19:38:45 2014 -0700 @@ -115,20 +115,20 @@ * @param clazz the class this method belongs to * @param name the name of the method */ - OverloadedDynamicMethod(Class<?> clazz, String name) { + OverloadedDynamicMethod(final Class<?> clazz, final String name) { this(new LinkedList<SingleDynamicMethod>(), clazz.getClassLoader(), getClassAndMethodName(clazz, name)); } - private OverloadedDynamicMethod(LinkedList<SingleDynamicMethod> methods, ClassLoader classLoader, String name) { + private OverloadedDynamicMethod(final LinkedList<SingleDynamicMethod> methods, final ClassLoader classLoader, final String name) { super(name); this.methods = methods; this.classLoader = classLoader; } @Override - SingleDynamicMethod getMethodForExactParamTypes(String paramTypes) { + SingleDynamicMethod getMethodForExactParamTypes(final String paramTypes) { final LinkedList<SingleDynamicMethod> matchingMethods = new LinkedList<>(); - for(SingleDynamicMethod method: methods) { + for(final SingleDynamicMethod method: methods) { final SingleDynamicMethod matchingMethod = method.getMethodForExactParamTypes(paramTypes); if(matchingMethod != null) { matchingMethods.add(matchingMethod); @@ -148,7 +148,6 @@ } } - @SuppressWarnings("fallthrough") @Override public MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) { final MethodType callSiteType = callSiteDescriptor.getMethodType(); @@ -207,7 +206,7 @@ case 1: { // Very lucky, we ended up with a single candidate method handle based on the call site signature; we // can link it very simply by delegating to the SingleDynamicMethod. - invokables.iterator().next().getInvocation(callSiteDescriptor, linkerServices); + return invokables.iterator().next().getInvocation(callSiteDescriptor, linkerServices); } default: { // We have more than one candidate. We have no choice but to link to a method that resolves overloads on @@ -218,7 +217,7 @@ // has an already determined Lookup. final List<MethodHandle> methodHandles = new ArrayList<>(invokables.size()); final MethodHandles.Lookup lookup = callSiteDescriptor.getLookup(); - for(SingleDynamicMethod method: invokables) { + for(final SingleDynamicMethod method: invokables) { methodHandles.add(method.getTarget(lookup)); } return new OverloadedMethod(methodHandles, this, callSiteType, linkerServices).getInvoker(); @@ -228,8 +227,8 @@ } @Override - public boolean contains(SingleDynamicMethod m) { - for(SingleDynamicMethod method: methods) { + public boolean contains(final SingleDynamicMethod m) { + for(final SingleDynamicMethod method: methods) { if(method.contains(m)) { return true; } @@ -241,8 +240,8 @@ return classLoader; } - private static boolean isApplicableDynamically(LinkerServices linkerServices, MethodType callSiteType, - SingleDynamicMethod m) { + private static boolean isApplicableDynamically(final LinkerServices linkerServices, final MethodType callSiteType, + final SingleDynamicMethod m) { final MethodType methodType = m.getMethodType(); final boolean varArgs = m.isVarArgs(); final int fixedArgLen = methodType.parameterCount() - (varArgs ? 1 : 0); @@ -288,13 +287,13 @@ return true; } - private static boolean isApplicableDynamically(LinkerServices linkerServices, Class<?> callSiteType, - Class<?> methodType) { + private static boolean isApplicableDynamically(final LinkerServices linkerServices, final Class<?> callSiteType, + final Class<?> methodType) { return TypeUtilities.isPotentiallyConvertible(callSiteType, methodType) || linkerServices.canConvert(callSiteType, methodType); } - private ApplicableOverloadedMethods getApplicables(MethodType callSiteType, ApplicabilityTest test) { + private ApplicableOverloadedMethods getApplicables(final MethodType callSiteType, final ApplicabilityTest test) { return new ApplicableOverloadedMethods(methods, callSiteType, test); } @@ -303,7 +302,7 @@ * * @param method a method to add */ - public void addMethod(SingleDynamicMethod method) { + public void addMethod(final SingleDynamicMethod method) { methods.add(method); } }
--- a/src/jdk/internal/dynalink/beans/OverloadedMethod.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/OverloadedMethod.java Thu Jun 05 19:38:45 2014 -0700 @@ -93,6 +93,7 @@ import java.util.concurrent.ConcurrentHashMap; import jdk.internal.dynalink.linker.LinkerServices; import jdk.internal.dynalink.support.Lookup; +import jdk.internal.dynalink.support.TypeUtilities; /** * Represents a subset of overloaded methods for a certain method name on a certain class. It can be either a fixarg or @@ -111,16 +112,18 @@ private final ArrayList<MethodHandle> fixArgMethods; private final ArrayList<MethodHandle> varArgMethods; - OverloadedMethod(List<MethodHandle> methodHandles, OverloadedDynamicMethod parent, MethodType callSiteType, - LinkerServices linkerServices) { + OverloadedMethod(final List<MethodHandle> methodHandles, final OverloadedDynamicMethod parent, final MethodType callSiteType, + final LinkerServices linkerServices) { this.parent = parent; - this.callSiteType = callSiteType; + final Class<?> commonRetType = getCommonReturnType(methodHandles); + this.callSiteType = callSiteType.changeReturnType(commonRetType); this.linkerServices = linkerServices; fixArgMethods = new ArrayList<>(methodHandles.size()); varArgMethods = new ArrayList<>(methodHandles.size()); final int argNum = callSiteType.parameterCount(); for(MethodHandle mh: methodHandles) { + mh = mh.asType(mh.type().changeReturnType(commonRetType)); if(mh.isVarargsCollector()) { final MethodHandle asFixed = mh.asFixedArity(); if(argNum == asFixed.type().parameterCount()) { @@ -137,7 +140,7 @@ final MethodHandle bound = SELECT_METHOD.bindTo(this); final MethodHandle collecting = SingleDynamicMethod.collectArguments(bound, argNum).asType( callSiteType.changeReturnType(MethodHandle.class)); - invoker = MethodHandles.foldArguments(MethodHandles.exactInvoker(callSiteType), collecting); + invoker = MethodHandles.foldArguments(MethodHandles.exactInvoker(this.callSiteType), collecting); } MethodHandle getInvoker() { @@ -148,7 +151,7 @@ MethodHandle.class, Object[].class); @SuppressWarnings("unused") - private MethodHandle selectMethod(Object[] args) throws NoSuchMethodException { + private MethodHandle selectMethod(final Object[] args) throws NoSuchMethodException { final Class<?>[] argTypes = new Class[args.length]; for(int i = 0; i < argTypes.length; ++i) { final Object arg = args[i]; @@ -185,7 +188,7 @@ return method; } - private MethodHandle getNoSuchMethodThrower(Class<?>[] argTypes) { + private MethodHandle getNoSuchMethodThrower(final Class<?>[] argTypes) { return adaptThrower(MethodHandles.insertArguments(THROW_NO_SUCH_METHOD, 0, this, argTypes)); } @@ -193,7 +196,7 @@ "throwNoSuchMethod", void.class, Class[].class); @SuppressWarnings("unused") - private void throwNoSuchMethod(Class<?>[] argTypes) throws NoSuchMethodException { + private void throwNoSuchMethod(final Class<?>[] argTypes) throws NoSuchMethodException { if(varArgMethods.isEmpty()) { throw new NoSuchMethodException("None of the fixed arity signatures " + getSignatureList(fixArgMethods) + " of method " + parent.getName() + " match the argument types " + argTypesString(argTypes)); @@ -203,11 +206,11 @@ parent.getName() + " match the argument types " + argTypesString(argTypes)); } - private MethodHandle getAmbiguousMethodThrower(Class<?>[] argTypes, List<MethodHandle> methods) { + private MethodHandle getAmbiguousMethodThrower(final Class<?>[] argTypes, final List<MethodHandle> methods) { return adaptThrower(MethodHandles.insertArguments(THROW_AMBIGUOUS_METHOD, 0, this, argTypes, methods)); } - private MethodHandle adaptThrower(MethodHandle rawThrower) { + private MethodHandle adaptThrower(final MethodHandle rawThrower) { return MethodHandles.dropArguments(rawThrower, 0, callSiteType.parameterList()).asType(callSiteType); } @@ -215,20 +218,20 @@ "throwAmbiguousMethod", void.class, Class[].class, List.class); @SuppressWarnings("unused") - private void throwAmbiguousMethod(Class<?>[] argTypes, List<MethodHandle> methods) throws NoSuchMethodException { + private void throwAmbiguousMethod(final Class<?>[] argTypes, final List<MethodHandle> methods) throws NoSuchMethodException { final String arity = methods.get(0).isVarargsCollector() ? "variable" : "fixed"; throw new NoSuchMethodException("Can't unambiguously select between " + arity + " arity signatures " + getSignatureList(methods) + " of the method " + parent.getName() + " for argument types " + argTypesString(argTypes)); } - private static String argTypesString(Class<?>[] classes) { + private static String argTypesString(final Class<?>[] classes) { final StringBuilder b = new StringBuilder().append('['); appendTypes(b, classes, false); return b.append(']').toString(); } - private static String getSignatureList(List<MethodHandle> methods) { + private static String getSignatureList(final List<MethodHandle> methods) { final StringBuilder b = new StringBuilder().append('['); final Iterator<MethodHandle> it = methods.iterator(); if(it.hasNext()) { @@ -240,13 +243,13 @@ return b.append(']').toString(); } - private static void appendSig(StringBuilder b, MethodHandle m) { + private static void appendSig(final StringBuilder b, final MethodHandle m) { b.append('('); appendTypes(b, m.type().parameterArray(), m.isVarargsCollector()); b.append(')'); } - private static void appendTypes(StringBuilder b, Class<?>[] classes, boolean varArg) { + private static void appendTypes(final StringBuilder b, final Class<?>[] classes, final boolean varArg) { final int l = classes.length; if(!varArg) { if(l > 1) { @@ -262,4 +265,13 @@ b.append(classes[l - 1].getComponentType().getCanonicalName()).append("..."); } } + + private static Class<?> getCommonReturnType(final List<MethodHandle> methodHandles) { + final Iterator<MethodHandle> it = methodHandles.iterator(); + Class<?> retType = it.next().type().returnType(); + while(it.hasNext()) { + retType = TypeUtilities.getCommonLosslessConversionType(retType, it.next().type().returnType()); + } + return retType; + } }
--- a/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java Thu Jun 05 19:38:45 2014 -0700 @@ -107,12 +107,12 @@ * @param clazz the class declaring the method * @param name the simple name of the method */ - SimpleDynamicMethod(MethodHandle target, Class<?> clazz, String name) { + SimpleDynamicMethod(final MethodHandle target, final Class<?> clazz, final String name) { super(getName(target, clazz, name)); this.target = target; } - private static String getName(MethodHandle target, Class<?> clazz, String name) { + private static String getName(final MethodHandle target, final Class<?> clazz, final String name) { return getMethodNameWithSignature(target.type(), getClassAndMethodName(clazz, name)); } @@ -127,7 +127,7 @@ } @Override - MethodHandle getTarget(Lookup lookup) { + MethodHandle getTarget(final Lookup lookup) { return target; } }
--- a/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java Thu Jun 05 19:38:45 2014 -0700 @@ -104,7 +104,7 @@ private static final MethodHandle CAN_CONVERT_TO = Lookup.findOwnStatic(MethodHandles.lookup(), "canConvertTo", boolean.class, LinkerServices.class, Class.class, Object.class); - SingleDynamicMethod(String name) { + SingleDynamicMethod(final String name) { super(name); } @@ -128,22 +128,22 @@ abstract MethodHandle getTarget(MethodHandles.Lookup lookup); @Override - MethodHandle getInvocation(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) { + MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) { return getInvocation(getTarget(callSiteDescriptor.getLookup()), callSiteDescriptor.getMethodType(), linkerServices); } @Override - SingleDynamicMethod getMethodForExactParamTypes(String paramTypes) { + SingleDynamicMethod getMethodForExactParamTypes(final String paramTypes) { return typeMatchesDescription(paramTypes, getMethodType()) ? this : null; } @Override - boolean contains(SingleDynamicMethod method) { + boolean contains(final SingleDynamicMethod method) { return getMethodType().parameterList().equals(method.getMethodType().parameterList()); } - static String getMethodNameWithSignature(MethodType type, String methodName) { + static String getMethodNameWithSignature(final MethodType type, final String methodName) { final String typeStr = type.toString(); final int retTypeIndex = typeStr.lastIndexOf(')') + 1; int secondParamIndex = typeStr.indexOf(',') + 1; @@ -156,13 +156,15 @@ /** * Given a method handle and a call site type, adapts the method handle to the call site type. Performs type * conversions as needed using the specified linker services, and in case that the method handle is a vararg - * collector, matches it to the arity of the call site. + * collector, matches it to the arity of the call site. The type of the return value is only changed if it can be + * converted using a conversion that loses neither precision nor magnitude, see + * {@link LinkerServices#asTypeLosslessReturn(MethodHandle, MethodType)}. * @param target the method handle to adapt * @param callSiteType the type of the call site * @param linkerServices the linker services used for type conversions * @return the adapted method handle. */ - static MethodHandle getInvocation(MethodHandle target, MethodType callSiteType, LinkerServices linkerServices) { + static MethodHandle getInvocation(final MethodHandle target, final MethodType callSiteType, final LinkerServices linkerServices) { final MethodType methodType = target.type(); final int paramsLen = methodType.parameterCount(); final boolean varArgs = target.isVarargsCollector(); @@ -264,7 +266,7 @@ } @SuppressWarnings("unused") - private static boolean canConvertTo(final LinkerServices linkerServices, Class<?> to, Object obj) { + private static boolean canConvertTo(final LinkerServices linkerServices, final Class<?> to, final Object obj) { return obj == null ? false : linkerServices.canConvert(obj.getClass(), to); } @@ -277,7 +279,7 @@ * @param parameterCount the total number of arguments in the new method handle * @return a collecting method handle */ - static MethodHandle collectArguments(MethodHandle target, final int parameterCount) { + static MethodHandle collectArguments(final MethodHandle target, final int parameterCount) { final MethodType methodType = target.type(); final int fixParamsLen = methodType.parameterCount() - 1; final Class<?> arrayType = methodType.parameterType(fixParamsLen); @@ -286,10 +288,10 @@ private static MethodHandle createConvertingInvocation(final MethodHandle sizedMethod, final LinkerServices linkerServices, final MethodType callSiteType) { - return linkerServices.asType(sizedMethod, callSiteType); + return linkerServices.asTypeLosslessReturn(sizedMethod, callSiteType); } - private static boolean typeMatchesDescription(String paramTypes, MethodType type) { + private static boolean typeMatchesDescription(final String paramTypes, final MethodType type) { final StringTokenizer tok = new StringTokenizer(paramTypes, ", "); for(int i = 1; i < type.parameterCount(); ++i) { // i = 1 as we ignore the receiver if(!(tok.hasMoreTokens() && typeNameMatches(tok.nextToken(), type.parameterType(i)))) { @@ -299,7 +301,7 @@ return !tok.hasMoreTokens(); } - private static boolean typeNameMatches(String typeName, Class<?> type) { + private static boolean typeNameMatches(final String typeName, final Class<?> type) { return typeName.equals(typeName.indexOf('.') == -1 ? type.getSimpleName() : type.getCanonicalName()); } }
--- a/src/jdk/internal/dynalink/beans/StaticClass.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/StaticClass.java Thu Jun 05 19:38:45 2014 -0700 @@ -96,7 +96,7 @@ public class StaticClass implements Serializable { private static final ClassValue<StaticClass> staticClasses = new ClassValue<StaticClass>() { @Override - protected StaticClass computeValue(Class<?> type) { + protected StaticClass computeValue(final Class<?> type) { return new StaticClass(type); } }; @@ -105,7 +105,7 @@ private final Class<?> clazz; - /*private*/ StaticClass(Class<?> clazz) { + /*private*/ StaticClass(final Class<?> clazz) { clazz.getClass(); // NPE check this.clazz = clazz; } @@ -115,7 +115,7 @@ * @param clazz the class for which the static facet is requested. * @return the {@link StaticClass} instance representing the specified class. */ - public static StaticClass forClass(Class<?> clazz) { + public static StaticClass forClass(final Class<?> clazz) { return staticClasses.get(clazz); }
--- a/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java Thu Jun 05 19:38:45 2014 -0700 @@ -90,14 +90,14 @@ import java.util.Map; class StaticClassIntrospector extends FacetIntrospector { - StaticClassIntrospector(Class<?> clazz) { + StaticClassIntrospector(final Class<?> clazz) { super(clazz, false); } @Override Map<String, MethodHandle> getInnerClassGetters() { final Map<String, MethodHandle> map = new HashMap<>(); - for(Class<?> innerClass: membersLookup.getInnerClasses()) { + for(final Class<?> innerClass: membersLookup.getInnerClasses()) { map.put(innerClass.getSimpleName(), editMethodHandle(MethodHandles.constant(StaticClass.class, StaticClass.forClass(innerClass)))); } @@ -105,15 +105,15 @@ } @Override - MethodHandle editMethodHandle(MethodHandle mh) { + MethodHandle editMethodHandle(final MethodHandle mh) { return editStaticMethodHandle(mh); } - static MethodHandle editStaticMethodHandle(MethodHandle mh) { + static MethodHandle editStaticMethodHandle(final MethodHandle mh) { return dropReceiver(mh, Object.class); } - static MethodHandle editConstructorMethodHandle(MethodHandle cmh) { + static MethodHandle editConstructorMethodHandle(final MethodHandle cmh) { return dropReceiver(cmh, StaticClass.class); }
--- a/src/jdk/internal/dynalink/beans/StaticClassLinker.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/beans/StaticClassLinker.java Thu Jun 05 19:38:45 2014 -0700 @@ -104,7 +104,7 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker { private static final ClassValue<SingleClassStaticsLinker> linkers = new ClassValue<SingleClassStaticsLinker>() { @Override - protected SingleClassStaticsLinker computeValue(Class<?> clazz) { + protected SingleClassStaticsLinker computeValue(final Class<?> clazz) { return new SingleClassStaticsLinker(clazz); } }; @@ -112,7 +112,7 @@ private static class SingleClassStaticsLinker extends AbstractJavaLinker { private final DynamicMethod constructor; - SingleClassStaticsLinker(Class<?> clazz) { + SingleClassStaticsLinker(final Class<?> clazz) { super(clazz, IS_CLASS.bindTo(clazz)); // Map "staticClassObject.class" to StaticClass.getRepresentedClass(). Some adventurous soul could subclass // StaticClass, so we use INSTANCE_OF validation instead of EXACT_CLASS. @@ -126,7 +126,7 @@ * @return a dynamic method containing all overloads of a class' public constructor. If the class has no public * constructors, returns null. */ - private static DynamicMethod createConstructorMethod(Class<?> clazz) { + private static DynamicMethod createConstructorMethod(final Class<?> clazz) { if(clazz.isArray()) { final MethodHandle boundArrayCtor = ARRAY_CTOR.bindTo(clazz.getComponentType()); return new SimpleDynamicMethod(StaticClassIntrospector.editConstructorMethodHandle( @@ -144,7 +144,7 @@ } @Override - public GuardedInvocation getGuardedInvocation(LinkRequest request, LinkerServices linkerServices) + public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices) throws Exception { final GuardedInvocation gi = super.getGuardedInvocation(request, linkerServices); if(gi != null) { @@ -162,20 +162,20 @@ } } - static Collection<String> getReadableStaticPropertyNames(Class<?> clazz) { + static Collection<String> getReadableStaticPropertyNames(final Class<?> clazz) { return linkers.get(clazz).getReadablePropertyNames(); } - static Collection<String> getWritableStaticPropertyNames(Class<?> clazz) { + static Collection<String> getWritableStaticPropertyNames(final Class<?> clazz) { return linkers.get(clazz).getWritablePropertyNames(); } - static Collection<String> getStaticMethodNames(Class<?> clazz) { + static Collection<String> getStaticMethodNames(final Class<?> clazz) { return linkers.get(clazz).getMethodNames(); } @Override - public GuardedInvocation getGuardedInvocation(LinkRequest request, LinkerServices linkerServices) throws Exception { + public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices) throws Exception { final Object receiver = request.getReceiver(); if(receiver instanceof StaticClass) { return linkers.get(((StaticClass)receiver).getRepresentedClass()).getGuardedInvocation(request, @@ -185,7 +185,7 @@ } @Override - public boolean canLinkType(Class<?> type) { + public boolean canLinkType(final Class<?> type) { return type == StaticClass.class; } @@ -201,7 +201,7 @@ } @SuppressWarnings("unused") - private static boolean isClass(Class<?> clazz, Object obj) { + private static boolean isClass(final Class<?> clazz, final Object obj) { return obj instanceof StaticClass && ((StaticClass)obj).getRepresentedClass() == clazz; } }
--- a/src/jdk/internal/dynalink/linker/GuardedInvocation.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/linker/GuardedInvocation.java Thu Jun 05 19:38:45 2014 -0700 @@ -83,6 +83,8 @@ package jdk.internal.dynalink.linker; +import static jdk.nashorn.internal.lookup.Lookup.MH; + import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -104,7 +106,18 @@ public class GuardedInvocation { private final MethodHandle invocation; private final MethodHandle guard; - private final SwitchPoint switchPoint; + private final Class<? extends Throwable> exception; + private final SwitchPoint[] switchPoints; + + /** + * Creates a new guarded invocation. This invocation is unconditional as it has no invalidations. + * + * @param invocation the method handle representing the invocation. Must not be null. + * @throws NullPointerException if invocation is null. + */ + public GuardedInvocation(final MethodHandle invocation) { + this(invocation, null, (SwitchPoint)null, null); + } /** * Creates a new guarded invocation. @@ -115,8 +128,19 @@ * an unconditional invocation, although that is unusual. * @throws NullPointerException if invocation is null. */ - public GuardedInvocation(MethodHandle invocation, MethodHandle guard) { - this(invocation, guard, null); + public GuardedInvocation(final MethodHandle invocation, final MethodHandle guard) { + this(invocation, guard, (SwitchPoint)null, null); + } + + /** + * Creates a new guarded invocation. + * + * @param invocation the method handle representing the invocation. Must not be null. + * @param switchPoint the optional switch point that can be used to invalidate this linkage. + * @throws NullPointerException if invocation is null. + */ + public GuardedInvocation(final MethodHandle invocation, final SwitchPoint switchPoint) { + this(invocation, null, switchPoint, null); } /** @@ -129,26 +153,50 @@ * @param switchPoint the optional switch point that can be used to invalidate this linkage. * @throws NullPointerException if invocation is null. */ - public GuardedInvocation(MethodHandle invocation, MethodHandle guard, SwitchPoint switchPoint) { - invocation.getClass(); // NPE check - this.invocation = invocation; - this.guard = guard; - this.switchPoint = switchPoint; + public GuardedInvocation(final MethodHandle invocation, final MethodHandle guard, final SwitchPoint switchPoint) { + this(invocation, guard, switchPoint, null); } /** * Creates a new guarded invocation. * * @param invocation the method handle representing the invocation. Must not be null. - * @param switchPoint the optional switch point that can be used to invalidate this linkage. * @param guard the method handle representing the guard. Must have the same method type as the invocation, except * it must return boolean. For some useful guards, check out the {@link Guards} class. It can be null. If both it * and the switch point are null, this represents an unconditional invocation, which is legal but unusual. + * @param switchPoint the optional switch point that can be used to invalidate this linkage. + * @param exception the optional exception type that is expected to be thrown by the invocation and that also + * invalidates the linkage. * @throws NullPointerException if invocation is null. */ - public GuardedInvocation(MethodHandle invocation, SwitchPoint switchPoint, MethodHandle guard) { - this(invocation, guard, switchPoint); + public GuardedInvocation(final MethodHandle invocation, final MethodHandle guard, final SwitchPoint switchPoint, final Class<? extends Throwable> exception) { + invocation.getClass(); // NPE check + this.invocation = invocation; + this.guard = guard; + this.switchPoints = switchPoint == null ? null : new SwitchPoint[] { switchPoint }; + this.exception = exception; } + + /** + * Creates a new guarded invocation + * + * @param invocation the method handle representing the invocation. Must not be null. + * @param guard the method handle representing the guard. Must have the same method type as the invocation, except + * it must return boolean. For some useful guards, check out the {@link Guards} class. It can be null. If both it + * and the switch point are null, this represents an unconditional invocation, which is legal but unusual. + * @param switchPoints the optional switch points that can be used to invalidate this linkage. + * @param exception the optional exception type that is expected to be thrown by the invocation and that also + * invalidates the linkage. + * @throws NullPointerException if invocation is null. + */ + public GuardedInvocation(final MethodHandle invocation, final MethodHandle guard, final SwitchPoint[] switchPoints, final Class<? extends Throwable> exception) { + invocation.getClass(); // NPE check + this.invocation = invocation; + this.guard = guard; + this.switchPoints = switchPoints; + this.exception = exception; + } + /** * Returns the invocation method handle. * @@ -172,8 +220,17 @@ * * @return the switch point that can be used to invalidate the invocation handle. Can be null. */ - public SwitchPoint getSwitchPoint() { - return switchPoint; + public SwitchPoint[] getSwitchPoints() { + return switchPoints == null ? null : switchPoints.clone(); + } + + /** + * Returns the exception type that if thrown should be used to invalidate the linkage. + * + * @return the exception type that if thrown should be used to invalidate the linkage. Can be null. + */ + public Class<? extends Throwable> getException() { + return exception; } /** @@ -181,7 +238,15 @@ * @return true if and only if this guarded invocation has a switchpoint, and that switchpoint has been invalidated. */ public boolean hasBeenInvalidated() { - return switchPoint != null && switchPoint.hasBeenInvalidated(); + if (switchPoints == null) { + return false; + } + for (final SwitchPoint sp : switchPoints) { + if (sp.hasBeenInvalidated()) { + return true; + } + } + return false; } /** @@ -191,9 +256,9 @@ * @param type the asserted type * @throws WrongMethodTypeException if the invocation and the guard are not of the expected method type. */ - public void assertType(MethodType type) { + public void assertType(final MethodType type) { assertType(invocation, type); - if(guard != null) { + if (guard != null) { assertType(guard, type.changeReturnType(Boolean.TYPE)); } } @@ -205,12 +270,34 @@ * @param newGuard the new guard * @return a new guarded invocation with the replaced methods and the same switch point as this invocation. */ - public GuardedInvocation replaceMethods(MethodHandle newInvocation, MethodHandle newGuard) { - return new GuardedInvocation(newInvocation, newGuard, switchPoint); + public GuardedInvocation replaceMethods(final MethodHandle newInvocation, final MethodHandle newGuard) { + return new GuardedInvocation(newInvocation, newGuard, switchPoints, exception); } - private GuardedInvocation replaceMethodsOrThis(MethodHandle newInvocation, MethodHandle newGuard) { - if(newInvocation == invocation && newGuard == guard) { + /** + * Add a switchpoint to this guarded invocation + * @param newSwitchPoint new switchpoint, or null for nop + * @return new guarded invocation with the extra switchpoint + */ + public GuardedInvocation addSwitchPoint(final SwitchPoint newSwitchPoint) { + if (newSwitchPoint == null) { + return this; + } + + final SwitchPoint[] newSwitchPoints; + if (switchPoints != null) { + newSwitchPoints = new SwitchPoint[switchPoints.length + 1]; + System.arraycopy(switchPoints, 0, newSwitchPoints, 0, switchPoints.length); + newSwitchPoints[switchPoints.length] = newSwitchPoint; + } else { + newSwitchPoints = new SwitchPoint[] { newSwitchPoint }; + } + + return new GuardedInvocation(invocation, guard, newSwitchPoints, exception); + } + + private GuardedInvocation replaceMethodsOrThis(final MethodHandle newInvocation, final MethodHandle newGuard) { + if (newInvocation == invocation && newGuard == guard) { return this; } return replaceMethods(newInvocation, newGuard); @@ -223,7 +310,7 @@ * @param newType the new type of the invocation. * @return a guarded invocation with the new type applied to it. */ - public GuardedInvocation asType(MethodType newType) { + public GuardedInvocation asType(final MethodType newType) { return replaceMethodsOrThis(invocation.asType(newType), guard == null ? null : Guards.asType(guard, newType)); } @@ -235,19 +322,33 @@ * @param newType the new type of the invocation. * @return a guarded invocation with the new type applied to it. */ - public GuardedInvocation asType(LinkerServices linkerServices, MethodType newType) { + public GuardedInvocation asType(final LinkerServices linkerServices, final MethodType newType) { return replaceMethodsOrThis(linkerServices.asType(invocation, newType), guard == null ? null : Guards.asType(linkerServices, guard, newType)); } /** + * Changes the type of the invocation, as if {@link LinkerServices#asTypeLosslessReturn(MethodHandle, MethodType)} was + * applied to its invocation and {@link LinkerServices#asType(MethodHandle, MethodType)} applied to its guard, if it + * has one (with return type changed to boolean, and parameter count potentially truncated for the guard). If the + * invocation doesn't change its type, returns this object. + * @param linkerServices the linker services to use for the conversion + * @param newType the new type of the invocation. + * @return a guarded invocation with the new type applied to it. + */ + public GuardedInvocation asTypeSafeReturn(final LinkerServices linkerServices, final MethodType newType) { + return replaceMethodsOrThis(linkerServices.asTypeLosslessReturn(invocation, newType), guard == null ? null : + Guards.asType(linkerServices, guard, newType)); + } + + /** * Changes the type of the invocation, as if {@link MethodHandle#asType(MethodType)} was applied to its invocation * and its guard, if it has one (with return type changed to boolean for guard). If the invocation already is of the * required type, returns this object. * @param desc a call descriptor whose method type is adapted. * @return a guarded invocation with the new type applied to it. */ - public GuardedInvocation asType(CallSiteDescriptor desc) { + public GuardedInvocation asType(final CallSiteDescriptor desc) { return asType(desc.getMethodType()); } @@ -257,7 +358,7 @@ * @param filters the argument filters * @return a filtered invocation */ - public GuardedInvocation filterArguments(int pos, MethodHandle... filters) { + public GuardedInvocation filterArguments(final int pos, final MethodHandle... filters) { return replaceMethods(MethodHandles.filterArguments(invocation, pos, filters), guard == null ? null : MethodHandles.filterArguments(guard, pos, filters)); } @@ -268,7 +369,7 @@ * @param valueTypes the types of the values being dropped * @return an invocation that drops arguments */ - public GuardedInvocation dropArguments(int pos, List<Class<?>> valueTypes) { + public GuardedInvocation dropArguments(final int pos, final List<Class<?>> valueTypes) { return replaceMethods(MethodHandles.dropArguments(invocation, pos, valueTypes), guard == null ? null : MethodHandles.dropArguments(guard, pos, valueTypes)); } @@ -279,7 +380,7 @@ * @param valueTypes the types of the values being dropped * @return an invocation that drops arguments */ - public GuardedInvocation dropArguments(int pos, Class<?>... valueTypes) { + public GuardedInvocation dropArguments(final int pos, final Class<?>... valueTypes) { return replaceMethods(MethodHandles.dropArguments(invocation, pos, valueTypes), guard == null ? null : MethodHandles.dropArguments(guard, pos, valueTypes)); } @@ -290,23 +391,50 @@ * @param fallback the fallback method handle in case switchpoint is invalidated or guard returns false. * @return a composite method handle. */ - public MethodHandle compose(MethodHandle fallback) { - return compose(fallback, fallback); + public MethodHandle compose(final MethodHandle fallback) { + return compose(fallback, fallback, fallback); } /** * Composes the invocation, switchpoint, and the guard into a composite method handle that knows how to fall back. * @param switchpointFallback the fallback method handle in case switchpoint is invalidated. * @param guardFallback the fallback method handle in case guard returns false. + * @param catchFallback the fallback method in case the exception handler triggers * @return a composite method handle. */ - public MethodHandle compose(MethodHandle switchpointFallback, MethodHandle guardFallback) { + public MethodHandle compose(final MethodHandle guardFallback, final MethodHandle switchpointFallback, final MethodHandle catchFallback) { final MethodHandle guarded = - guard == null ? invocation : MethodHandles.guardWithTest(guard, invocation, guardFallback); - return switchPoint == null ? guarded : switchPoint.guardWithTest(guarded, switchpointFallback); + guard == null ? + invocation : + MethodHandles.guardWithTest( + guard, + invocation, + guardFallback); + + final MethodHandle catchGuarded = + exception == null ? + guarded : + MH.catchException( + guarded, + exception, + MethodHandles.dropArguments( + catchFallback, + 0, + exception)); + + if (switchPoints == null) { + return catchGuarded; + } + + MethodHandle spGuarded = catchGuarded; + for (final SwitchPoint sp : switchPoints) { + spGuarded = sp.guardWithTest(spGuarded, switchpointFallback); + } + + return spGuarded; } - private static void assertType(MethodHandle mh, MethodType type) { + private static void assertType(final MethodHandle mh, final MethodType type) { if(!mh.type().equals(type)) { throw new WrongMethodTypeException("Expected type: " + type + " actual type: " + mh.type()); }
--- a/src/jdk/internal/dynalink/linker/GuardedTypeConversion.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/linker/GuardedTypeConversion.java Thu Jun 05 19:38:45 2014 -0700 @@ -83,19 +83,35 @@ package jdk.internal.dynalink.linker; +/** + * Guarded type conversion + */ public class GuardedTypeConversion { private final GuardedInvocation conversionInvocation; private final boolean cacheable; + /** + * Constructor + * @param conversionInvocation guarded invocation for this type conversion + * @param cacheable is this invocation cacheable + */ public GuardedTypeConversion(final GuardedInvocation conversionInvocation, final boolean cacheable) { this.conversionInvocation = conversionInvocation; this.cacheable = cacheable; } + /** + * Get the invocation + * @return invocation + */ public GuardedInvocation getConversionInvocation() { return conversionInvocation; } + /** + * Check if invocation is cacheable + * @return true if cachable, false otherwise + */ public boolean isCacheable() { return cacheable; }
--- a/src/jdk/internal/dynalink/linker/GuardingDynamicLinker.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/linker/GuardingDynamicLinker.java Thu Jun 05 19:38:45 2014 -0700 @@ -101,10 +101,16 @@ * @return a guarded invocation with a method handle suitable for the arguments, as well as a guard condition that * if fails should trigger relinking. Must return null if it can't resolve the invocation. If the returned * invocation is unconditional (which is actually quite rare), the guard in the return value can be null. The - * invocation can also have a switch point for asynchronous invalidation of the linkage. If the linker does not - * recognize any native language runtime contexts in arguments, or does recognize its own, but receives a call site - * descriptor without its recognized context in the arguments, it should invoke - * {@link LinkRequest#withoutRuntimeContext()} and link for that. + * invocation can also have a switch point for asynchronous invalidation of the linkage, as well as a + * {@link Throwable} subclass that describes an expected exception condition that also triggers relinking (often it + * is faster to rely on an infrequent but expected {@link ClassCastException} than on an always evaluated + * {@code instanceof} guard). If the linker does not recognize any native language runtime contexts in arguments, or + * does recognize its own, but receives a call site descriptor without its recognized context in the arguments, it + * should invoke {@link LinkRequest#withoutRuntimeContext()} and link for that. While the linker must produce an + * invocation with parameter types matching those in the call site descriptor of the link request, it should not try + * to match the return type expected at the call site except when it can do it with only the conversions that lose + * neither precision nor magnitude, see {@link LinkerServices#asTypeLosslessReturn(java.lang.invoke.MethodHandle, + * java.lang.invoke.MethodType)}. * @throws Exception if the operation fails for whatever reason */ public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, LinkerServices linkerServices)
--- a/src/jdk/internal/dynalink/linker/LinkRequest.java Wed Jun 04 20:20:44 2014 -0700 +++ b/src/jdk/internal/dynalink/linker/LinkRequest.java Thu Jun 05 19:38:45 2014 -0700 @@ -101,6 +101,17 @@ public CallSiteDescriptor getCallSiteDescriptor(); /** + * Returns the call site token for the call site being linked. This token is an opaque object that is guaranteed to + * have different identity for different call sites, and is also guaranteed to not become weakly reachable before + * the call site does and to become weakly reachable some time after the call site does. This makes it ideal as a + * candidate for a key in a weak hash map in which a linker might want to keep per-call site linking state (usually + * profiling information). + * + * @return the call site token for the call site being linked. + */ + public Object getCallSiteToken(); + + /** * Returns the arguments for the invocation being linked. The returned array is a clone; modifications to it won't * affect the arguments in this request. * @@ -116,6 +127,17 @@ public Object getReceiver(); /** + * Returns the number of times this callsite has been linked/relinked. This can be useful if you want to + * change e.g. exception based relinking to guard based relinking. It's probably not a good idea to keep, + * for example, expensive exception throwing relinkage based on failed type checks/ClassCastException in + * a nested callsite tree where the exception is thrown repeatedly for the common case. There it would be + * much more performant to use exact type guards instead. + * + * @return link count for call site