This commit is contained in:
Lana Steuck 2014-06-05 19:38:45 -07:00
commit 250d670627
1395 changed files with 40045 additions and 20110 deletions

View File

@ -13,6 +13,8 @@ webrev.zip
*.clazz
*.log
*.orig
*.rej
*~
genfiles.properties
hotspot.log
.DS_Store*

View File

@ -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"

View File

@ -22,9 +22,16 @@
# questions.
#
#convert tabs to spaces
find . -name "*.java" -exec sed -i "" 's/ / /g' {} \;
#remove trailing whitespace
find . -name "*.java" -exec sed -i "" 's/[ ]*$//' \{} \;
fix() {
#convert tabs to spaces
find . -name $1 -exec sed -i "" 's/ / /g' {} \;
#remove trailing whitespace
find . -name $1 -exec sed -i "" 's/[ ]*$//' \{} \;
}
if [ ! -z $1 ]; then
fix $1;
else
fix "*.java"
fix "*.js"
fi

51
nashorn/bin/run_octane.sh Normal file
View File

@ -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

25
nashorn/bin/rundiff.sh Normal file
View File

@ -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

110
nashorn/bin/runopt.sh Normal file
View File

@ -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

View File

@ -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 \

View File

@ -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 \

View File

@ -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

View File

@ -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"

View File

@ -31,29 +31,29 @@ import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
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;

View File

@ -32,9 +32,9 @@ import static jdk.internal.org.objectweb.asm.Opcodes.V1_7;
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;

View File

@ -319,7 +319,7 @@ public final class MemberInfo implements Cloneable {
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 @@ public final class MemberInfo implements Cloneable {
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 @@ public final class MemberInfo implements Cloneable {
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;

View File

@ -413,7 +413,8 @@ public class MethodGenerator extends MethodVisitor {
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 @@ public class MethodGenerator extends MethodVisitor {
super.visitMethodInsn(INVOKEVIRTUAL,
"java/io/PrintStream",
"println",
"(Ljava/lang/Object;)V", false);
"(Ljava/lang/Object;)V",
false);
}
}

View File

@ -31,9 +31,9 @@ import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;
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;

View File

@ -26,9 +26,8 @@
package jdk.nashorn.internal.tools.nasgen;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import jdk.internal.org.objectweb.asm.Type;

View File

@ -737,26 +737,6 @@ an implementation based on Joni, the regular expression engine used by
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 @@ etc. It will also show the internal representation of respective field
(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 @@ A short summary follows:
-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 @@ A short summary follows:
-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 @@ A short summary follows:
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 @@ A short summary follows:
--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 @@ A short summary follows:
--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 @@ A short summary follows:
-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 @@ A short summary follows:
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.)

View File

@ -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.
-->
<project name="nashorn-benchmarks" default="all" basedir="..">
<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"/>
</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>
<!--
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=".."
xmlns:if="ant:if">
<!--
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="jar">
<antcall target="run-octane">
<param name="octane-tests" value="box2d"/>
</antcall>
<target name="octane-box2d" depends="octane-box2d-nashorn"/>
<target name="octane-box2d-nashorn" depends="jar">
<run-one cond="octane.benchmark.box2d" runtime="nashorn"/>
</target>
<target name="octane-box2d-v8" depends="jar">
<antcall target="run-octane-v8">
<param name="octane-tests" value="box2d"/>
</antcall>
<run-one cond="octane.benchmark.box2d" runtime="v8"/>
</target>
<target name="octane-box2d-rhino" depends="jar">
<antcall target="run-octane-rhino">
<param name="octane-tests" value="box2d"/>
</antcall>
<run-one cond="octane.benchmark.box2d" runtime="rhino"/>
</target>
<!-- code-load -->
<target name="octane-code-load" depends="jar">
<antcall target="run-octane">
<param name="octane-tests" value="code-load"/>
</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">
<antcall target="run-octane-v8">
<param name="octane-tests" value="code-load"/>
</antcall>
<run-one cond="octane.benchmark.code-load" runtime="v8"/>
</target>
<target name="octane-code-load-rhino" depends="jar">
<antcall target="run-octane-rhino">
<param name="octane-tests" value="code-load"/>
</antcall>
<run-one cond="octane.benchmark.code-load" runtime="rhino"/>
</target>
<!-- crypto -->
<target name="octane-crypto" depends="jar">
<antcall target="run-octane">
<param name="octane-tests" value="crypto"/>
</antcall>
<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">
<antcall target="run-octane-v8">
<param name="octane-tests" value="crypto"/>
</antcall>
<run-one cond="octane.benchmark.crypto" runtime="v8"/>
</target>
<target name="octane-crypto-rhino" depends="jar">
<antcall target="run-octane-rhino">
<param name="octane-tests" value="crypto"/>
</antcall>
<run-one cond="octane.benchmark.crypto" runtime="rhino"/>
</target>
<!-- deltablue -->
<target name="octane-deltablue" depends="jar">
<antcall target="run-octane">
<param name="octane-tests" value="deltablue"/>
</antcall>
<target name="octane-deltablue" depends="octane-deltablue-nashorn"/>
<target name="octane-deltablue-nashorn" depends="jar">
<run-one cond="octane.benchmark.deltablue" runtime="nashorn"/>
</target>
<target name="octane-deltablue-v8" depends="jar">
<antcall target="run-octane-v8">
<param name="octane-tests" value="deltablue"/>
</antcall>
<run-one cond="octane.benchmark.deltablue" runtime="v8"/>
</target>
<target name="octane-deltablue-rhino" depends="jar">
<antcall target="run-octane-rhino">
<param name="octane-tests" value="deltablue"/>
</antcall>
<run-one cond="octane.benchmark.deltablue" runtime="rhino"/>
</target>
<!-- earley-boyer -->
<target name="octane-earley-boyer" depends="jar">
<antcall target="run-octane">
<param name="octane-tests" value="earley-boyer"/>
</antcall>
<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">
<antcall target="run-octane-v8">
<param name="octane-tests" value="earley-boyer"/>
</antcall>
<run-one cond="octane.benchmark.earley-boyer" runtime="v8"/>
</target>
<target name="octane-earley-boyer-rhino" depends="jar">
<antcall target="run-octane-rhino">
<param name="octane-tests" value="earley-boyer"/>
</antcall>
<run-one cond="octane.benchmark.earley-boyer" runtime="rhino"/>
</target>
<!-- gbemu -->
<target name="octane-gbemu" depends="jar">
<antcall target="run-octane">
<param name="octane-tests" value="gbemu"/>
</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">
<antcall target="run-octane-v8">
<param name="octane-tests" value="gbemu"/>
</antcall>
<run-one cond="octane.benchmark.gbemu" runtime="v8"/>
</target>
<target name="octane-gbemu-rhino" depends="jar">
<antcall target="run-octane-rhino">
<param name="octane-tests" value="gbemu"/>
</antcall>
<run-one cond="octane.benchmark.gbemu" runtime="rhino"/>
</target>
<!-- mandreel -->
<target name="octane-mandreel" depends="jar">
<antcall target="run-octane">
<param name="octane-tests" value="mandreel"/>
</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">
<antcall target="run-octane-v8">
<param name="octane-tests" value="mandreel"/>
</antcall>
<run-one cond="octane.benchmark.mandreel" runtime="v8"/>
</target>
<target name="octane-mandreel-rhino" depends="jar">
<antcall target="run-octane-rhino">
<param name="octane-tests" value="mandreel"/>
</antcall>
<run-one cond="octane.benchmark.mandreel" runtime="rhino"/>
</target>
<!-- navier-stokes -->
<target name="octane-navier-stokes" depends="jar">
<antcall target="run-octane">
<param name="octane-tests" value="navier-stokes"/>
</antcall>
<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">
<antcall target="run-octane-v8">
<param name="octane-tests" value="navier-stokes"/>
</antcall>
<run-one cond="octane.benchmark.navier-stokes" runtime="v8"/>
</target>
<target name="octane-navier-stokes-rhino" depends="jar">
<antcall target="run-octane-rhino">
<param name="octane-tests" value="navier-stokes"/>
</antcall>
<run-one cond="octane.benchmark.navier-stokes" runtime="rhino"/>
</target>
<!-- pdfjs -->
<target name="octane-pdfjs" depends="jar">
<antcall target="run-octane">
<param name="octane-tests" value="pdfjs"/>
</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">
<antcall target="run-octane-v8">
<param name="octane-tests" value="pdfjs"/>
</antcall>
<run-one cond="octane.benchmark.pdfjs" runtime="v8"/>
</target>
<target name="octane-pdfjs-rhino" depends="jar">
<antcall target="run-octane-rhino">
<param name="octane-tests" value="pdfjs"/>
</antcall>
<run-one cond="octane.benchmark.pdfjs" runtime="rhino"/>
</target>
<!-- raytrace -->
<target name="octane-raytrace" depends="jar">
<antcall target="run-octane">
<param name="octane-tests" value="raytrace"/>
</antcall>
<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-raytrace-v8" depends="jar">
<antcall target="run-octane-v8">
<param name="octane-tests" value="raytrace"/>
</antcall>
<run-one cond="octane.benchmark.raytrace" runtime="v8"/>
</target>
<target name="octane-raytrace-rhino" depends="jar">
<antcall target="run-octane-rhino">
<param name="octane-tests" value="raytrace"/>
</antcall>
<run-one cond="octane.benchmark.raytrace" runtime="rhino"/>
</target>
<!-- regexp -->
<target name="octane-regexp" depends="jar">
<antcall target="run-octane">
<param name="octane-tests" value="regexp"/>
</antcall>
<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">
<antcall target="run-octane-v8">
<param name="octane-tests" value="regexp"/>
</antcall>
<run-one cond="octane.benchmark.regexp" runtime="v8"/>
</target>
<target name="octane-regexp-rhino" depends="jar">
<antcall target="run-octane-rhino">
<param name="octane-tests" value="regexp"/>
</antcall>
<run-one cond="octane.benchmark.regexp" runtime="rhino"/>
</target>
<!-- richards -->
<target name="octane-richards" depends="jar">
<antcall target="run-octane">
<param name="octane-tests" value="richards"/>
</antcall>
<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">
<antcall target="run-octane-v8">
<param name="octane-tests" value="richards"/>
</antcall>
<run-one cond="octane.benchmark.richards" runtime="v8"/>
</target>
<target name="octane-richards-rhino" depends="jar">
<antcall target="run-octane-rhino">
<param name="octane-tests" value="richards"/>
</antcall>
<run-one cond="octane.benchmark.richards" runtime="rhino"/>
</target>
<!-- splay -->
<target name="octane-splay" depends="jar">
<antcall target="run-octane">
<param name="octane-tests" value="splay"/>
</antcall>
<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-splay-v8" depends="jar">
<antcall target="run-octane-v8">
<param name="octane-tests" value="splay"/>
</antcall>
<run-one cond="octane.benchmark.splay" runtime="v8"/>
</target>
<target name="octane-splay-rhino" depends="jar">
<antcall target="run-octane-rhino">
<param name="octane-tests" value="splay"/>
</antcall>
<run-one cond="octane.benchmark.splay" runtime="rhino"/>
</target>
<!-- splay -->
<target name="octane-typescript" depends="jar">
<antcall target="run-octane">
<param name="octane-tests" value="typescript"/>
</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">
<antcall target="run-octane-v8">
<param name="octane-typescript" value="typescript"/>
</antcall>
<run-one cond="octane.benchmark.typescript" runtime="v8"/>
</target>
<target name="octane-typescript-rhino" depends="jar">
<antcall target="run-octane-rhino">
<param name="octane-tests" value="typescript"/>
</antcall>
<run-one cond="octane.benchmark.typescript" runtime="rhino"/>
</target>
<!-- zlib -->
<target name="octane-zlib" depends="jar">
<antcall target="run-octane">
<param name="octane-tests" value="zlib"/>
</antcall>
<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-zlib-v8" depends="jar">
<antcall target="run-octane-v8">
<param name="octane-typescript" value="zlib"/>
</antcall>
<run-one cond="octane.benchmark.zlib" runtime="v8"/>
</target>
<target name="octane-zlib-rhino" depends="jar">
<antcall target="run-octane-rhino">
<param name="octane-tests" value="zlib"/>
<run-one cond="octane.benchmark.zlib" runtime="rhino"/>
</target>
<!--
Benchmark runners for one or more benchmarks, single
or multiple process
-->
<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-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>
<!-- run octane benchmarks in a single process -->
<target name="octane-single-process" depends="octane-init">
<antcall target="run-octane"/>
<!--
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>
<!-- 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>

View File

@ -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 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</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 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<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 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</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 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<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 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</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 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</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 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</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 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<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 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<target name="alltests" depends="exit-if-no-testng, externals, update-externals, test, test262parallel, perf"/>
<import file="build-benchmark.xml"/>
</project>

View File

@ -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>

View File

@ -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 @@ parallel.test.runner=jdk.nashorn.internal.test.framework.ParallelTestRunner
# 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 @@ nashorn.api.tests.jar=${build.dir}/nashorn-api-tests.jar
# 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-sys-prop.test.js.unchecked.dir=${test262.dir}
# 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-sys-prop.test.js.shared.context=true
# 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 @@ test.src.dir=test/src
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\.*

View File

@ -103,8 +103,27 @@ import jdk.internal.dynalink.support.Lookup;
* 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 @@ public class ChainedCallSite extends AbstractRelinkableCallSite {
* 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 @@ public class ChainedCallSite extends AbstractRelinkableCallSite {
}
@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 @@ public class ChainedCallSite extends AbstractRelinkableCallSite {
// 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
@ -177,15 +199,31 @@ public class ChainedCallSite extends AbstractRelinkableCallSite {
return target;
}
/**
* 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 @@ public class ChainedCallSite extends AbstractRelinkableCallSite {
}
@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);
}
}

View File

@ -117,7 +117,7 @@ public class DefaultBootstrapper {
* @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 @@ public class DefaultBootstrapper {
* @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)));
}
}

View File

@ -140,7 +140,6 @@ import jdk.internal.dynalink.support.RuntimeContextLinkRequestImpl;
* @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 @@ public class DynamicLinker {
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 @@ public class DynamicLinker {
* 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.runtimeContextArgCount = runtimeContextArgCount;
this.linkerServices = linkerServices;
this.prelinkFilter = prelinkFilter;
this.runtimeContextArgCount = runtimeContextArgCount;
this.syncOnRelink = syncOnRelink;
this.unstableRelinkThreshold = unstableRelinkThreshold;
}
@ -199,7 +201,7 @@ public class DynamicLinker {
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 @@ public class DynamicLinker {
* @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 @@ public class DynamicLinker {
}
}
// 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

View File

@ -102,14 +102,15 @@ import jdk.internal.dynalink.support.BottomGuardingDynamicLinker;
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 @@ public class DynamicLinkerFactory {
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 @@ public class DynamicLinkerFactory {
*
* @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 @@ public class DynamicLinkerFactory {
* @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 @@ public class DynamicLinkerFactory {
*
* @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 @@ public class DynamicLinkerFactory {
* @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 @@ public class DynamicLinkerFactory {
* @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 @@ public class DynamicLinkerFactory {
* @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 @@ public class DynamicLinkerFactory {
*
* @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 @@ public class DynamicLinkerFactory {
* 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 @@ public class DynamicLinkerFactory {
* 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 @@ public class DynamicLinkerFactory {
}
/**
* 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 @@ public class DynamicLinkerFactory {
// ... 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 @@ public class DynamicLinkerFactory {
}
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 @@ public class DynamicLinkerFactory {
}, 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());
}
}

View File

@ -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);
}

View File

@ -99,17 +99,17 @@ public class MonomorphicCallSite extends AbstractRelinkableCallSite {
* 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);
}
}

View File

@ -97,7 +97,7 @@ public class NoSuchDynamicMethodException extends RuntimeException {
* Creates a new NoSuchDynamicMethodException
* @param message the message of the exception.
*/
public NoSuchDynamicMethodException(String message) {
public NoSuchDynamicMethodException(final String message) {
super(message);
}
}

View File

@ -97,7 +97,6 @@ import java.util.Collections;
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.linker.LinkerServices;
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
}
// 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
}
// 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
}
}
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
* @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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
* @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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
* @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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
* @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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
* @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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
* @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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
}
@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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
}
}
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
// 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
"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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
// 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
}
}
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
}
}
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
// 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
// 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
}
}
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
* @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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
* @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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
* @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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
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;
}

View File

@ -104,7 +104,7 @@ import java.util.Set;
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 @@ class AccessibleMembersLookup {
* @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 @@ class AccessibleMembersLookup {
* @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 @@ class AccessibleMembersLookup {
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 @@ class AccessibleMembersLookup {
}
}
}
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

View File

@ -108,7 +108,7 @@ class ApplicableOverloadedMethods {
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 @@ class ApplicableOverloadedMethods {
*/
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 @@ class ApplicableOverloadedMethods {
*/
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 @@ class ApplicableOverloadedMethods {
*/
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;
}

View File

@ -88,7 +88,7 @@ import java.util.Collections;
import java.util.Map;
class BeanIntrospector extends FacetIntrospector {
BeanIntrospector(Class<?> clazz) {
BeanIntrospector(final Class<?> clazz) {
super(clazz, true);
}
@ -98,7 +98,7 @@ class BeanIntrospector extends FacetIntrospector {
}
@Override
MethodHandle editMethodHandle(MethodHandle mh) {
MethodHandle editMethodHandle(final MethodHandle mh) {
return mh;
}
}

View File

@ -106,7 +106,7 @@ import jdk.internal.dynalink.support.TypeUtilities;
* @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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
}
@Override
public boolean canLinkType(Class<?> type) {
public boolean canLinkType(final Class<?> type) {
return type == clazz;
}
@ -129,8 +129,8 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
}
@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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
} 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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
}
@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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
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.");
}

View File

@ -131,7 +131,7 @@ import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
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 @@ public class BeansLinker implements GuardingDynamicLinker {
* @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 @@ public class BeansLinker implements GuardingDynamicLinker {
* @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 @@ public class BeansLinker implements GuardingDynamicLinker {
* @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 @@ public class BeansLinker implements GuardingDynamicLinker {
* @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 @@ public class BeansLinker implements GuardingDynamicLinker {
* @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 @@ public class BeansLinker implements GuardingDynamicLinker {
* @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 @@ public class BeansLinker implements GuardingDynamicLinker {
* @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();

View File

@ -107,14 +107,14 @@ public class CallerSensitiveDetector {
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 @@ public class CallerSensitiveDetector {
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 @@ public class CallerSensitiveDetector {
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;
}

View File

@ -107,13 +107,13 @@ class CallerSensitiveDynamicMethod extends SingleDynamicMethod {
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 @@ class CallerSensitiveDynamicMethod extends SingleDynamicMethod {
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 @@ class CallerSensitiveDynamicMethod extends SingleDynamicMethod {
}
@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())) {

View File

@ -101,7 +101,7 @@ class CheckRestrictedPackage {
* @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 @@ class CheckRestrictedPackage {
return null;
}
}, NO_PERMISSIONS_CONTEXT);
} catch(SecurityException e) {
} catch(final SecurityException e) {
return true;
}
return false;

View File

@ -104,16 +104,16 @@ final class ClassString {
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 @@ final class ClassString {
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 @@ final class ClassString {
/**
* 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 @@ final class ClassString {
* 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 @@ final class ClassString {
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();
}

View File

@ -99,7 +99,7 @@ import jdk.internal.dynalink.linker.LinkerServices;
abstract class DynamicMethod {
private final String name;
DynamicMethod(String name) {
DynamicMethod(final String name) {
this.name = name;
}
@ -138,7 +138,7 @@ abstract class DynamicMethod {
*/
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;
}

View File

@ -99,12 +99,12 @@ import jdk.internal.dynalink.support.Guards;
*/
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;

View File

@ -106,7 +106,7 @@ abstract class FacetIntrospector {
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 @@ abstract class FacetIntrospector {
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 @@ abstract class FacetIntrospector {
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 @@ abstract class FacetIntrospector {
}
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));
}

View File

@ -105,38 +105,38 @@ class GuardedInvocationComponent {
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 @@ class GuardedInvocationComponent {
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 @@ class GuardedInvocationComponent {
/*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 @@ class GuardedInvocationComponent {
throw new AssertionError("Incompatible composition " + this + " vs " + other);
}
private boolean isAssignableFrom(Validator other) {
private boolean isAssignableFrom(final Validator other) {
return validatorClass.isAssignableFrom(other.validatorClass);
}

View File

@ -105,7 +105,7 @@ class MaximallySpecific {
* @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 @@ class MaximallySpecific {
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 @@ class MaximallySpecific {
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 @@ class MaximallySpecific {
* @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 @@ class MaximallySpecific {
* @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 @@ class MaximallySpecific {
* @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 @@ class MaximallySpecific {
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 @@ class MaximallySpecific {
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 @@ class MaximallySpecific {
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);
}
}

View File

@ -115,20 +115,20 @@ class OverloadedDynamicMethod extends DynamicMethod {
* @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 @@ class OverloadedDynamicMethod extends DynamicMethod {
}
}
@SuppressWarnings("fallthrough")
@Override
public MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
final MethodType callSiteType = callSiteDescriptor.getMethodType();
@ -207,7 +206,7 @@ class OverloadedDynamicMethod extends DynamicMethod {
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 @@ class OverloadedDynamicMethod extends DynamicMethod {
// 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 @@ class OverloadedDynamicMethod extends DynamicMethod {
}
@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 @@ class OverloadedDynamicMethod extends DynamicMethod {
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 @@ class OverloadedDynamicMethod extends DynamicMethod {
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 @@ class OverloadedDynamicMethod extends DynamicMethod {
*
* @param method a method to add
*/
public void addMethod(SingleDynamicMethod method) {
public void addMethod(final SingleDynamicMethod method) {
methods.add(method);
}
}

View File

@ -93,6 +93,7 @@ import java.util.Map;
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 @@ class OverloadedMethod {
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 @@ class OverloadedMethod {
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 @@ class OverloadedMethod {
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 @@ class OverloadedMethod {
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 @@ class OverloadedMethod {
"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 @@ class OverloadedMethod {
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 @@ class OverloadedMethod {
"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 @@ class OverloadedMethod {
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 @@ class OverloadedMethod {
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;
}
}

View File

@ -107,12 +107,12 @@ class SimpleDynamicMethod extends SingleDynamicMethod {
* @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 @@ class SimpleDynamicMethod extends SingleDynamicMethod {
}
@Override
MethodHandle getTarget(Lookup lookup) {
MethodHandle getTarget(final Lookup lookup) {
return target;
}
}

View File

@ -104,7 +104,7 @@ abstract class SingleDynamicMethod extends DynamicMethod {
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 class SingleDynamicMethod extends DynamicMethod {
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 @@ abstract class SingleDynamicMethod extends DynamicMethod {
/**
* 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 @@ abstract class SingleDynamicMethod extends DynamicMethod {
}
@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 @@ abstract class SingleDynamicMethod extends DynamicMethod {
* @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 @@ abstract class SingleDynamicMethod extends DynamicMethod {
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 @@ abstract class SingleDynamicMethod extends DynamicMethod {
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());
}
}

View File

@ -96,7 +96,7 @@ import java.io.Serializable;
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 @@ public class StaticClass implements Serializable {
private final Class<?> clazz;
/*private*/ StaticClass(Class<?> clazz) {
/*private*/ StaticClass(final Class<?> clazz) {
clazz.getClass(); // NPE check
this.clazz = clazz;
}
@ -115,7 +115,7 @@ public class StaticClass implements Serializable {
* @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);
}

View File

@ -90,14 +90,14 @@ import java.util.HashMap;
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 @@ class StaticClassIntrospector extends FacetIntrospector {
}
@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);
}

View File

@ -104,7 +104,7 @@ import jdk.internal.dynalink.support.Lookup;
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 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
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 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
* @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 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
}
@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 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
}
}
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 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
}
@Override
public boolean canLinkType(Class<?> type) {
public boolean canLinkType(final Class<?> type) {
return type == StaticClass.class;
}
@ -201,7 +201,7 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
}
@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;
}
}

View File

@ -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 @@ import jdk.internal.dynalink.support.Guards;
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 @@ public class GuardedInvocation {
* 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 @@ public class GuardedInvocation {
* @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) {
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 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(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.switchPoint = switchPoint;
this.switchPoints = switchPoint == null ? null : new SwitchPoint[] { switchPoint };
this.exception = exception;
}
/**
* Creates a new guarded invocation.
* 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 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(MethodHandle invocation, SwitchPoint switchPoint, MethodHandle guard) {
this(invocation, guard, switchPoint);
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 @@ public class GuardedInvocation {
*
* @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 @@ public class GuardedInvocation {
* @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 @@ public class GuardedInvocation {
* @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 @@ public class GuardedInvocation {
* @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 @@ public class GuardedInvocation {
* @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,11 +322,25 @@ public class GuardedInvocation {
* @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
@ -247,7 +348,7 @@ public class GuardedInvocation {
* @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 @@ public class GuardedInvocation {
* @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 @@ public class GuardedInvocation {
* @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 @@ public class GuardedInvocation {
* @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 @@ public class GuardedInvocation {
* @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());
}

View File

@ -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;
}

View File

@ -101,10 +101,16 @@ public interface GuardingDynamicLinker {
* @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)

View File

@ -100,6 +100,17 @@ public interface LinkRequest {
*/
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.
@ -115,6 +126,17 @@ public interface LinkRequest {
*/
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
*/
public int getLinkCount();
/**
* Returns true if the call site is considered unstable, that is, it has been relinked more times than was
* specified in {@link DynamicLinkerFactory#setUnstableRelinkThreshold(int)}. Linkers should use this as a

View File

@ -87,7 +87,9 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import jdk.internal.dynalink.DynamicLinker;
import jdk.internal.dynalink.DynamicLinkerFactory;
import jdk.internal.dynalink.linker.ConversionComparator.Comparison;
import jdk.internal.dynalink.support.TypeUtilities;
/**
* Interface for services provided to {@link GuardingDynamicLinker} instances by the {@link DynamicLinker} that owns
@ -103,17 +105,33 @@ public interface LinkerServices {
* parameters. It will apply {@link MethodHandle#asType(MethodType)} for all primitive-to-primitive,
* wrapper-to-primitive, primitive-to-wrapper conversions as well as for all upcasts. For all other conversions,
* it'll insert {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with composite filters
* provided by {@link GuardingTypeConverterFactory} implementations. It doesn't use language-specific conversions on
* the return type.
* provided by {@link GuardingTypeConverterFactory} implementations.
*
* @param handle target method handle
* @param fromType the types of source arguments
* @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)} and
* {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with
* {@link GuardingTypeConverterFactory} produced type converters as filters.
* @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)},
* {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)}, and
* {@link MethodHandles#filterReturnValue(MethodHandle, MethodHandle)} with
* {@link GuardingTypeConverterFactory}-produced type converters as filters.
*/
public MethodHandle asType(MethodHandle handle, MethodType fromType);
/**
* Similar to {@link #asType(MethodHandle, MethodType)} except it only converts the return type of the method handle
* when it can be done using a conversion that loses neither precision nor magnitude, otherwise it leaves it
* unchanged. The idea is that other conversions should not be performed by individual linkers, but instead the
* {@link DynamicLinkerFactory#setPrelinkFilter(jdk.internal.dynalink.GuardedInvocationFilter) pre-link filter of
* the dynamic linker} should implement the strategy of dealing with potentially lossy return type conversions in a
* manner specific to the language runtime.
*
* @param handle target method handle
* @param fromType the types of source arguments
* @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)}, and
* {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with
* {@link GuardingTypeConverterFactory}-produced type converters as filters.
*/
public MethodHandle asTypeLosslessReturn(MethodHandle handle, MethodType fromType);
/**
* Given a source and target type, returns a method handle that converts between them. Never returns null; in worst
* case it will return an identity conversion (that might fail for some values at runtime). You rarely need to use
@ -161,4 +179,23 @@ public interface LinkerServices {
* conversion.
*/
public Comparison compareConversion(Class<?> sourceType, Class<?> targetType1, Class<?> targetType2);
/**
* If we could just use Java 8 constructs, then {@code asTypeSafeReturn} would be a method with default
* implementation. Since we can't do that, we extract common default implementations into this static class.
*/
public static class Implementation {
/**
* Default implementation for {@link LinkerServices#asTypeLosslessReturn(MethodHandle, MethodType)}.
* @param linkerServices the linker services that delegates to this implementation
* @param handle the passed handle
* @param fromType the passed type
* @return the converted method handle, as per the {@code asTypeSafeReturn} semantics.
*/
public static MethodHandle asTypeLosslessReturn(final LinkerServices linkerServices, final MethodHandle handle, final MethodType fromType) {
final Class<?> handleReturnType = handle.type().returnType();
return linkerServices.asType(handle, TypeUtilities.isConvertibleWithoutLoss(handleReturnType, fromType.returnType()) ?
fromType : fromType.changeReturnType(handleReturnType));
}
}
}

View File

@ -106,7 +106,7 @@ public abstract class AbstractCallSiteDescriptor implements CallSiteDescriptor {
}
@Override
public boolean equals(Object obj) {
public boolean equals(final Object obj) {
return obj instanceof CallSiteDescriptor && equals((CallSiteDescriptor)obj);
}
@ -115,7 +115,7 @@ public abstract class AbstractCallSiteDescriptor implements CallSiteDescriptor {
* @param csd the other call site descriptor.
* @return true if they are equal.
*/
public boolean equals(CallSiteDescriptor csd) {
public boolean equals(final CallSiteDescriptor csd) {
if(csd == null) {
return false;
}
@ -165,7 +165,7 @@ public abstract class AbstractCallSiteDescriptor implements CallSiteDescriptor {
return l + c - 1;
}
private StringBuilder appendName(StringBuilder b) {
private StringBuilder appendName(final StringBuilder b) {
b.append(getNameToken(0));
final int c = getNameTokenCount();
for(int i = 1; i < c; ++i) {
@ -174,7 +174,7 @@ public abstract class AbstractCallSiteDescriptor implements CallSiteDescriptor {
return b;
}
private static boolean lookupsEqual(Lookup l1, Lookup l2) {
private static boolean lookupsEqual(final Lookup l1, final Lookup l2) {
if(l1 == l2) {
return true;
}

View File

@ -100,7 +100,7 @@ public abstract class AbstractRelinkableCallSite extends MutableCallSite impleme
* Creates a new relinkable call site.
* @param descriptor the descriptor for this call site
*/
protected AbstractRelinkableCallSite(CallSiteDescriptor descriptor) {
protected AbstractRelinkableCallSite(final CallSiteDescriptor descriptor) {
super(descriptor.getMethodType());
this.descriptor = descriptor;
}
@ -111,7 +111,7 @@ public abstract class AbstractRelinkableCallSite extends MutableCallSite impleme
}
@Override
public void initialize(MethodHandle relinkAndInvoke) {
public void initialize(final MethodHandle relinkAndInvoke) {
setTarget(relinkAndInvoke);
}
}

View File

@ -116,14 +116,14 @@ public class AutoDiscovery {
* @return a list of guarding dynamic linkers available through the specified class loader. Can be zero-length list
* but not null.
*/
public static List<GuardingDynamicLinker> loadLinkers(ClassLoader cl) {
public static List<GuardingDynamicLinker> loadLinkers(final ClassLoader cl) {
return getLinkers(ServiceLoader.load(GuardingDynamicLinker.class, cl));
}
/**
* I can't believe there's no Collections API for making a List given an Iterator...
*/
private static <T> List<T> getLinkers(ServiceLoader<T> loader) {
private static <T> List<T> getLinkers(final ServiceLoader<T> loader) {
final List<T> list = new LinkedList<>();
for(final T linker: loader) {
list.add(linker);

View File

@ -105,12 +105,12 @@ public class BottomGuardingDynamicLinker implements TypeBasedGuardingDynamicLink
}
@Override
public boolean canLinkType(Class<?> type) {
public boolean canLinkType(final Class<?> type) {
return false;
}
@Override
public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, LinkerServices linkerServices) {
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) {
return null;
}
}

View File

@ -86,6 +86,7 @@ package jdk.internal.dynalink.support;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Collections;
@ -103,7 +104,7 @@ import jdk.internal.dynalink.CallSiteDescriptor;
* @author Attila Szegedi
*/
public class CallSiteDescriptorFactory {
private static final WeakHashMap<CallSiteDescriptor, WeakReference<CallSiteDescriptor>> publicDescs =
private static final WeakHashMap<CallSiteDescriptor, Reference<CallSiteDescriptor>> publicDescs =
new WeakHashMap<>();
@ -121,7 +122,7 @@ public class CallSiteDescriptorFactory {
* @return a call site descriptor representing the input. Note that although the method name is "create", it will
* in fact return a weakly-referenced canonical instance.
*/
public static CallSiteDescriptor create(Lookup lookup, String name, MethodType methodType) {
public static CallSiteDescriptor create(final Lookup lookup, final String name, final MethodType methodType) {
name.getClass(); // NPE check
methodType.getClass(); // NPE check
lookup.getClass(); // NPE check
@ -134,19 +135,28 @@ public class CallSiteDescriptorFactory {
static CallSiteDescriptor getCanonicalPublicDescriptor(final CallSiteDescriptor desc) {
synchronized(publicDescs) {
final WeakReference<CallSiteDescriptor> ref = publicDescs.get(desc);
final Reference<CallSiteDescriptor> ref = publicDescs.get(desc);
if(ref != null) {
final CallSiteDescriptor canonical = ref.get();
if(canonical != null) {
return canonical;
}
}
publicDescs.put(desc, new WeakReference<>(desc));
publicDescs.put(desc, createReference(desc));
}
return desc;
}
private static CallSiteDescriptor createPublicCallSiteDescriptor(String[] tokenizedName, MethodType methodType) {
/**
* Override this to use a different kind of references for the cache
* @param desc desc
* @return reference
*/
protected static Reference<CallSiteDescriptor> createReference(final CallSiteDescriptor desc) {
return new WeakReference<>(desc);
}
private static CallSiteDescriptor createPublicCallSiteDescriptor(final String[] tokenizedName, final MethodType methodType) {
final int l = tokenizedName.length;
if(l > 0 && tokenizedName[0] == "dyn") {
if(l == 2) {
@ -158,7 +168,7 @@ public class CallSiteDescriptorFactory {
return new DefaultCallSiteDescriptor(tokenizedName, methodType);
}
private static boolean isPublicLookup(Lookup lookup) {
private static boolean isPublicLookup(final Lookup lookup) {
return lookup == MethodHandles.publicLookup();
}
@ -169,7 +179,7 @@ public class CallSiteDescriptorFactory {
* @param name the composite name consisting of colon-separated, possibly mangled tokens.
* @return an array of tokens
*/
public static String[] tokenizeName(String name) {
public static String[] tokenizeName(final String name) {
final StringTokenizer tok = new StringTokenizer(name, CallSiteDescriptor.TOKEN_DELIMITER);
final String[] tokens = new String[tok.countTokens()];
for(int i = 0; i < tokens.length; ++i) {
@ -188,7 +198,7 @@ public class CallSiteDescriptorFactory {
* @param desc the call site descriptor with the operation
* @return a list of tokens
*/
public static List<String> tokenizeOperators(CallSiteDescriptor desc) {
public static List<String> tokenizeOperators(final CallSiteDescriptor desc) {
final String ops = desc.getNameToken(CallSiteDescriptor.OPERATOR);
final StringTokenizer tok = new StringTokenizer(ops, CallSiteDescriptor.OPERATOR_DELIMITER);
final int count = tok.countTokens();
@ -210,7 +220,7 @@ public class CallSiteDescriptorFactory {
* @param end index of the first parameter to not remove
* @return a new call site descriptor with modified method type
*/
public static CallSiteDescriptor dropParameterTypes(CallSiteDescriptor desc, int start, int end) {
public static CallSiteDescriptor dropParameterTypes(final CallSiteDescriptor desc, final int start, final int end) {
return desc.changeMethodType(desc.getMethodType().dropParameterTypes(start, end));
}
@ -222,7 +232,7 @@ public class CallSiteDescriptorFactory {
* @param nptype the new parameter type
* @return a new call site descriptor with modified method type
*/
public static CallSiteDescriptor changeParameterType(CallSiteDescriptor desc, int num, Class<?> nptype) {
public static CallSiteDescriptor changeParameterType(final CallSiteDescriptor desc, final int num, final Class<?> nptype) {
return desc.changeMethodType(desc.getMethodType().changeParameterType(num, nptype));
}
@ -233,7 +243,7 @@ public class CallSiteDescriptorFactory {
* @param nrtype the new return type
* @return a new call site descriptor with modified method type
*/
public static CallSiteDescriptor changeReturnType(CallSiteDescriptor desc, Class<?> nrtype) {
public static CallSiteDescriptor changeReturnType(final CallSiteDescriptor desc, final Class<?> nrtype) {
return desc.changeMethodType(desc.getMethodType().changeReturnType(nrtype));
}
@ -245,7 +255,7 @@ public class CallSiteDescriptorFactory {
* @param ptypesToInsert the new types to insert
* @return a new call site descriptor with modified method type
*/
public static CallSiteDescriptor insertParameterTypes(CallSiteDescriptor desc, int num, Class<?>... ptypesToInsert) {
public static CallSiteDescriptor insertParameterTypes(final CallSiteDescriptor desc, final int num, final Class<?>... ptypesToInsert) {
return desc.changeMethodType(desc.getMethodType().insertParameterTypes(num, ptypesToInsert));
}
@ -257,7 +267,7 @@ public class CallSiteDescriptorFactory {
* @param ptypesToInsert the new types to insert
* @return a new call site descriptor with modified method type
*/
public static CallSiteDescriptor insertParameterTypes(CallSiteDescriptor desc, int num, List<Class<?>> ptypesToInsert) {
public static CallSiteDescriptor insertParameterTypes(final CallSiteDescriptor desc, final int num, final List<Class<?>> ptypesToInsert) {
return desc.changeMethodType(desc.getMethodType().insertParameterTypes(num, ptypesToInsert));
}
}

View File

@ -110,7 +110,7 @@ public abstract class ClassMap<T> {
*
* @param classLoader the classloader that determines strong referenceability.
*/
protected ClassMap(ClassLoader classLoader) {
protected ClassMap(final ClassLoader classLoader) {
this.classLoader = classLoader;
}

View File

@ -109,16 +109,16 @@ public class CompositeGuardingDynamicLinker implements GuardingDynamicLinker, Se
*
* @param linkers a list of component linkers.
*/
public CompositeGuardingDynamicLinker(Iterable<? extends GuardingDynamicLinker> linkers) {
public CompositeGuardingDynamicLinker(final Iterable<? extends GuardingDynamicLinker> linkers) {
final List<GuardingDynamicLinker> l = new LinkedList<>();
for(GuardingDynamicLinker linker: linkers) {
for(final GuardingDynamicLinker linker: linkers) {
l.add(linker);
}
this.linkers = l.toArray(new GuardingDynamicLinker[l.size()]);
}
@Override
public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, final LinkerServices linkerServices)
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices)
throws Exception {
for(final GuardingDynamicLinker linker: linkers) {
final GuardedInvocation invocation = linker.getGuardedInvocation(linkRequest, linkerServices);

View File

@ -112,7 +112,7 @@ public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardin
private final List<TypeBasedGuardingDynamicLinker>[] singletonLinkers;
@SuppressWarnings("unchecked")
ClassToLinker(TypeBasedGuardingDynamicLinker[] linkers) {
ClassToLinker(final TypeBasedGuardingDynamicLinker[] linkers) {
this.linkers = linkers;
singletonLinkers = new List[linkers.length];
for(int i = 0; i < linkers.length; ++i) {
@ -121,7 +121,7 @@ public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardin
}
@Override
protected List<TypeBasedGuardingDynamicLinker> computeValue(Class<?> clazz) {
protected List<TypeBasedGuardingDynamicLinker> computeValue(final Class<?> clazz) {
List<TypeBasedGuardingDynamicLinker> list = NO_LINKER;
for(int i = 0; i < linkers.length; ++i) {
final TypeBasedGuardingDynamicLinker linker = linkers[i];
@ -152,27 +152,27 @@ public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardin
*
* @param linkers the component linkers
*/
public CompositeTypeBasedGuardingDynamicLinker(Iterable<? extends TypeBasedGuardingDynamicLinker> linkers) {
public CompositeTypeBasedGuardingDynamicLinker(final Iterable<? extends TypeBasedGuardingDynamicLinker> linkers) {
final List<TypeBasedGuardingDynamicLinker> l = new LinkedList<>();
for(TypeBasedGuardingDynamicLinker linker: linkers) {
for(final TypeBasedGuardingDynamicLinker linker: linkers) {
l.add(linker);
}
this.classToLinker = new ClassToLinker(l.toArray(new TypeBasedGuardingDynamicLinker[l.size()]));
}
@Override
public boolean canLinkType(Class<?> type) {
public boolean canLinkType(final Class<?> type) {
return !classToLinker.get(type).isEmpty();
}
@Override
public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, final LinkerServices linkerServices)
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices)
throws Exception {
final Object obj = linkRequest.getReceiver();
if(obj == null) {
return null;
}
for(TypeBasedGuardingDynamicLinker linker: classToLinker.get(obj.getClass())) {
for(final TypeBasedGuardingDynamicLinker linker: classToLinker.get(obj.getClass())) {
final GuardedInvocation invocation = linker.getGuardedInvocation(linkRequest, linkerServices);
if(invocation != null) {
return invocation;
@ -189,10 +189,10 @@ public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardin
* @param linkers the list of linkers to optimize
* @return the optimized list
*/
public static List<GuardingDynamicLinker> optimize(Iterable<? extends GuardingDynamicLinker> linkers) {
public static List<GuardingDynamicLinker> optimize(final Iterable<? extends GuardingDynamicLinker> linkers) {
final List<GuardingDynamicLinker> llinkers = new LinkedList<>();
final List<TypeBasedGuardingDynamicLinker> tblinkers = new LinkedList<>();
for(GuardingDynamicLinker linker: linkers) {
for(final GuardingDynamicLinker linker: linkers) {
if(linker instanceof TypeBasedGuardingDynamicLinker) {
tblinkers.add((TypeBasedGuardingDynamicLinker)linker);
} else {
@ -204,8 +204,8 @@ public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardin
return llinkers;
}
private static void addTypeBased(List<GuardingDynamicLinker> llinkers,
List<TypeBasedGuardingDynamicLinker> tblinkers) {
private static void addTypeBased(final List<GuardingDynamicLinker> llinkers,
final List<TypeBasedGuardingDynamicLinker> tblinkers) {
switch(tblinkers.size()) {
case 0: {
break;

View File

@ -98,7 +98,7 @@ class DefaultCallSiteDescriptor extends AbstractCallSiteDescriptor {
private final String[] tokenizedName;
private final MethodType methodType;
DefaultCallSiteDescriptor(String[] tokenizedName, MethodType methodType) {
DefaultCallSiteDescriptor(final String[] tokenizedName, final MethodType methodType) {
this.tokenizedName = tokenizedName;
this.methodType = methodType;
}
@ -109,10 +109,10 @@ class DefaultCallSiteDescriptor extends AbstractCallSiteDescriptor {
}
@Override
public String getNameToken(int i) {
public String getNameToken(final int i) {
try {
return tokenizedName[i];
} catch(ArrayIndexOutOfBoundsException e) {
} catch(final ArrayIndexOutOfBoundsException e) {
throw new IllegalArgumentException(e.getMessage());
}
}
@ -127,7 +127,7 @@ class DefaultCallSiteDescriptor extends AbstractCallSiteDescriptor {
}
@Override
public CallSiteDescriptor changeMethodType(MethodType newMethodType) {
public CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
return CallSiteDescriptorFactory.getCanonicalPublicDescriptor(new DefaultCallSiteDescriptor(tokenizedName,
newMethodType));
}

View File

@ -0,0 +1,99 @@
/*
* 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.support;
import jdk.internal.dynalink.GuardedInvocationFilter;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
/**
* Default filter for guarded invocation pre link filtering
*/
public class DefaultPrelinkFilter implements GuardedInvocationFilter {
@Override
public GuardedInvocation filter(final GuardedInvocation inv, final LinkRequest request, final LinkerServices linkerServices) {
return inv.asType(linkerServices, request.getCallSiteDescriptor().getMethodType());
}
}

View File

@ -113,7 +113,7 @@ public class Guards {
* @return a method handle testing whether its first argument is of the specified class.
*/
@SuppressWarnings("boxing")
public static MethodHandle isOfClass(Class<?> clazz, MethodType type) {
public static MethodHandle isOfClass(final Class<?> clazz, final MethodType type) {
final Class<?> declaredType = type.parameterType(0);
if(clazz == declaredType) {
LOG.log(Level.WARNING, "isOfClassGuardAlwaysTrue", new Object[] { clazz.getName(), 0, type, DynamicLinker.getLinkedCallSiteLocation() });
@ -135,7 +135,7 @@ public class Guards {
* @param type the method type
* @return a method handle testing whether its first argument is of the specified class or subclass.
*/
public static MethodHandle isInstance(Class<?> clazz, MethodType type) {
public static MethodHandle isInstance(final Class<?> clazz, final MethodType type) {
return isInstance(clazz, 0, type);
}
@ -150,7 +150,7 @@ public class Guards {
* @return a method handle testing whether its first argument is of the specified class or subclass.
*/
@SuppressWarnings("boxing")
public static MethodHandle isInstance(Class<?> clazz, int pos, MethodType type) {
public static MethodHandle isInstance(final Class<?> clazz, final int pos, final MethodType type) {
final Class<?> declaredType = type.parameterType(pos);
if(clazz.isAssignableFrom(declaredType)) {
LOG.log(Level.WARNING, "isInstanceGuardAlwaysTrue", new Object[] { clazz.getName(), pos, type, DynamicLinker.getLinkedCallSiteLocation() });
@ -172,7 +172,7 @@ public class Guards {
* the arguments are ignored.
*/
@SuppressWarnings("boxing")
public static MethodHandle isArray(int pos, MethodType type) {
public static MethodHandle isArray(final int pos, final MethodType type) {
final Class<?> declaredType = type.parameterType(pos);
if(declaredType.isArray()) {
LOG.log(Level.WARNING, "isArrayGuardAlwaysTrue", new Object[] { pos, type, DynamicLinker.getLinkedCallSiteLocation() });
@ -193,7 +193,7 @@ public class Guards {
* @param referredLoader the referred class loader
* @return true if it is safe to strongly reference the class
*/
public static boolean canReferenceDirectly(ClassLoader referrerLoader, final ClassLoader referredLoader) {
public static boolean canReferenceDirectly(final ClassLoader referrerLoader, final ClassLoader referredLoader) {
if(referredLoader == null) {
// Can always refer directly to a system class
return true;
@ -215,7 +215,7 @@ public class Guards {
return false;
}
private static MethodHandle getClassBoundArgumentTest(MethodHandle test, Class<?> clazz, int pos, MethodType type) {
private static MethodHandle getClassBoundArgumentTest(final MethodHandle test, final Class<?> clazz, final int pos, final MethodType type) {
// Bind the class to the first argument of the test
return asType(test.bindTo(clazz), pos, type);
}
@ -227,7 +227,7 @@ public class Guards {
* @param type the type to adapt the method handle to
* @return the adapted method handle
*/
public static MethodHandle asType(MethodHandle test, MethodType type) {
public static MethodHandle asType(final MethodHandle test, final MethodType type) {
return test.asType(getTestType(test, type));
}
@ -239,16 +239,16 @@ public class Guards {
* @param type the type to adapt the method handle to
* @return the adapted method handle
*/
public static MethodHandle asType(LinkerServices linkerServices, MethodHandle test, MethodType type) {
public static MethodHandle asType(final LinkerServices linkerServices, final MethodHandle test, final MethodType type) {
return linkerServices.asType(test, getTestType(test, type));
}
private static MethodType getTestType(MethodHandle test, MethodType type) {
private static MethodType getTestType(final MethodHandle test, final MethodType type) {
return type.dropParameterTypes(test.type().parameterCount(),
type.parameterCount()).changeReturnType(boolean.class);
}
private static MethodHandle asType(MethodHandle test, int pos, MethodType type) {
private static MethodHandle asType(final MethodHandle test, final int pos, final MethodType type) {
assert test != null;
assert type != null;
assert type.parameterCount() > 0;
@ -283,7 +283,7 @@ public class Guards {
* @param clazz the class to test for.
* @return the desired guard method.
*/
public static MethodHandle getClassGuard(Class<?> clazz) {
public static MethodHandle getClassGuard(final Class<?> clazz) {
return IS_OF_CLASS.bindTo(clazz);
}
@ -292,7 +292,7 @@ public class Guards {
* @param clazz the class to test for.
* @return the desired guard method.
*/
public static MethodHandle getInstanceOfGuard(Class<?> clazz) {
public static MethodHandle getInstanceOfGuard(final Class<?> clazz) {
return IS_INSTANCE.bindTo(clazz);
}
@ -301,7 +301,7 @@ public class Guards {
* @param obj the object used as referential identity test
* @return the desired guard method.
*/
public static MethodHandle getIdentityGuard(Object obj) {
public static MethodHandle getIdentityGuard(final Object obj) {
return IS_IDENTICAL.bindTo(obj);
}
@ -322,39 +322,39 @@ public class Guards {
}
@SuppressWarnings("unused")
private static boolean isNull(Object obj) {
private static boolean isNull(final Object obj) {
return obj == null;
}
@SuppressWarnings("unused")
private static boolean isNotNull(Object obj) {
private static boolean isNotNull(final Object obj) {
return obj != null;
}
@SuppressWarnings("unused")
private static boolean isArray(Object o) {
private static boolean isArray(final Object o) {
return o != null && o.getClass().isArray();
}
@SuppressWarnings("unused")
private static boolean isOfClass(Class<?> c, Object o) {
private static boolean isOfClass(final Class<?> c, final Object o) {
return o != null && o.getClass() == c;
}
@SuppressWarnings("unused")
private static boolean isIdentical(Object o1, Object o2) {
private static boolean isIdentical(final Object o1, final Object o2) {
return o1 == o2;
}
private static MethodHandle constantTrue(MethodType type) {
private static MethodHandle constantTrue(final MethodType type) {
return constantBoolean(Boolean.TRUE, type);
}
private static MethodHandle constantFalse(MethodType type) {
private static MethodHandle constantFalse(final MethodType type) {
return constantBoolean(Boolean.FALSE, type);
}
private static MethodHandle constantBoolean(Boolean value, MethodType type) {
private static MethodHandle constantBoolean(final Boolean value, final MethodType type) {
return MethodHandles.permuteArguments(MethodHandles.constant(Boolean.TYPE, value),
type.changeReturnType(Boolean.TYPE));
}

View File

@ -95,18 +95,24 @@ import jdk.internal.dynalink.linker.LinkRequest;
public class LinkRequestImpl implements LinkRequest {
private final CallSiteDescriptor callSiteDescriptor;
private final Object callSiteToken;
private final Object[] arguments;
private final boolean callSiteUnstable;
private final int linkCount;
/**
* Creates a new link request.
*
* @param callSiteDescriptor the descriptor for the call site being linked
* @param callSiteToken the opaque token for the call site being linked.
* @param linkCount how many times this callsite has been linked/relinked
* @param callSiteUnstable true if the call site being linked is considered unstable
* @param arguments the arguments for the invocation
*/
public LinkRequestImpl(CallSiteDescriptor callSiteDescriptor, boolean callSiteUnstable, Object... arguments) {
public LinkRequestImpl(final CallSiteDescriptor callSiteDescriptor, final Object callSiteToken, final int linkCount, final boolean callSiteUnstable, final Object... arguments) {
this.callSiteDescriptor = callSiteDescriptor;
this.callSiteToken = callSiteToken;
this.linkCount = linkCount;
this.callSiteUnstable = callSiteUnstable;
this.arguments = arguments;
}
@ -126,18 +132,28 @@ public class LinkRequestImpl implements LinkRequest {
return callSiteDescriptor;
}
@Override
public Object getCallSiteToken() {
return callSiteToken;
}
@Override
public boolean isCallSiteUnstable() {
return callSiteUnstable;
}
@Override
public int getLinkCount() {
return linkCount;
}
@Override
public LinkRequest withoutRuntimeContext() {
return this;
}
@Override
public LinkRequest replaceArguments(CallSiteDescriptor newCallSiteDescriptor, Object[] newArguments) {
return new LinkRequestImpl(newCallSiteDescriptor, callSiteUnstable, newArguments);
public LinkRequest replaceArguments(final CallSiteDescriptor newCallSiteDescriptor, final Object[] newArguments) {
return new LinkRequestImpl(newCallSiteDescriptor, callSiteToken, linkCount, callSiteUnstable, newArguments);
}
}

View File

@ -117,27 +117,32 @@ public class LinkerServicesImpl implements LinkerServices {
}
@Override
public boolean canConvert(Class<?> from, Class<?> to) {
public boolean canConvert(final Class<?> from, final Class<?> to) {
return typeConverterFactory.canConvert(from, to);
}
@Override
public MethodHandle asType(MethodHandle handle, MethodType fromType) {
public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
return typeConverterFactory.asType(handle, fromType);
}
@Override
public MethodHandle getTypeConverter(Class<?> sourceType, Class<?> targetType) {
public MethodHandle asTypeLosslessReturn(final MethodHandle handle, final MethodType fromType) {
return Implementation.asTypeLosslessReturn(this, handle, fromType);
}
@Override
public MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
return typeConverterFactory.getTypeConverter(sourceType, targetType);
}
@Override
public Comparison compareConversion(Class<?> sourceType, Class<?> targetType1, Class<?> targetType2) {
public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
return typeConverterFactory.compareConversion(sourceType, targetType1, targetType2);
}
@Override
public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest) throws Exception {
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest) throws Exception {
final LinkRequest prevLinkRequest = threadLinkRequest.get();
threadLinkRequest.set(linkRequest);
try {
@ -154,7 +159,7 @@ public class LinkerServicesImpl implements LinkerServices {
* permission.
*/
public static LinkRequest getCurrentLinkRequest() {
SecurityManager sm = System.getSecurityManager();
final SecurityManager sm = System.getSecurityManager();
if(sm != null) {
sm.checkPermission(GET_CURRENT_LINK_REQUEST);
}

View File

@ -104,7 +104,7 @@ public class Lookup {
*
* @param lookup the {@link java.lang.invoke.MethodHandles.Lookup} it delegates to.
*/
public Lookup(MethodHandles.Lookup lookup) {
public Lookup(final MethodHandles.Lookup lookup) {
this.lookup = lookup;
}
@ -120,7 +120,7 @@ public class Lookup {
* @param m the method to unreflect
* @return the unreflected method handle.
*/
public MethodHandle unreflect(Method m) {
public MethodHandle unreflect(final Method m) {
return unreflect(lookup, m);
}
@ -132,10 +132,10 @@ public class Lookup {
* @param m the method to unreflect
* @return the unreflected method handle.
*/
public static MethodHandle unreflect(MethodHandles.Lookup lookup, Method m) {
public static MethodHandle unreflect(final MethodHandles.Lookup lookup, final Method m) {
try {
return lookup.unreflect(m);
} catch(IllegalAccessException e) {
} catch(final IllegalAccessException e) {
final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect method " + m);
ee.initCause(e);
throw ee;
@ -149,10 +149,10 @@ public class Lookup {
* @param f the field for which a getter is unreflected
* @return the unreflected field getter handle.
*/
public MethodHandle unreflectGetter(Field f) {
public MethodHandle unreflectGetter(final Field f) {
try {
return lookup.unreflectGetter(f);
} catch(IllegalAccessException e) {
} catch(final IllegalAccessException e) {
final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect getter for field " + f);
ee.initCause(e);
throw ee;
@ -171,15 +171,15 @@ public class Lookup {
* @throws IllegalAccessError if the field is inaccessible.
* @throws NoSuchFieldError if the field does not exist.
*/
public MethodHandle findGetter(Class<?>refc, String name, Class<?> type) {
public MethodHandle findGetter(final Class<?>refc, final String name, final Class<?> type) {
try {
return lookup.findGetter(refc, name, type);
} catch(IllegalAccessException e) {
} catch(final IllegalAccessException e) {
final IllegalAccessError ee = new IllegalAccessError("Failed to access getter for field " + refc.getName() +
"." + name + " of type " + type.getName());
ee.initCause(e);
throw ee;
} catch(NoSuchFieldException e) {
} catch(final NoSuchFieldException e) {
final NoSuchFieldError ee = new NoSuchFieldError("Failed to find getter for field " + refc.getName() +
"." + name + " of type " + type.getName());
ee.initCause(e);
@ -194,10 +194,10 @@ public class Lookup {
* @param f the field for which a setter is unreflected
* @return the unreflected field setter handle.
*/
public MethodHandle unreflectSetter(Field f) {
public MethodHandle unreflectSetter(final Field f) {
try {
return lookup.unreflectSetter(f);
} catch(IllegalAccessException e) {
} catch(final IllegalAccessException e) {
final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect setter for field " + f);
ee.initCause(e);
throw ee;
@ -211,7 +211,7 @@ public class Lookup {
* @param c the constructor to unreflect
* @return the unreflected constructor handle.
*/
public MethodHandle unreflectConstructor(Constructor<?> c) {
public MethodHandle unreflectConstructor(final Constructor<?> c) {
return unreflectConstructor(lookup, c);
}
@ -223,10 +223,10 @@ public class Lookup {
* @param c the constructor to unreflect
* @return the unreflected constructor handle.
*/
public static MethodHandle unreflectConstructor(MethodHandles.Lookup lookup, Constructor<?> c) {
public static MethodHandle unreflectConstructor(final MethodHandles.Lookup lookup, final Constructor<?> c) {
try {
return lookup.unreflectConstructor(c);
} catch(IllegalAccessException e) {
} catch(final IllegalAccessException e) {
final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect constructor " + c);
ee.initCause(e);
throw ee;
@ -244,15 +244,15 @@ public class Lookup {
* @throws IllegalAccessError if the method is inaccessible.
* @throws NoSuchMethodError if the method does not exist.
*/
public MethodHandle findSpecial(Class<?> declaringClass, String name, MethodType type) {
public MethodHandle findSpecial(final Class<?> declaringClass, final String name, final MethodType type) {
try {
return lookup.findSpecial(declaringClass, name, type, declaringClass);
} catch(IllegalAccessException e) {
} catch(final IllegalAccessException e) {
final IllegalAccessError ee = new IllegalAccessError("Failed to access special method " + methodDescription(
declaringClass, name, type));
ee.initCause(e);
throw ee;
} catch(NoSuchMethodException e) {
} catch(final NoSuchMethodException e) {
final NoSuchMethodError ee = new NoSuchMethodError("Failed to find special method " + methodDescription(
declaringClass, name, type));
ee.initCause(e);
@ -260,7 +260,7 @@ public class Lookup {
}
}
private static String methodDescription(Class<?> declaringClass, String name, MethodType type) {
private static String methodDescription(final Class<?> declaringClass, final String name, final MethodType type) {
return declaringClass.getName() + "#" + name + type;
}
@ -275,15 +275,15 @@ public class Lookup {
* @throws IllegalAccessError if the method is inaccessible.
* @throws NoSuchMethodError if the method does not exist.
*/
public MethodHandle findStatic(Class<?> declaringClass, String name, MethodType type) {
public MethodHandle findStatic(final Class<?> declaringClass, final String name, final MethodType type) {
try {
return lookup.findStatic(declaringClass, name, type);
} catch(IllegalAccessException e) {
} catch(final IllegalAccessException e) {
final IllegalAccessError ee = new IllegalAccessError("Failed to access static method " + methodDescription(
declaringClass, name, type));
ee.initCause(e);
throw ee;
} catch(NoSuchMethodException e) {
} catch(final NoSuchMethodException e) {
final NoSuchMethodError ee = new NoSuchMethodError("Failed to find static method " + methodDescription(
declaringClass, name, type));
ee.initCause(e);
@ -302,15 +302,15 @@ public class Lookup {
* @throws IllegalAccessError if the method is inaccessible.
* @throws NoSuchMethodError if the method does not exist.
*/
public MethodHandle findVirtual(Class<?> declaringClass, String name, MethodType type) {
public MethodHandle findVirtual(final Class<?> declaringClass, final String name, final MethodType type) {
try {
return lookup.findVirtual(declaringClass, name, type);
} catch(IllegalAccessException e) {
} catch(final IllegalAccessException e) {
final IllegalAccessError ee = new IllegalAccessError("Failed to access virtual method " + methodDescription(
declaringClass, name, type));
ee.initCause(e);
throw ee;
} catch(NoSuchMethodException e) {
} catch(final NoSuchMethodException e) {
final NoSuchMethodError ee = new NoSuchMethodError("Failed to find virtual method " + methodDescription(
declaringClass, name, type));
ee.initCause(e);
@ -327,7 +327,7 @@ public class Lookup {
* @param ptypes the parameter types of the method
* @return the method handle for the method
*/
public static MethodHandle findOwnSpecial(MethodHandles.Lookup lookup, String name, Class<?> rtype, Class<?>... ptypes) {
public static MethodHandle findOwnSpecial(final MethodHandles.Lookup lookup, final String name, final Class<?> rtype, final Class<?>... ptypes) {
return new Lookup(lookup).findOwnSpecial(name, rtype, ptypes);
}
@ -341,7 +341,7 @@ public class Lookup {
* @param ptypes the parameter types of the method
* @return the method handle for the method
*/
public MethodHandle findOwnSpecial(String name, Class<?> rtype, Class<?>... ptypes) {
public MethodHandle findOwnSpecial(final String name, final Class<?> rtype, final Class<?>... ptypes) {
return findSpecial(lookup.lookupClass(), name, MethodType.methodType(rtype, ptypes));
}
@ -355,7 +355,7 @@ public class Lookup {
* @param ptypes the parameter types of the method
* @return the method handle for the method
*/
public static MethodHandle findOwnStatic(MethodHandles.Lookup lookup, String name, Class<?> rtype, Class<?>... ptypes) {
public static MethodHandle findOwnStatic(final MethodHandles.Lookup lookup, final String name, final Class<?> rtype, final Class<?>... ptypes) {
return new Lookup(lookup).findOwnStatic(name, rtype, ptypes);
}
@ -368,7 +368,7 @@ public class Lookup {
* @param ptypes the parameter types of the method
* @return the method handle for the method
*/
public MethodHandle findOwnStatic(String name, Class<?> rtype, Class<?>... ptypes) {
public MethodHandle findOwnStatic(final String name, final Class<?> rtype, final Class<?>... ptypes) {
return findStatic(lookup.lookupClass(), name, MethodType.methodType(rtype, ptypes));
}
}

View File

@ -92,7 +92,7 @@ import jdk.internal.dynalink.CallSiteDescriptor;
* @author Attila Szegedi
*/
class LookupCallSiteDescriptor extends DefaultCallSiteDescriptor {
private Lookup lookup;
private final Lookup lookup;
/**
* Create a new call site descriptor from explicit information.
@ -100,7 +100,7 @@ class LookupCallSiteDescriptor extends DefaultCallSiteDescriptor {
* @param methodType the method type
* @param lookup the lookup
*/
LookupCallSiteDescriptor(String[] tokenizedName, MethodType methodType, Lookup lookup) {
LookupCallSiteDescriptor(final String[] tokenizedName, final MethodType methodType, final Lookup lookup) {
super(tokenizedName, methodType);
this.lookup = lookup;
}
@ -111,7 +111,7 @@ class LookupCallSiteDescriptor extends DefaultCallSiteDescriptor {
}
@Override
public CallSiteDescriptor changeMethodType(MethodType newMethodType) {
public CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
return new LookupCallSiteDescriptor(getTokenizedName(), newMethodType, lookup);
}
}

View File

@ -137,7 +137,7 @@ public class NameCodec {
* @param name the symbolic name to mangle
* @return the mangled form of the symbolic name.
*/
public static String encode(String name) {
public static String encode(final String name) {
final int l = name.length();
if(l == 0) {
return EMPTY_NAME;
@ -176,7 +176,7 @@ public class NameCodec {
* @param name the symbolic name to demangle
* @return the demangled form of the symbolic name.
*/
public static String decode(String name) {
public static String decode(final String name) {
if(name.charAt(0) != ESCAPE_CHAR) {
return name;
}
@ -184,11 +184,11 @@ public class NameCodec {
if(l == 2 && name.charAt(1) == EMPTY_CHAR) {
return "";
}
StringBuilder b = new StringBuilder(name.length());
final StringBuilder b = new StringBuilder(name.length());
int lastEscape = -2;
int lastBackslash = -1;
for(;;) {
int nextBackslash = name.indexOf(ESCAPE_CHAR, lastBackslash + 1);
final int nextBackslash = name.indexOf(ESCAPE_CHAR, lastBackslash + 1);
if(nextBackslash == -1 || nextBackslash == l - 1) {
break;
}
@ -211,7 +211,7 @@ public class NameCodec {
return b.toString();
}
private static void addEncoding(char from, char to) {
private static void addEncoding(final char from, final char to) {
ENCODING[from - MIN_ENCODING] = to;
DECODING[to - MIN_DECODING] = from;
}

View File

@ -89,7 +89,7 @@ import jdk.internal.dynalink.CallSiteDescriptor;
class NamedDynCallSiteDescriptor extends UnnamedDynCallSiteDescriptor {
private final String name;
NamedDynCallSiteDescriptor(String op, String name, MethodType methodType) {
NamedDynCallSiteDescriptor(final String op, final String name, final MethodType methodType) {
super(op, methodType);
this.name = name;
}
@ -100,7 +100,7 @@ class NamedDynCallSiteDescriptor extends UnnamedDynCallSiteDescriptor {
}
@Override
public String getNameToken(int i) {
public String getNameToken(final int i) {
switch(i) {
case 0: return "dyn";
case 1: return getOp();
@ -110,7 +110,7 @@ class NamedDynCallSiteDescriptor extends UnnamedDynCallSiteDescriptor {
}
@Override
public CallSiteDescriptor changeMethodType(MethodType newMethodType) {
public CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
return CallSiteDescriptorFactory.getCanonicalPublicDescriptor(new NamedDynCallSiteDescriptor(getOp(), name,
newMethodType));
}

View File

@ -101,15 +101,17 @@ public class RuntimeContextLinkRequestImpl extends LinkRequestImpl {
* Creates a new link request.
*
* @param callSiteDescriptor the descriptor for the call site being linked
* @param callSiteToken the opaque token for the call site being linked.
* @param arguments the arguments for the invocation
* @param linkCount number of times callsite has been linked/relinked
* @param callSiteUnstable true if the call site being linked is considered unstable
* @param runtimeContextArgCount the number of the leading arguments on the stack that represent the language
* runtime specific context arguments.
* @throws IllegalArgumentException if runtimeContextArgCount is less than 1.
*/
public RuntimeContextLinkRequestImpl(CallSiteDescriptor callSiteDescriptor, boolean callSiteUnstable,
Object[] arguments, int runtimeContextArgCount) {
super(callSiteDescriptor, callSiteUnstable, arguments);
public RuntimeContextLinkRequestImpl(final CallSiteDescriptor callSiteDescriptor, final Object callSiteToken,
final int linkCount, final boolean callSiteUnstable, final Object[] arguments, final int runtimeContextArgCount) {
super(callSiteDescriptor, callSiteToken, linkCount, callSiteUnstable, arguments);
if(runtimeContextArgCount < 1) {
throw new IllegalArgumentException("runtimeContextArgCount < 1");
}
@ -121,14 +123,14 @@ public class RuntimeContextLinkRequestImpl extends LinkRequestImpl {
if(contextStrippedRequest == null) {
contextStrippedRequest =
new LinkRequestImpl(CallSiteDescriptorFactory.dropParameterTypes(getCallSiteDescriptor(), 1,
runtimeContextArgCount + 1), isCallSiteUnstable(), getTruncatedArguments());
runtimeContextArgCount + 1), getCallSiteToken(), getLinkCount(), isCallSiteUnstable(), getTruncatedArguments());
}
return contextStrippedRequest;
}
@Override
public LinkRequest replaceArguments(CallSiteDescriptor callSiteDescriptor, Object[] arguments) {
return new RuntimeContextLinkRequestImpl(callSiteDescriptor, isCallSiteUnstable(), arguments,
public LinkRequest replaceArguments(final CallSiteDescriptor callSiteDescriptor, final Object[] arguments) {
return new RuntimeContextLinkRequestImpl(callSiteDescriptor, getCallSiteToken(), getLinkCount(), isCallSiteUnstable(), arguments,
runtimeContextArgCount);
}

View File

@ -115,12 +115,12 @@ public class TypeConverterFactory {
protected ClassMap<MethodHandle> computeValue(final Class<?> sourceType) {
return new ClassMap<MethodHandle>(getClassLoader(sourceType)) {
@Override
protected MethodHandle computeValue(Class<?> targetType) {
protected MethodHandle computeValue(final Class<?> targetType) {
try {
return createConverter(sourceType, targetType);
} catch (RuntimeException e) {
} catch (final RuntimeException e) {
throw e;
} catch (Exception e) {
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
@ -133,7 +133,7 @@ public class TypeConverterFactory {
protected ClassMap<MethodHandle> computeValue(final Class<?> sourceType) {
return new ClassMap<MethodHandle>(getClassLoader(sourceType)) {
@Override
protected MethodHandle computeValue(Class<?> targetType) {
protected MethodHandle computeValue(final Class<?> targetType) {
if(!canAutoConvert(sourceType, targetType)) {
final MethodHandle converter = getCacheableTypeConverter(sourceType, targetType);
if(converter != IDENTITY_CONVERSION) {
@ -151,12 +151,12 @@ public class TypeConverterFactory {
protected ClassMap<Boolean> computeValue(final Class<?> sourceType) {
return new ClassMap<Boolean>(getClassLoader(sourceType)) {
@Override
protected Boolean computeValue(Class<?> targetType) {
protected Boolean computeValue(final Class<?> targetType) {
try {
return getTypeConverterNull(sourceType, targetType) != null;
} catch (RuntimeException e) {
} catch (final RuntimeException e) {
throw e;
} catch (Exception e) {
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
@ -178,10 +178,10 @@ public class TypeConverterFactory {
*
* @param factories the {@link GuardingTypeConverterFactory} instances to compose.
*/
public TypeConverterFactory(Iterable<? extends GuardingTypeConverterFactory> factories) {
public TypeConverterFactory(final Iterable<? extends GuardingTypeConverterFactory> factories) {
final List<GuardingTypeConverterFactory> l = new LinkedList<>();
final List<ConversionComparator> c = new LinkedList<>();
for(GuardingTypeConverterFactory factory: factories) {
for(final GuardingTypeConverterFactory factory: factories) {
l.add(factory);
if(factory instanceof ConversionComparator) {
c.add((ConversionComparator)factory);
@ -206,7 +206,7 @@ public class TypeConverterFactory {
* {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with
* {@link GuardingTypeConverterFactory} produced type converters as filters.
*/
public MethodHandle asType(MethodHandle handle, final MethodType fromType) {
public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
MethodHandle newHandle = handle;
final MethodType toType = newHandle.type();
final int l = toType.parameterCount();
@ -250,7 +250,7 @@ public class TypeConverterFactory {
return newHandle.asType(fromType);
}
private static MethodHandle applyConverters(MethodHandle handle, int pos, List<MethodHandle> converters) {
private static MethodHandle applyConverters(final MethodHandle handle, final int pos, final List<MethodHandle> converters) {
if(converters.isEmpty()) {
return handle;
}
@ -285,8 +285,8 @@ public class TypeConverterFactory {
* @return one of Comparison constants that establish which - if any - of the target types is preferable for the
* conversion.
*/
public Comparison compareConversion(Class<?> sourceType, Class<?> targetType1, Class<?> targetType2) {
for(ConversionComparator comparator: comparators) {
public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
for(final ConversionComparator comparator: comparators) {
final Comparison result = comparator.compareConversion(sourceType, targetType1, targetType2);
if(result != Comparison.INDETERMINATE) {
return result;
@ -313,20 +313,20 @@ public class TypeConverterFactory {
return TypeUtilities.isMethodInvocationConvertible(fromType, toType);
}
/*private*/ MethodHandle getCacheableTypeConverterNull(Class<?> sourceType, Class<?> targetType) {
/*private*/ MethodHandle getCacheableTypeConverterNull(final Class<?> sourceType, final Class<?> targetType) {
final MethodHandle converter = getCacheableTypeConverter(sourceType, targetType);
return converter == IDENTITY_CONVERSION ? null : converter;
}
/*private*/ MethodHandle getTypeConverterNull(Class<?> sourceType, Class<?> targetType) {
/*private*/ MethodHandle getTypeConverterNull(final Class<?> sourceType, final Class<?> targetType) {
try {
return getCacheableTypeConverterNull(sourceType, targetType);
} catch(NotCacheableConverter e) {
} catch(final NotCacheableConverter e) {
return e.converter;
}
}
/*private*/ MethodHandle getCacheableTypeConverter(Class<?> sourceType, Class<?> targetType) {
/*private*/ MethodHandle getCacheableTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
return converterMap.get(sourceType).get(targetType);
}
@ -339,15 +339,15 @@ public class TypeConverterFactory {
* @param targetType the type to convert to
* @return a method handle performing the conversion.
*/
public MethodHandle getTypeConverter(Class<?> sourceType, Class<?> targetType) {
public MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
try {
return converterIdentityMap.get(sourceType).get(targetType);
} catch(NotCacheableConverter e) {
} catch(final NotCacheableConverter e) {
return e.converter;
}
}
/*private*/ MethodHandle createConverter(Class<?> sourceType, Class<?> targetType) throws Exception {
/*private*/ MethodHandle createConverter(final Class<?> sourceType, final Class<?> targetType) throws Exception {
final MethodType type = MethodType.methodType(targetType, sourceType);
final MethodHandle identity = IDENTITY_CONVERSION.asType(type);
MethodHandle last = identity;
@ -372,6 +372,7 @@ public class TypeConverterFactory {
/*private*/ static final MethodHandle IDENTITY_CONVERSION = MethodHandles.identity(Object.class);
@SuppressWarnings("serial")
private static class NotCacheableConverter extends RuntimeException {
final MethodHandle converter;

View File

@ -106,38 +106,49 @@ public class TypeUtilities {
}
/**
* Given two types represented by c1 and c2, returns a type that is their most specific common superclass or
* superinterface.
* Given two types represented by c1 and c2, returns a type that is their most specific common supertype for
* purposes of lossless conversions.
*
* @param c1 one type
* @param c2 another type
* @return their most common superclass or superinterface. If they have several unrelated superinterfaces as their
* most specific common type, or the types themselves are completely unrelated interfaces, {@link java.lang.Object}
* is returned.
* @return their most common superclass or superinterface for purposes of lossless conversions. If they have several
* unrelated superinterfaces as their most specific common type, or the types themselves are completely
* unrelated interfaces, {@link java.lang.Object} is returned.
*/
public static Class<?> getMostSpecificCommonType(Class<?> c1, Class<?> c2) {
public static Class<?> getCommonLosslessConversionType(final Class<?> c1, final Class<?> c2) {
if(c1 == c2) {
return c1;
} else if(isConvertibleWithoutLoss(c2, c1)) {
return c1;
} else if(isConvertibleWithoutLoss(c1, c2)) {
return c2;
}
Class<?> c3 = c2;
if(c3.isPrimitive()) {
if(c3 == Byte.TYPE)
c3 = Byte.class;
else if(c3 == Short.TYPE)
c3 = Short.class;
else if(c3 == Character.TYPE)
c3 = Character.class;
else if(c3 == Integer.TYPE)
c3 = Integer.class;
else if(c3 == Float.TYPE)
c3 = Float.class;
else if(c3 == Long.TYPE)
c3 = Long.class;
else if(c3 == Double.TYPE)
c3 = Double.class;
if(c1 == void.class) {
return c2;
} else if(c2 == void.class) {
return c1;
}
Set<Class<?>> a1 = getAssignables(c1, c3);
Set<Class<?>> a2 = getAssignables(c3, c1);
if(c1.isPrimitive() && c2.isPrimitive()) {
if((c1 == byte.class && c2 == char.class) || (c1 == char.class && c2 == byte.class)) {
// byte + char = int
return int.class;
} else if((c1 == short.class && c2 == char.class) || (c1 == char.class && c2 == short.class)) {
// short + char = int
return int.class;
} else if((c1 == int.class && c2 == float.class) || (c1 == float.class && c2 == int.class)) {
// int + float = double
return double.class;
}
}
// For all other cases. This will handle long + (float|double) = Number case as well as boolean + anything = Object case too.
return getMostSpecificCommonTypeUnequalNonprimitives(c1, c2);
}
private static Class<?> getMostSpecificCommonTypeUnequalNonprimitives(final Class<?> c1, final Class<?> c2) {
final Class<?> npc1 = c1.isPrimitive() ? getWrapperType(c1) : c1;
final Class<?> npc2 = c2.isPrimitive() ? getWrapperType(c2) : c2;
final Set<Class<?>> a1 = getAssignables(npc1, npc2);
final Set<Class<?>> a2 = getAssignables(npc2, npc1);
a1.retainAll(a2);
if(a1.isEmpty()) {
// Can happen when at least one of the arguments is an interface,
@ -148,10 +159,10 @@ public class TypeUtilities {
// thank to interfaces. I.e., if you call this method for String.class
// and Number.class, you'll have Comparable, Serializable, and Object
// as maximal elements.
List<Class<?>> max = new ArrayList<>();
outer: for(Class<?> clazz: a1) {
for(Iterator<Class<?>> maxiter = max.iterator(); maxiter.hasNext();) {
Class<?> maxClazz = maxiter.next();
final List<Class<?>> max = new ArrayList<>();
outer: for(final Class<?> clazz: a1) {
for(final Iterator<Class<?>> maxiter = max.iterator(); maxiter.hasNext();) {
final Class<?> maxClazz = maxiter.next();
if(isSubtype(maxClazz, clazz)) {
// It can't be maximal, if there's already a more specific
// maximal than it.
@ -168,26 +179,26 @@ public class TypeUtilities {
max.add(clazz);
}
if(max.size() > 1) {
return OBJECT_CLASS;
return Object.class;
}
return max.get(0);
}
private static Set<Class<?>> getAssignables(Class<?> c1, Class<?> c2) {
Set<Class<?>> s = new HashSet<>();
private static Set<Class<?>> getAssignables(final Class<?> c1, final Class<?> c2) {
final Set<Class<?>> s = new HashSet<>();
collectAssignables(c1, c2, s);
return s;
}
private static void collectAssignables(Class<?> c1, Class<?> c2, Set<Class<?>> s) {
private static void collectAssignables(final Class<?> c1, final Class<?> c2, final Set<Class<?>> s) {
if(c1.isAssignableFrom(c2)) {
s.add(c1);
}
Class<?> sc = c1.getSuperclass();
final Class<?> sc = c1.getSuperclass();
if(sc != null) {
collectAssignables(sc, c2, s);
}
Class<?>[] itf = c1.getInterfaces();
final Class<?>[] itf = c1.getInterfaces();
for(int i = 0; i < itf.length; ++i) {
collectAssignables(itf[i], c2, s);
}
@ -210,17 +221,17 @@ public class TypeUtilities {
return Collections.unmodifiableMap(wrapperTypes);
}
private static Map<String, Class<?>> createClassNameMapping(Collection<Class<?>> classes) {
private static Map<String, Class<?>> createClassNameMapping(final Collection<Class<?>> classes) {
final Map<String, Class<?>> map = new HashMap<>();
for(Class<?> clazz: classes) {
for(final Class<?> clazz: classes) {
map.put(clazz.getName(), clazz);
}
return map;
}
private static <K, V> Map<V, K> invertMap(Map<K, V> map) {
private static <K, V> Map<V, K> invertMap(final Map<K, V> map) {
final Map<V, K> inverted = new IdentityHashMap<>(map.size());
for(Map.Entry<K, V> entry: map.entrySet()) {
for(final Map.Entry<K, V> entry: map.entrySet()) {
inverted.put(entry.getValue(), entry.getKey());
}
return Collections.unmodifiableMap(inverted);
@ -232,29 +243,58 @@ public class TypeUtilities {
* {@link #isSubtype(Class, Class)}) as well as boxing conversion (JLS 5.1.7) optionally followed by widening
* reference conversion and unboxing conversion (JLS 5.1.8) optionally followed by widening primitive conversion.
*
* @param callSiteType the parameter type at the call site
* @param methodType the parameter type in the method declaration
* @return true if callSiteType is method invocation convertible to the methodType.
* @param sourceType the type being converted from (call site type for parameter types, method type for return types)
* @param targetType the parameter type being converted to (method type for parameter types, call site type for return types)
* @return true if source type is method invocation convertible to target type.
*/
public static boolean isMethodInvocationConvertible(Class<?> callSiteType, Class<?> methodType) {
if(methodType.isAssignableFrom(callSiteType)) {
public static boolean isMethodInvocationConvertible(final Class<?> sourceType, final Class<?> targetType) {
if(targetType.isAssignableFrom(sourceType)) {
return true;
}
if(callSiteType.isPrimitive()) {
if(methodType.isPrimitive()) {
return isProperPrimitiveSubtype(callSiteType, methodType);
if(sourceType.isPrimitive()) {
if(targetType.isPrimitive()) {
return isProperPrimitiveSubtype(sourceType, targetType);
}
// Boxing + widening reference conversion
return methodType.isAssignableFrom(WRAPPER_TYPES.get(callSiteType));
assert WRAPPER_TYPES.get(sourceType) != null : sourceType.getName();
return targetType.isAssignableFrom(WRAPPER_TYPES.get(sourceType));
}
if(methodType.isPrimitive()) {
final Class<?> unboxedCallSiteType = PRIMITIVE_TYPES.get(callSiteType);
if(targetType.isPrimitive()) {
final Class<?> unboxedCallSiteType = PRIMITIVE_TYPES.get(sourceType);
return unboxedCallSiteType != null
&& (unboxedCallSiteType == methodType || isProperPrimitiveSubtype(unboxedCallSiteType, methodType));
&& (unboxedCallSiteType == targetType || isProperPrimitiveSubtype(unboxedCallSiteType, targetType));
}
return false;
}
/**
* Determines whether a type can be converted to another without losing any
* precision.
*
* @param sourceType the source type
* @param targetType the target type
* @return true if lossless conversion is possible
*/
public static boolean isConvertibleWithoutLoss(final Class<?> sourceType, final Class<?> targetType) {
if(targetType.isAssignableFrom(sourceType)) {
return true;
}
if(sourceType.isPrimitive()) {
if(sourceType == void.class) {
return false; // Void can't be losslessly represented by any type
}
if(targetType.isPrimitive()) {
return isProperPrimitiveLosslessSubtype(sourceType, targetType);
}
// Boxing + widening reference conversion
assert WRAPPER_TYPES.get(sourceType) != null : sourceType.getName();
return targetType.isAssignableFrom(WRAPPER_TYPES.get(sourceType));
}
// Can't convert from any non-primitive type to any primitive type without data loss because of null.
// Also, can't convert non-assignable reference types.
return false;
}
/**
* Determines whether one type can be potentially converted to another type at runtime. Allows a conversion between
* any subtype and supertype in either direction, and also allows a conversion between any two primitive types, as
@ -264,9 +304,9 @@ public class TypeUtilities {
* @param methodType the parameter type in the method declaration
* @return true if callSiteType is potentially convertible to the methodType.
*/
public static boolean isPotentiallyConvertible(Class<?> callSiteType, Class<?> methodType) {
public static boolean isPotentiallyConvertible(final Class<?> callSiteType, final Class<?> methodType) {
// Widening or narrowing reference conversion
if(methodType.isAssignableFrom(callSiteType) || callSiteType.isAssignableFrom(methodType)) {
if(areAssignable(callSiteType, methodType)) {
return true;
}
if(callSiteType.isPrimitive()) {
@ -286,6 +326,16 @@ public class TypeUtilities {
return false;
}
/**
* Returns true if either of the types is assignable from the other.
* @param c1 one of the types
* @param c2 another one of the types
* @return true if either c1 is assignable from c2 or c2 is assignable from c1.
*/
public static boolean areAssignable(final Class<?> c1, final Class<?> c2) {
return c1.isAssignableFrom(c2) || c2.isAssignableFrom(c1);
}
/**
* Determines whether one type is a subtype of another type, as per JLS 4.10 "Subtyping". Note: this is not strict
* or proper subtype, therefore true is also returned for identical types; to be completely precise, it allows
@ -297,7 +347,7 @@ public class TypeUtilities {
* @return true if subType can be converted by identity conversion, widening primitive conversion, or widening
* reference conversion to superType.
*/
public static boolean isSubtype(Class<?> subType, Class<?> superType) {
public static boolean isSubtype(final Class<?> subType, final Class<?> superType) {
// Covers both JLS 4.10.2 "Subtyping among Class and Interface Types"
// and JLS 4.10.3 "Subtyping among Array Types", as well as primitive
// type identity.
@ -328,7 +378,7 @@ public class TypeUtilities {
* @param superType the supposed supertype
* @return true if subType is a proper (not identical to) primitive subtype of the superType
*/
private static boolean isProperPrimitiveSubtype(Class<?> subType, Class<?> superType) {
private static boolean isProperPrimitiveSubtype(final Class<?> subType, final Class<?> superType) {
if(superType == boolean.class || subType == boolean.class) {
return false;
}
@ -353,6 +403,37 @@ public class TypeUtilities {
return false;
}
/**
* Similar to {@link #isProperPrimitiveSubtype(Class, Class)}, except it disallows conversions from int and long to
* float, and from long to double, as those can lose precision. It also disallows conversion from and to char and
* anything else (similar to boolean) as char is not meant to be an arithmetic type.
* @param subType the supposed subtype
* @param superType the supposed supertype
* @return true if subType is a proper (not identical to) primitive subtype of the superType that can be represented
* by the supertype without no precision loss.
*/
private static boolean isProperPrimitiveLosslessSubtype(final Class<?> subType, final Class<?> superType) {
if(superType == boolean.class || subType == boolean.class) {
return false;
}
if(superType == char.class || subType == char.class) {
return false;
}
if(subType == byte.class) {
return true;
}
if(subType == short.class) {
return superType != byte.class;
}
if(subType == int.class) {
return superType == long.class || superType == double.class;
}
if(subType == float.class) {
return superType == double.class;
}
return false;
}
private static final Map<Class<?>, Class<?>> WRAPPER_TO_PRIMITIVE_TYPES = createWrapperToPrimitiveTypes();
private static Map<Class<?>, Class<?>> createWrapperToPrimitiveTypes() {
@ -384,13 +465,13 @@ public class TypeUtilities {
return classes.keySet();
}
private static void addClassHierarchy(Map<Class<?>, Class<?>> map, Class<?> clazz) {
private static void addClassHierarchy(final Map<Class<?>, Class<?>> map, final Class<?> clazz) {
if(clazz == null) {
return;
}
map.put(clazz, clazz);
addClassHierarchy(map, clazz.getSuperclass());
for(Class<?> itf: clazz.getInterfaces()) {
for(final Class<?> itf: clazz.getInterfaces()) {
addClassHierarchy(map, itf);
}
}
@ -402,7 +483,7 @@ public class TypeUtilities {
* @return true if the class can be assigned from any boxed primitive. Basically, it is true if the class is any
* primitive wrapper class, or a superclass or superinterface of any primitive wrapper class.
*/
private static boolean isAssignableFromBoxedPrimitive(Class<?> clazz) {
private static boolean isAssignableFromBoxedPrimitive(final Class<?> clazz) {
return PRIMITIVE_WRAPPER_TYPES.contains(clazz);
}
@ -413,7 +494,7 @@ public class TypeUtilities {
* @return the class representing the primitive type, or null if the name does not correspond to a primitive type
* or is "void".
*/
public static Class<?> getPrimitiveTypeByName(String name) {
public static Class<?> getPrimitiveTypeByName(final String name) {
return PRIMITIVE_TYPES_BY_NAME.get(name);
}
@ -424,7 +505,7 @@ public class TypeUtilities {
* @param wrapperType the class object representing a wrapper for a primitive type
* @return the class object representing the primitive type, or null if the passed class is not a primitive wrapper.
*/
public static Class<?> getPrimitiveType(Class<?> wrapperType) {
public static Class<?> getPrimitiveType(final Class<?> wrapperType) {
return WRAPPER_TO_PRIMITIVE_TYPES.get(wrapperType);
}
@ -436,7 +517,7 @@ public class TypeUtilities {
* @param primitiveType the class object representing a primitive type
* @return the class object representing the wrapper type, or null if the passed class is not a primitive.
*/
public static Class<?> getWrapperType(Class<?> primitiveType) {
public static Class<?> getWrapperType(final Class<?> primitiveType) {
return WRAPPER_TYPES.get(primitiveType);
}
}

View File

@ -90,7 +90,7 @@ class UnnamedDynCallSiteDescriptor extends AbstractCallSiteDescriptor {
private final MethodType methodType;
private final String op;
UnnamedDynCallSiteDescriptor(String op, MethodType methodType) {
UnnamedDynCallSiteDescriptor(final String op, final MethodType methodType) {
this.op = op;
this.methodType = methodType;
}
@ -105,7 +105,7 @@ class UnnamedDynCallSiteDescriptor extends AbstractCallSiteDescriptor {
}
@Override
public String getNameToken(int i) {
public String getNameToken(final int i) {
switch(i) {
case 0: return "dyn";
case 1: return op;
@ -119,7 +119,7 @@ class UnnamedDynCallSiteDescriptor extends AbstractCallSiteDescriptor {
}
@Override
public CallSiteDescriptor changeMethodType(MethodType newMethodType) {
public CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
return CallSiteDescriptorFactory.getCanonicalPublicDescriptor(new UnnamedDynCallSiteDescriptor(op,
newMethodType));
}

View File

@ -83,4 +83,4 @@ isOfClassGuardAlwaysTrue=isOfClass guard for {0} in position {1} in method type
isOfClassGuardAlwaysFalse=isOfClass guard for {0} in position {1} in method type {2} at {3} will always return false
isArrayGuardAlwaysTrue=isArray guard in position {0} in method type {1} at {2} will always return true
isArrayGuardAlwaysFalse=isArray guard in position {0} in method type {1} at {2} will always return false
isArrayGuardAlwaysFalse=isArray guard in position {0} in method type {1} at {2} will always return false

View File

@ -65,8 +65,8 @@ final class Formatter {
while (m.find()) {
int index = index(m.group(1));
boolean previous = isPreviousArgument(m.group(2));
char conversion = m.group(6).charAt(0);
final boolean previous = isPreviousArgument(m.group(2));
final char conversion = m.group(6).charAt(0);
// skip over some formats
if (index < 0 || previous
@ -85,7 +85,7 @@ final class Formatter {
}
// current argument
Object arg = args[index - 1];
final Object arg = args[index - 1];
// for date we convert double to long
if (m.group(5) != null) {

View File

@ -26,7 +26,6 @@
package jdk.nashorn.api.scripting;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
/**

View File

@ -182,7 +182,7 @@ public abstract class NashornException extends RuntimeException {
if (ECMAErrors.isScriptFrame(st)) {
final String className = "<" + st.getFileName() + ">";
String methodName = st.getMethodName();
if (methodName.equals(CompilerConstants.RUN_SCRIPT.symbolName())) {
if (methodName.equals(CompilerConstants.PROGRAM.symbolName())) {
methodName = "<program>";
}
@ -224,10 +224,22 @@ public abstract class NashornException extends RuntimeException {
return buf.toString();
}
/**
* Get the thrown object. Subclass responsibility
* @return thrown object
*/
protected Object getThrown() {
return null;
}
/**
* Initialization function for ECMA errors. Stores the error
* in the ecmaError field of this class. It is only initialized
* once, and then reused
*
* @param global the global
* @return initialized exception
*/
protected NashornException initEcmaError(final ScriptObject global) {
if (ecmaError != null) {
return this; // initialized already!

View File

@ -123,7 +123,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
// load engine.js
@SuppressWarnings("resource")
private static Source loadEngineJSSource() {
final String script = "resources/engine.js";
try {
@ -281,7 +280,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
private static Source makeSource(final Reader reader, final ScriptContext ctxt) throws ScriptException {
try {
return sourceFor(getScriptName(ctxt), reader);
} catch (IOException e) {
} catch (final IOException e) {
throw new ScriptException(e);
}
}
@ -380,7 +379,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
// Arbitrary user Bindings implementation. Look for NASHORN_GLOBAL in it!
Object scope = bindings.get(NASHORN_GLOBAL);
final Object scope = bindings.get(NASHORN_GLOBAL);
if (scope instanceof ScriptObjectMirror) {
final Global glob = globalFromMirror((ScriptObjectMirror)scope);
if (glob != null) {
@ -397,7 +396,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
// Retrieve nashorn Global object from a given ScriptObjectMirror
private Global globalFromMirror(final ScriptObjectMirror mirror) {
ScriptObject sobj = mirror.getScriptObject();
final ScriptObject sobj = mirror.getScriptObject();
if (sobj instanceof Global && isOfContext((Global)sobj, nashornContext)) {
return (Global)sobj;
}
@ -456,7 +455,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
private void setContextVariables(final Global ctxtGlobal, final ScriptContext ctxt) {
// set "context" global variable via contextProperty - because this
// property is non-writable
contextProperty.setObjectValue(ctxtGlobal, ctxtGlobal, ctxt, false);
contextProperty.setValue(ctxtGlobal, ctxtGlobal, ctxt, false);
Object args = ScriptObjectMirror.unwrap(ctxt.getAttribute("arguments"), ctxtGlobal);
if (args == null || args == UNDEFINED) {
args = ScriptRuntime.EMPTY_ARRAY;
@ -671,7 +670,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
continue;
}
Object obj = sobj.get(method.getName());
final Object obj = sobj.get(method.getName());
if (! (obj instanceof ScriptFunction)) {
return false;
}

View File

@ -164,7 +164,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
* @param args arguments array passed to script engine.
* @return newly created script engine.
*/
public ScriptEngine getScriptEngine(final String[] args) {
public ScriptEngine getScriptEngine(final String... args) {
checkConfigPermission();
return new NashornScriptEngine(this, args, getAppClassLoader());
}
@ -220,7 +220,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
// Revisit: script engine implementation needs the capability to
// find the class loader of the context in which the script engine
// is running so that classes will be found and loaded properly
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
final ClassLoader ccl = Thread.currentThread().getContextClassLoader();
return (ccl == null)? NashornScriptEngineFactory.class.getClassLoader() : ccl;
}
}

View File

@ -43,13 +43,13 @@ import java.util.Set;
import java.util.concurrent.Callable;
import javax.script.Bindings;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
/**
* Mirror object that wraps a given Nashorn Script object.
@ -169,6 +169,12 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
});
}
/**
* Call member function
* @param functionName function name
* @param args arguments
* @return return value of function
*/
public Object callMember(final String functionName, final Object... args) {
functionName.getClass(); // null check
final Global oldGlobal = Context.getGlobal();
@ -496,7 +502,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
public void setProto(final Object proto) {
inGlobal(new Callable<Void>() {
@Override public Void call() {
sobj.setProtoCheck(unwrap(proto, global));
sobj.setPrototypeOf(unwrap(proto, global));
return null;
}
});
@ -729,7 +735,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
return global;
}
static Object translateUndefined(Object obj) {
static Object translateUndefined(final Object obj) {
return (obj == ScriptRuntime.UNDEFINED)? null : obj;
}

View File

@ -28,11 +28,11 @@ package jdk.nashorn.api.scripting;
import java.lang.invoke.MethodHandle;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
/**
* Utilities that are to be called from script code.

View File

@ -81,7 +81,7 @@ public final class URLReader extends Reader {
}
@Override
public int read(char cbuf[], int off, int len) throws IOException {
public int read(final char cbuf[], final int off, final int len) throws IOException {
return getReader().read(cbuf, off, len);
}

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal;
/**
* Small helper class for fast int deques
*/
public class IntDeque {
private int[] deque = new int[16];
private int nextFree = 0;
/**
* Push an int value
* @param value value
*/
public void push(final int value) {
if (nextFree == deque.length) {
final int[] newDeque = new int[nextFree * 2];
System.arraycopy(deque, 0, newDeque, 0, nextFree);
deque = newDeque;
}
deque[nextFree++] = value;
}
/**
* Pop an int value
* @return value
*/
public int pop() {
return deque[--nextFree];
}
/**
* Peek
* @return top value
*/
public int peek() {
return deque[nextFree - 1];
}
/**
* Get the value of the top element and increment it.
* @return top value
*/
public int getAndIncrement() {
return deque[nextFree - 1]++;
}
/**
* Decrement the value of the top element and return it.
* @return decremented top value
*/
public int decrementAndGet() {
return --deque[nextFree - 1];
}
/**
* Check if deque is empty
* @return true if empty
*/
public boolean isEmpty() {
return nextFree == 0;
}
}

View File

@ -0,0 +1,318 @@
/*
* 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.codegen;
import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS_VAR;
import static jdk.nashorn.internal.codegen.CompilerConstants.EXPLODED_ARGUMENT_PREFIX;
import java.lang.invoke.MethodType;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
import jdk.nashorn.internal.runtime.logging.Loggable;
import jdk.nashorn.internal.runtime.logging.Logger;
import jdk.nashorn.internal.runtime.options.Options;
/**
* An optimization that attempts to turn applies into calls. This pattern
* is very common for fake class instance creation, and apply
* introduces expensive args collection and boxing
*
* <pre>
* var Class = {
* create: function() {
* return function() { //vararg
* this.initialize.apply(this, arguments);
* }
* }
* };
*
* Color = Class.create();
*
* Color.prototype = {
* red: 0, green: 0, blue: 0,
* initialize: function(r,g,b) {
* this.red = r;
* this.green = g;
* this.blue = b;
* }
* }
*
* new Color(17, 47, 11);
* </pre>
*/
@Logger(name="apply2call")
public final class ApplySpecialization extends NodeVisitor<LexicalContext> implements Loggable {
private static final boolean USE_APPLY2CALL = Options.getBooleanProperty("nashorn.apply2call", true);
private final DebugLogger log;
private final Compiler compiler;
private final Set<Integer> changed = new HashSet<>();
private final Deque<List<IdentNode>> explodedArguments = new ArrayDeque<>();
private static final String ARGUMENTS = ARGUMENTS_VAR.symbolName();
/**
* Apply specialization optimization. Try to explode arguments and call
* applies as calls if they just pass on the "arguments" array and
* "arguments" doesn't escape.
*
* @param compiler compiler
*/
public ApplySpecialization(final Compiler compiler) {
super(new LexicalContext());
this.compiler = compiler;
this.log = initLogger(compiler.getContext());
}
@Override
public DebugLogger getLogger() {
return log;
}
@Override
public DebugLogger initLogger(final Context context) {
return context.getLogger(this.getClass());
}
/**
* Arguments may only be used as args to the apply. Everything else is disqualified
* We cannot control arguments if they escape from the method and go into an unknown
* scope, thus we are conservative and treat any access to arguments outside the
* apply call as a case of "we cannot apply the optimization".
*
* @return true if arguments escape
*/
private boolean argumentsEscape(final FunctionNode functionNode) {
final Deque<Set<Expression>> stack = new ArrayDeque<>();
//ensure that arguments is only passed as arg to apply
try {
functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
private boolean isCurrentArg(final Expression expr) {
return !stack.isEmpty() && stack.peek().contains(expr); //args to current apply call
}
private boolean isArguments(final Expression expr) {
return expr instanceof IdentNode && ARGUMENTS.equals(((IdentNode)expr).getName());
}
private boolean isParam(final String name) {
for (final IdentNode param : functionNode.getParameters()) {
if (param.getName().equals(name)) {
return true;
}
}
return false;
}
@Override
public Node leaveIdentNode(final IdentNode identNode) {
if (isParam(identNode.getName()) || ARGUMENTS.equals(identNode.getName()) && !isCurrentArg(identNode)) {
throw new UnsupportedOperationException();
}
return identNode;
}
@Override
public boolean enterCallNode(final CallNode callNode) {
final Set<Expression> callArgs = new HashSet<>();
if (isApply(callNode)) {
final List<Expression> argList = callNode.getArgs();
if (argList.size() != 2 || !isArguments(argList.get(argList.size() - 1))) {
throw new UnsupportedOperationException();
}
callArgs.addAll(callNode.getArgs());
}
stack.push(callArgs);
return true;
}
@Override
public Node leaveCallNode(final CallNode callNode) {
stack.pop();
return callNode;
}
});
} catch (final UnsupportedOperationException e) {
log.fine("'arguments' escapes, is not used in standard call dispatch, or is reassigned in '" + functionNode.getName() + "'. Aborting");
return true; //bad
}
return false;
}
@Override
public boolean enterCallNode(final CallNode callNode) {
return !explodedArguments.isEmpty();
}
@Override
public Node leaveCallNode(final CallNode callNode) {
//apply needs to be a global symbol or we don't allow it
final List<IdentNode> newParams = explodedArguments.peek();
if (isApply(callNode)) {
final List<Expression> newArgs = new ArrayList<>();
for (final Expression arg : callNode.getArgs()) {
if (arg instanceof IdentNode && ARGUMENTS.equals(((IdentNode)arg).getName())) {
newArgs.addAll(newParams);
} else {
newArgs.add(arg);
}
}
changed.add(lc.getCurrentFunction().getId());
final CallNode newCallNode = callNode.setArgs(newArgs).setIsApplyToCall();
log.fine("Transformed ",
callNode,
" from apply to call => ",
newCallNode,
" in ",
DebugLogger.quote(lc.getCurrentFunction().getName()));
return newCallNode;
}
return callNode;
}
private boolean pushExplodedArgs(final FunctionNode functionNode) {
int start = 0;
final MethodType actualCallSiteType = compiler.getCallSiteType(functionNode);
if (actualCallSiteType == null) {
return false;
}
assert actualCallSiteType.parameterType(actualCallSiteType.parameterCount() - 1) != Object[].class : "error vararg callsite passed to apply2call " + functionNode.getName() + " " + actualCallSiteType;
final TypeMap ptm = compiler.getTypeMap();
if (ptm.needsCallee()) {
start++;
}
start++; //we always uses this
final List<IdentNode> params = functionNode.getParameters();
final List<IdentNode> newParams = new ArrayList<>();
final long to = Math.max(params.size(), actualCallSiteType.parameterCount() - start);
for (int i = 0; i < to; i++) {
if (i >= params.size()) {
newParams.add(new IdentNode(functionNode.getToken(), functionNode.getFinish(), EXPLODED_ARGUMENT_PREFIX.symbolName() + (i)));
} else {
newParams.add(params.get(i));
}
}
explodedArguments.push(newParams);
return true;
}
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
if (!USE_APPLY2CALL) {
return false;
}
if (!Global.instance().isSpecialNameValid("apply")) {
log.fine("Apply transform disabled: apply/call overridden");
assert !Global.instance().isSpecialNameValid("call") : "call and apply should have the same SwitchPoint";
return false;
}
if (!compiler.isOnDemandCompilation()) {
return false;
}
if (functionNode.hasEval()) {
return false;
}
if (argumentsEscape(functionNode)) {
return false;
}
return pushExplodedArgs(functionNode);
}
/**
* Try to do the apply to call transformation
* @return true if successful, false otherwise
*/
@Override
public Node leaveFunctionNode(final FunctionNode functionNode0) {
FunctionNode newFunctionNode = functionNode0;
final String functionName = newFunctionNode.getName();
if (changed.contains(newFunctionNode.getId())) {
newFunctionNode = newFunctionNode.clearFlag(lc, FunctionNode.USES_ARGUMENTS).
setFlag(lc, FunctionNode.HAS_APPLY_TO_CALL_SPECIALIZATION).
setParameters(lc, explodedArguments.peek());
if (log.isEnabled()) {
log.info("Successfully specialized apply to call in '",
functionName,
" params=",
explodedArguments.peek(),
"' id=",
newFunctionNode.getId(),
" source=",
newFunctionNode.getSource().getURL());
}
}
explodedArguments.pop();
return newFunctionNode;
}
private static boolean isApply(final CallNode callNode) {
final Expression f = callNode.getFunction();
return f instanceof AccessNode && "apply".equals(((AccessNode)f).getProperty());
}
}

View File

@ -0,0 +1,946 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.codegen;
import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS_VAR;
import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE;
import static jdk.nashorn.internal.codegen.CompilerConstants.EXCEPTION_PREFIX;
import static jdk.nashorn.internal.codegen.CompilerConstants.ITERATOR_PREFIX;
import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
import static jdk.nashorn.internal.codegen.CompilerConstants.SWITCH_TAG_PREFIX;
import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
import static jdk.nashorn.internal.ir.Symbol.HAS_OBJECT_VALUE;
import static jdk.nashorn.internal.ir.Symbol.IS_FUNCTION_SELF;
import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL;
import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
import static jdk.nashorn.internal.ir.Symbol.IS_LET;
import static jdk.nashorn.internal.ir.Symbol.IS_PARAM;
import static jdk.nashorn.internal.ir.Symbol.IS_PROGRAM_LEVEL;
import static jdk.nashorn.internal.ir.Symbol.IS_SCOPE;
import static jdk.nashorn.internal.ir.Symbol.IS_THIS;
import static jdk.nashorn.internal.ir.Symbol.IS_VAR;
import static jdk.nashorn.internal.ir.Symbol.KINDMASK;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LexicalContextNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.RuntimeNode.Request;
import jdk.nashorn.internal.ir.SplitNode;
import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.TryNode;
import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WithNode;
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
import jdk.nashorn.internal.runtime.logging.Loggable;
import jdk.nashorn.internal.runtime.logging.Logger;
/**
* This visitor assigns symbols to identifiers denoting variables. It does few more minor calculations that are only
* possible after symbols have been assigned; such is the transformation of "delete" and "typeof" operators into runtime
* nodes and counting of number of properties assigned to "this" in constructor functions. This visitor is also notable
* for what it doesn't do, most significantly it does no type calculations as in JavaScript variables can change types
* during runtime and as such symbols don't have types. Calculation of expression types is performed by a separate
* visitor.
*/
@Logger(name="symbols")
final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements Loggable {
private final DebugLogger log;
private final boolean debug;
private static boolean isParamOrVar(final IdentNode identNode) {
final Symbol symbol = identNode.getSymbol();
return symbol.isParam() || symbol.isVar();
}
private static String name(final Node node) {
final String cn = node.getClass().getName();
final int lastDot = cn.lastIndexOf('.');
if (lastDot == -1) {
return cn;
}
return cn.substring(lastDot + 1);
}
/**
* Checks if various symbols that were provisionally marked as needing a slot ended up unused, and marks them as not
* needing a slot after all.
* @param functionNode the function node
* @return the passed in node, for easy chaining
*/
private static FunctionNode removeUnusedSlots(final FunctionNode functionNode) {
if (!functionNode.needsCallee()) {
functionNode.compilerConstant(CALLEE).setNeedsSlot(false);
}
if (!(functionNode.hasScopeBlock() || functionNode.needsParentScope())) {
functionNode.compilerConstant(SCOPE).setNeedsSlot(false);
}
if (!functionNode.usesReturnSymbol()) {
functionNode.compilerConstant(RETURN).setNeedsSlot(false);
}
// Named function expressions that end up not referencing themselves won't need a local slot for the self symbol.
if(!functionNode.isDeclared() && !functionNode.usesSelfSymbol() && !functionNode.isAnonymous()) {
final Symbol selfSymbol = functionNode.getBody().getExistingSymbol(functionNode.getIdent().getName());
if(selfSymbol != null) {
if(selfSymbol.isFunctionSelf()) {
selfSymbol.setNeedsSlot(false);
selfSymbol.clearFlag(Symbol.IS_VAR);
}
} else {
assert functionNode.isProgram();
}
}
return functionNode;
}
private final Deque<Set<String>> thisProperties = new ArrayDeque<>();
private final Map<String, Symbol> globalSymbols = new HashMap<>(); //reuse the same global symbol
private final Compiler compiler;
public AssignSymbols(final Compiler compiler) {
super(new LexicalContext());
this.compiler = compiler;
this.log = initLogger(compiler.getContext());
this.debug = log.isEnabled();
}
@Override
public DebugLogger getLogger() {
return log;
}
@Override
public DebugLogger initLogger(final Context context) {
return context.getLogger(this.getClass());
}
/**
* Define symbols for all variable declarations at the top of the function scope. This way we can get around
* problems like
*
* while (true) {
* break;
* if (true) {
* var s;
* }
* }
*
* to an arbitrary nesting depth.
*
* see NASHORN-73
*
* @param functionNode the FunctionNode we are entering
* @param body the body of the FunctionNode we are entering
*/
private void acceptDeclarations(final FunctionNode functionNode, final Block body) {
// This visitor will assign symbol to all declared variables, except function declarations (which are taken care
// in a separate step above) and "var" declarations in for loop initializers.
//
body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public boolean enterFunctionNode(final FunctionNode nestedFn) {
// Don't descend into nested functions
return false;
}
@Override
public Node leaveVarNode(final VarNode varNode) {
if (varNode.isStatement()) {
final IdentNode ident = varNode.getName();
final Symbol symbol = defineSymbol(body, ident.getName(), IS_VAR);
functionNode.addDeclaredSymbol(symbol);
if (varNode.isFunctionDeclaration()) {
symbol.setIsFunctionDeclaration();
}
return varNode.setName((IdentNode)ident.setSymbol(symbol));
}
return varNode;
}
});
}
private IdentNode compilerConstantIdentifier(final CompilerConstants cc) {
return (IdentNode)createImplicitIdentifier(cc.symbolName()).setSymbol(lc.getCurrentFunction().compilerConstant(cc));
}
/**
* Creates an ident node for an implicit identifier within the function (one not declared in the script source
* code). These identifiers are defined with function's token and finish.
* @param name the name of the identifier
* @return an ident node representing the implicit identifier.
*/
private IdentNode createImplicitIdentifier(final String name) {
final FunctionNode fn = lc.getCurrentFunction();
return new IdentNode(fn.getToken(), fn.getFinish(), name);
}
private Symbol createSymbol(final String name, final int flags) {
if ((flags & Symbol.KINDMASK) == IS_GLOBAL) {
//reuse global symbols so they can be hashed
Symbol global = globalSymbols.get(name);
if (global == null) {
global = new Symbol(name, flags);
globalSymbols.put(name, global);
}
return global;
}
return new Symbol(name, flags);
}
/**
* Creates a synthetic initializer for a variable (a var statement that doesn't occur in the source code). Typically
* used to create assignmnent of {@code :callee} to the function name symbol in self-referential function
* expressions as well as for assignment of {@code :arguments} to {@code arguments}.
*
* @param name the ident node identifying the variable to initialize
* @param initConstant the compiler constant it is initialized to
* @param fn the function node the assignment is for
* @return a var node with the appropriate assignment
*/
private VarNode createSyntheticInitializer(final IdentNode name, final CompilerConstants initConstant, final FunctionNode fn) {
final IdentNode init = compilerConstantIdentifier(initConstant);
assert init.getSymbol() != null && init.getSymbol().isBytecodeLocal();
final VarNode synthVar = new VarNode(fn.getLineNumber(), fn.getToken(), fn.getFinish(), name, init);
final Symbol nameSymbol = fn.getBody().getExistingSymbol(name.getName());
assert nameSymbol != null;
return (VarNode)synthVar.setName((IdentNode)name.setSymbol(nameSymbol)).accept(this);
}
private FunctionNode createSyntheticInitializers(final FunctionNode functionNode) {
final List<VarNode> syntheticInitializers = new ArrayList<>(2);
// Must visit the new var nodes in the context of the body. We could also just set the new statements into the
// block and then revisit the entire block, but that seems to be too much double work.
final Block body = functionNode.getBody();
lc.push(body);
try {
if (functionNode.usesSelfSymbol()) {
// "var fn = :callee"
syntheticInitializers.add(createSyntheticInitializer(functionNode.getIdent(), CALLEE, functionNode));
}
if (functionNode.needsArguments()) {
// "var arguments = :arguments"
syntheticInitializers.add(createSyntheticInitializer(createImplicitIdentifier(ARGUMENTS_VAR.symbolName()),
ARGUMENTS, functionNode));
}
if (syntheticInitializers.isEmpty()) {
return functionNode;
}
for(final ListIterator<VarNode> it = syntheticInitializers.listIterator(); it.hasNext();) {
it.set((VarNode)it.next().accept(this));
}
} finally {
lc.pop(body);
}
final List<Statement> stmts = body.getStatements();
final List<Statement> newStatements = new ArrayList<>(stmts.size() + syntheticInitializers.size());
newStatements.addAll(syntheticInitializers);
newStatements.addAll(stmts);
return functionNode.setBody(lc, body.setStatements(lc, newStatements));
}
private Symbol defineGlobalSymbol(final Block block, final String name) {
return defineSymbol(block, name, IS_GLOBAL);
}
/**
* Defines a new symbol in the given block.
*
* @param block the block in which to define the symbol
* @param name name of symbol.
* @param symbolFlags Symbol flags.
*
* @return Symbol for given name or null for redefinition.
*/
private Symbol defineSymbol(final Block block, final String name, final int symbolFlags) {
int flags = symbolFlags;
Symbol symbol = findSymbol(block, name); // Locate symbol.
final boolean isGlobal = (flags & KINDMASK) == IS_GLOBAL;
// Global variables are implicitly always scope variables too.
if (isGlobal) {
flags |= IS_SCOPE;
}
if (lc.getCurrentFunction().isProgram()) {
flags |= IS_PROGRAM_LEVEL;
}
final boolean isParam = (flags & KINDMASK) == IS_PARAM;
final boolean isVar = (flags & KINDMASK) == IS_VAR;
final FunctionNode function = lc.getFunction(block);
if (symbol != null) {
// Symbol was already defined. Check if it needs to be redefined.
if (isParam) {
if (!isLocal(function, symbol)) {
// Not defined in this function. Create a new definition.
symbol = null;
} else if (symbol.isParam()) {
// Duplicate parameter. Null return will force an error.
throw new AssertionError("duplicate parameter");
}
} else if (isVar) {
if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET) {
// Always create a new definition.
symbol = null;
} else {
// Not defined in this function. Create a new definition.
if (!isLocal(function, symbol) || symbol.less(IS_VAR)) {
symbol = null;
}
}
}
}
if (symbol == null) {
// If not found, then create a new one.
Block symbolBlock;
// Determine where to create it.
if (isVar && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) {
symbolBlock = block; //internal vars are always defined in the block closest to them
} else if (isGlobal) {
symbolBlock = lc.getOutermostFunction().getBody();
} else {
symbolBlock = lc.getFunctionBody(function);
}
// Create and add to appropriate block.
symbol = createSymbol(name, flags);
symbolBlock.putSymbol(lc, symbol);
if ((flags & IS_SCOPE) == 0) {
// Initial assumption; symbol can lose its slot later
symbol.setNeedsSlot(true);
}
} else if (symbol.less(flags)) {
symbol.setFlags(flags);
}
if((isVar || isParam) && compiler.useOptimisticTypes() && compiler.isOnDemandCompilation()) {
compiler.declareLocalSymbol(name);
}
return symbol;
}
private <T extends Node> T end(final T node) {
return end(node, true);
}
private <T extends Node> T end(final T node, final boolean printNode) {
if (debug) {
final StringBuilder sb = new StringBuilder();
sb.append("[LEAVE ").
append(name(node)).
append("] ").
append(printNode ? node.toString() : "").
append(" in '").
append(lc.getCurrentFunction().getName()).
append('\'');
if (node instanceof IdentNode) {
final Symbol symbol = ((IdentNode)node).getSymbol();
if (symbol == null) {
sb.append(" <NO SYMBOL>");
} else {
sb.append(" <symbol=").append(symbol).append('>');
}
}
log.unindent();
log.info(sb);
}
return node;
}
@Override
public boolean enterBlock(final Block block) {
start(block);
block.clearSymbols();
if (lc.isFunctionBody()) {
enterFunctionBody();
}
return true;
}
@Override
public boolean enterCatchNode(final CatchNode catchNode) {
final IdentNode exception = catchNode.getException();
final Block block = lc.getCurrentBlock();
start(catchNode);
// define block-local exception variable
final String exname = exception.getName();
// If the name of the exception starts with ":e", this is a synthetic catch block, likely a catch-all. Its
// symbol is naturally internal, and should be treated as such.
final boolean isInternal = exname.startsWith(EXCEPTION_PREFIX.symbolName());
defineSymbol(block, exname, IS_VAR | IS_LET | (isInternal ? IS_INTERNAL : 0) | HAS_OBJECT_VALUE);
return true;
}
private void enterFunctionBody() {
final FunctionNode functionNode = lc.getCurrentFunction();
final Block body = lc.getCurrentBlock();
initFunctionWideVariables(functionNode, body);
if (functionNode.isProgram()) {
initGlobalSymbols(body);
} else if (!functionNode.isDeclared() && !functionNode.isAnonymous()) {
// It's neither declared nor program - it's a function expression then; assign it a self-symbol unless it's
// anonymous.
final String name = functionNode.getIdent().getName();
assert name != null;
assert body.getExistingSymbol(name) == null;
defineSymbol(body, name, IS_VAR | IS_FUNCTION_SELF | HAS_OBJECT_VALUE);
if(functionNode.allVarsInScope()) { // basically, has deep eval
lc.setFlag(functionNode, FunctionNode.USES_SELF_SYMBOL);
}
}
acceptDeclarations(functionNode, body);
}
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
// TODO: once we have information on symbols used by nested functions, we can stop descending into nested
// functions with on-demand compilation, e.g. add
// if(!thisProperties.isEmpty() && env.isOnDemandCompilation()) {
// return false;
// }
start(functionNode, false);
thisProperties.push(new HashSet<String>());
//an outermost function in our lexical context that is not a program
//is possible - it is a function being compiled lazily
if (functionNode.isDeclared()) {
final Iterator<Block> blocks = lc.getBlocks();
if (blocks.hasNext()) {
defineSymbol(blocks.next(), functionNode.getIdent().getName(), IS_VAR);
}
}
return true;
}
@Override
public boolean enterVarNode(final VarNode varNode) {
start(varNode);
defineSymbol(lc.getCurrentBlock(), varNode.getName().getName(), IS_VAR | (lc.getCurrentFunction().isProgram() ? IS_SCOPE : 0));
return true;
}
private Symbol exceptionSymbol() {
return newObjectInternal(EXCEPTION_PREFIX);
}
/**
* This has to run before fix assignment types, store any type specializations for
* paramters, then turn then to objects for the generic version of this method
*
* @param functionNode functionNode
*/
private FunctionNode finalizeParameters(final FunctionNode functionNode) {
final List<IdentNode> newParams = new ArrayList<>();
final boolean isVarArg = functionNode.isVarArg();
final Block body = functionNode.getBody();
for (final IdentNode param : functionNode.getParameters()) {
final Symbol paramSymbol = body.getExistingSymbol(param.getName());
assert paramSymbol != null;
assert paramSymbol.isParam() : paramSymbol + " " + paramSymbol.getFlags();
newParams.add((IdentNode)param.setSymbol(paramSymbol));
// parameters should not be slots for a function that uses variable arity signature
if (isVarArg) {
paramSymbol.setNeedsSlot(false);
}
}
return functionNode.setParameters(lc, newParams);
}
/**
* Search for symbol in the lexical context starting from the given block.
* @param name Symbol name.
* @return Found symbol or null if not found.
*/
private Symbol findSymbol(final Block block, final String name) {
for (final Iterator<Block> blocks = lc.getBlocks(block); blocks.hasNext();) {
final Symbol symbol = blocks.next().getExistingSymbol(name);
if (symbol != null) {
return symbol;
}
}
return null;
}
/**
* Marks the current function as one using any global symbol. The function and all its parent functions will all be
* marked as needing parent scope.
* @see FunctionNode#needsParentScope()
*/
private void functionUsesGlobalSymbol() {
for (final Iterator<FunctionNode> fns = lc.getFunctions(); fns.hasNext();) {
lc.setFlag(fns.next(), FunctionNode.USES_ANCESTOR_SCOPE);
}
}
/**
* Marks the current function as one using a scoped symbol. The block defining the symbol will be marked as needing
* its own scope to hold the variable. If the symbol is defined outside of the current function, it and all
* functions up to (but not including) the function containing the defining block will be marked as needing parent
* function scope.
* @see FunctionNode#needsParentScope()
*/
private void functionUsesScopeSymbol(final Symbol symbol) {
final String name = symbol.getName();
for (final Iterator<LexicalContextNode> contextNodeIter = lc.getAllNodes(); contextNodeIter.hasNext(); ) {
final LexicalContextNode node = contextNodeIter.next();
if (node instanceof Block) {
final Block block = (Block)node;
if (block.getExistingSymbol(name) != null) {
assert lc.contains(block);
lc.setBlockNeedsScope(block);
break;
}
} else if (node instanceof FunctionNode) {
lc.setFlag(node, FunctionNode.USES_ANCESTOR_SCOPE);
}
}
}
/**
* Declares that the current function is using the symbol.
* @param symbol the symbol used by the current function.
*/
private void functionUsesSymbol(final Symbol symbol) {
assert symbol != null;
if (symbol.isScope()) {
if (symbol.isGlobal()) {
functionUsesGlobalSymbol();
} else {
functionUsesScopeSymbol(symbol);
}
} else {
assert !symbol.isGlobal(); // Every global is also scope
}
}
private void initCompileConstant(final CompilerConstants cc, final Block block, final int flags) {
defineSymbol(block, cc.symbolName(), flags).setNeedsSlot(true);
}
private void initFunctionWideVariables(final FunctionNode functionNode, final Block body) {
initCompileConstant(CALLEE, body, IS_PARAM | IS_INTERNAL | HAS_OBJECT_VALUE);
initCompileConstant(THIS, body, IS_PARAM | IS_THIS | HAS_OBJECT_VALUE);
if (functionNode.isVarArg()) {
initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL | HAS_OBJECT_VALUE);
if (functionNode.needsArguments()) {
initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL | HAS_OBJECT_VALUE);
defineSymbol(body, ARGUMENTS_VAR.symbolName(), IS_VAR | HAS_OBJECT_VALUE);
}
}
initParameters(functionNode, body);
initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL | HAS_OBJECT_VALUE);
initCompileConstant(RETURN, body, IS_VAR | IS_INTERNAL);
}
/**
* Move any properties from the global map into the scope of this function (which must be a program function).
* @param block the function node body for which to init scope vars
*/
private void initGlobalSymbols(final Block block) {
final PropertyMap map = Context.getGlobalMap();
for (final Property property : map.getProperties()) {
final Symbol symbol = defineGlobalSymbol(block, property.getKey());
log.info("Added global symbol from property map ", symbol);
}
}
/**
* Initialize parameters for function node.
* @param functionNode the function node
*/
private void initParameters(final FunctionNode functionNode, final Block body) {
final boolean isVarArg = functionNode.isVarArg();
final boolean scopeParams = functionNode.allVarsInScope() || isVarArg;
for (final IdentNode param : functionNode.getParameters()) {
final Symbol symbol = defineSymbol(body, param.getName(), IS_PARAM);
if(scopeParams) {
// NOTE: this "set is scope" is a poor substitute for clear expression of where the symbol is stored.
// It will force creation of scopes where they would otherwise not necessarily be needed (functions
// using arguments object and other variable arity functions). Tracked by JDK-8038942.
symbol.setIsScope();
assert symbol.hasSlot();
if(isVarArg) {
symbol.setNeedsSlot(false);
}
}
}
}
/**
* Is the symbol local to (that is, defined in) the specified function?
* @param function the function
* @param symbol the symbol
* @return true if the symbol is defined in the specified function
*/
private boolean isLocal(final FunctionNode function, final Symbol symbol) {
final FunctionNode definingFn = lc.getDefiningFunction(symbol);
assert definingFn != null;
return definingFn == function;
}
@Override
public Node leaveASSIGN(final BinaryNode binaryNode) {
// If we're assigning a property of the this object ("this.foo = ..."), record it.
final Expression lhs = binaryNode.lhs();
if (lhs instanceof AccessNode) {
final AccessNode accessNode = (AccessNode) lhs;
final Expression base = accessNode.getBase();
if (base instanceof IdentNode) {
final Symbol symbol = ((IdentNode)base).getSymbol();
if(symbol.isThis()) {
thisProperties.peek().add(accessNode.getProperty());
}
}
}
return binaryNode;
}
@Override
public Node leaveDELETE(final UnaryNode unaryNode) {
final FunctionNode currentFunctionNode = lc.getCurrentFunction();
final boolean strictMode = currentFunctionNode.isStrict();
final Expression rhs = unaryNode.getExpression();
final Expression strictFlagNode = (Expression)LiteralNode.newInstance(unaryNode, strictMode).accept(this);
Request request = Request.DELETE;
final List<Expression> args = new ArrayList<>();
if (rhs instanceof IdentNode) {
final IdentNode ident = (IdentNode)rhs;
// If this is a declared variable or a function parameter, delete always fails (except for globals).
final String name = ident.getName();
final Symbol symbol = ident.getSymbol();
final boolean failDelete = strictMode || symbol.isParam() || (symbol.isVar() && !symbol.isProgramLevel());
if (failDelete && symbol.isThis()) {
return LiteralNode.newInstance(unaryNode, true).accept(this);
}
final Expression literalNode = (Expression)LiteralNode.newInstance(unaryNode, name).accept(this);
if (!failDelete) {
args.add(compilerConstantIdentifier(SCOPE));
}
args.add(literalNode);
args.add(strictFlagNode);
if (failDelete) {
request = Request.FAIL_DELETE;
}
} else if (rhs instanceof AccessNode) {
final Expression base = ((AccessNode)rhs).getBase();
final String property = ((AccessNode)rhs).getProperty();
args.add(base);
args.add((Expression)LiteralNode.newInstance(unaryNode, property).accept(this));
args.add(strictFlagNode);
} else if (rhs instanceof IndexNode) {
final IndexNode indexNode = (IndexNode)rhs;
final Expression base = indexNode.getBase();
final Expression index = indexNode.getIndex();
args.add(base);
args.add(index);
args.add(strictFlagNode);
} else {
return LiteralNode.newInstance(unaryNode, true).accept(this);
}
return new RuntimeNode(unaryNode, request, args).accept(this);
}
@Override
public Node leaveForNode(final ForNode forNode) {
if (forNode.isForIn()) {
forNode.setIterator(newObjectInternal(ITERATOR_PREFIX)); //NASHORN-73
}
return end(forNode);
}
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
return markProgramBlock(
removeUnusedSlots(
createSyntheticInitializers(
finalizeParameters(
lc.applyTopFlags(functionNode))))
.setThisProperties(lc, thisProperties.pop().size())
.setState(lc, CompilationState.SYMBOLS_ASSIGNED));
}
@Override
public Node leaveIdentNode(final IdentNode identNode) {
final String name = identNode.getName();
if (identNode.isPropertyName()) {
return identNode;
}
final Block block = lc.getCurrentBlock();
Symbol symbol = findSymbol(block, name);
//If an existing symbol with the name is found, use that otherwise, declare a new one
if (symbol != null) {
log.info("Existing symbol = ", symbol);
if (symbol.isFunctionSelf()) {
final FunctionNode functionNode = lc.getDefiningFunction(symbol);
assert functionNode != null;
assert lc.getFunctionBody(functionNode).getExistingSymbol(CALLEE.symbolName()) != null;
lc.setFlag(functionNode, FunctionNode.USES_SELF_SYMBOL);
}
// if symbol is non-local or we're in a with block, we need to put symbol in scope (if it isn't already)
maybeForceScope(symbol);
} else {
log.info("No symbol exists. Declare as global: ", symbol);
symbol = defineGlobalSymbol(block, name);
Symbol.setSymbolIsScope(lc, symbol);
}
functionUsesSymbol(symbol);
if (!identNode.isInitializedHere()) {
symbol.increaseUseCount();
}
return end(identNode.setSymbol(symbol));
}
@Override
public Node leaveSwitchNode(final SwitchNode switchNode) {
// We only need a symbol for the tag if it's not an integer switch node
if(!switchNode.isInteger()) {
switchNode.setTag(newObjectInternal(SWITCH_TAG_PREFIX));
}
return switchNode;
}
@Override
public Node leaveTryNode(final TryNode tryNode) {
tryNode.setException(exceptionSymbol());
if (tryNode.getFinallyBody() != null) {
tryNode.setFinallyCatchAll(exceptionSymbol());
}
end(tryNode);
return tryNode;
}
@Override
public Node leaveTYPEOF(final UnaryNode unaryNode) {
final Expression rhs = unaryNode.getExpression();
final List<Expression> args = new ArrayList<>();
if (rhs instanceof IdentNode && !isParamOrVar((IdentNode)rhs)) {
args.add(compilerConstantIdentifier(SCOPE));
args.add((Expression)LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null
} else {
args.add(rhs);
args.add((Expression)LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this'
}
final Node runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args).accept(this);
end(unaryNode);
return runtimeNode;
}
private FunctionNode markProgramBlock(final FunctionNode functionNode) {
if (compiler.isOnDemandCompilation() || !functionNode.isProgram()) {
return functionNode;
}
assert functionNode.getId() == 1;
return functionNode.setBody(lc, functionNode.getBody().setFlag(lc, Block.IS_GLOBAL_SCOPE));
}
/**
* If the symbol isn't already a scope symbol, but it needs to be (see {@link #symbolNeedsToBeScope(Symbol)}, it is
* promoted to a scope symbol and its block marked as needing a scope.
* @param symbol the symbol that might be scoped
*/
private void maybeForceScope(final Symbol symbol) {
if (!symbol.isScope() && symbolNeedsToBeScope(symbol)) {
Symbol.setSymbolIsScope(lc, symbol);
}
}
private Symbol newInternal(final CompilerConstants cc, final int flags) {
return defineSymbol(lc.getCurrentBlock(), lc.getCurrentFunction().uniqueName(cc.symbolName()), IS_VAR | IS_INTERNAL | flags); //NASHORN-73
}
private Symbol newObjectInternal(final CompilerConstants cc) {
return newInternal(cc, HAS_OBJECT_VALUE);
}
private boolean start(final Node node) {
return start(node, true);
}
private boolean start(final Node node, final boolean printNode) {
if (debug) {
final StringBuilder sb = new StringBuilder();
sb.append("[ENTER ").
append(name(node)).
append("] ").
append(printNode ? node.toString() : "").
append(" in '").
append(lc.getCurrentFunction().getName()).
append("'");
log.info(sb);
log.indent();
}
return true;
}
/**
* Determines if the symbol has to be a scope symbol. In general terms, it has to be a scope symbol if it can only
* be reached from the current block by traversing a function node, a split node, or a with node.
* @param symbol the symbol checked for needing to be a scope symbol
* @return true if the symbol has to be a scope symbol.
*/
private boolean symbolNeedsToBeScope(final Symbol symbol) {
if (symbol.isThis() || symbol.isInternal()) {
return false;
}
if (lc.getCurrentFunction().allVarsInScope()) {
return true;
}
boolean previousWasBlock = false;
for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) {
final LexicalContextNode node = it.next();
if (node instanceof FunctionNode || node instanceof SplitNode || isSplitArray(node)) {
// We reached the function boundary or a splitting boundary without seeing a definition for the symbol.
// It needs to be in scope.
return true;
} else if (node instanceof WithNode) {
if (previousWasBlock) {
// We reached a WithNode; the symbol must be scoped. Note that if the WithNode was not immediately
// preceded by a block, this means we're currently processing its expression, not its body,
// therefore it doesn't count.
return true;
}
previousWasBlock = false;
} else if (node instanceof Block) {
if (((Block)node).getExistingSymbol(symbol.getName()) == symbol) {
// We reached the block that defines the symbol without reaching either the function boundary, or a
// WithNode. The symbol need not be scoped.
return false;
}
previousWasBlock = true;
} else {
previousWasBlock = false;
}
}
throw new AssertionError();
}
private static boolean isSplitArray(final LexicalContextNode expr) {
if(!(expr instanceof ArrayLiteralNode)) {
return false;
}
final List<ArrayUnit> units = ((ArrayLiteralNode)expr).getUnits();
return !(units == null || units.isEmpty());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -32,10 +32,10 @@ import static jdk.nashorn.internal.codegen.Condition.LE;
import static jdk.nashorn.internal.codegen.Condition.LT;
import static jdk.nashorn.internal.codegen.Condition.NE;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.JoinPredecessorExpression;
import jdk.nashorn.internal.ir.LocalVariableConversion;
import jdk.nashorn.internal.ir.UnaryNode;
/**
@ -57,7 +57,7 @@ final class BranchOptimizer {
}
private void branchOptimizer(final UnaryNode unaryNode, final Label label, final boolean state) {
final Expression rhs = unaryNode.rhs();
final Expression rhs = unaryNode.getExpression();
switch (unaryNode.tokenType()) {
case NOT:
@ -71,13 +71,7 @@ final class BranchOptimizer {
break;
}
// convert to boolean
codegen.load(unaryNode, Type.BOOLEAN);
if (state) {
method.ifne(label);
} else {
method.ifeq(label);
}
loadTestAndJump(unaryNode, label, state);
}
private void branchOptimizer(final BinaryNode binaryNode, final Label label, final boolean state) {
@ -88,86 +82,97 @@ final class BranchOptimizer {
case AND:
if (state) {
final Label skip = new Label("skip");
branchOptimizer(lhs, skip, false);
branchOptimizer(rhs, label, true);
optimizeLogicalOperand(lhs, skip, false, false);
optimizeLogicalOperand(rhs, label, true, true);
method.label(skip);
} else {
branchOptimizer(lhs, label, false);
branchOptimizer(rhs, label, false);
optimizeLogicalOperand(lhs, label, false, false);
optimizeLogicalOperand(rhs, label, false, true);
}
return;
case OR:
if (state) {
branchOptimizer(lhs, label, true);
branchOptimizer(rhs, label, true);
optimizeLogicalOperand(lhs, label, true, false);
optimizeLogicalOperand(rhs, label, true, true);
} else {
final Label skip = new Label("skip");
branchOptimizer(lhs, skip, true);
branchOptimizer(rhs, label, false);
optimizeLogicalOperand(lhs, skip, true, false);
optimizeLogicalOperand(rhs, label, false, true);
method.label(skip);
}
return;
case EQ:
case EQ_STRICT:
codegen.loadBinaryOperands(lhs, rhs, Type.widest(lhs.getType(), rhs.getType()));
codegen.loadBinaryOperands(binaryNode);
method.conditionalJump(state ? EQ : NE, true, label);
return;
case NE:
case NE_STRICT:
codegen.loadBinaryOperands(lhs, rhs, Type.widest(lhs.getType(), rhs.getType()));
codegen.loadBinaryOperands(binaryNode);
method.conditionalJump(state ? NE : EQ, true, label);
return;
case GE:
codegen.loadBinaryOperands(lhs, rhs, Type.widest(lhs.getType(), rhs.getType()));
method.conditionalJump(state ? GE : LT, !state, label);
codegen.loadBinaryOperands(binaryNode);
method.conditionalJump(state ? GE : LT, false, label);
return;
case GT:
codegen.loadBinaryOperands(lhs, rhs, Type.widest(lhs.getType(), rhs.getType()));
method.conditionalJump(state ? GT : LE, !state, label);
codegen.loadBinaryOperands(binaryNode);
method.conditionalJump(state ? GT : LE, false, label);
return;
case LE:
codegen.loadBinaryOperands(lhs, rhs, Type.widest(lhs.getType(), rhs.getType()));
method.conditionalJump(state ? LE : GT, state, label);
codegen.loadBinaryOperands(binaryNode);
method.conditionalJump(state ? LE : GT, true, label);
return;
case LT:
codegen.loadBinaryOperands(lhs, rhs, Type.widest(lhs.getType(), rhs.getType()));
method.conditionalJump(state ? LT : GE, state, label);
codegen.loadBinaryOperands(binaryNode);
method.conditionalJump(state ? LT : GE, true, label);
return;
default:
break;
}
codegen.load(binaryNode, Type.BOOLEAN);
if (state) {
method.ifne(label);
} else {
method.ifeq(label);
}
loadTestAndJump(binaryNode, label, state);
}
private void optimizeLogicalOperand(final Expression expr, final Label label, final boolean state, final boolean isRhs) {
final JoinPredecessorExpression jpexpr = (JoinPredecessorExpression)expr;
if(LocalVariableConversion.hasLiveConversion(jpexpr)) {
final Label after = new Label("after");
branchOptimizer(jpexpr.getExpression(), after, !state);
method.beforeJoinPoint(jpexpr);
method._goto(label);
method.label(after);
if(isRhs) {
method.beforeJoinPoint(jpexpr);
}
} else {
branchOptimizer(jpexpr.getExpression(), label, state);
}
}
private void branchOptimizer(final Expression node, final Label label, final boolean state) {
if (!(node instanceof TernaryNode)) {
if (node instanceof BinaryNode) {
branchOptimizer((BinaryNode)node, label, state);
return;
}
if (node instanceof UnaryNode) {
branchOptimizer((UnaryNode)node, label, state);
return;
}
if (node instanceof BinaryNode) {
branchOptimizer((BinaryNode)node, label, state);
return;
}
codegen.load(node, Type.BOOLEAN);
if (node instanceof UnaryNode) {
branchOptimizer((UnaryNode)node, label, state);
return;
}
loadTestAndJump(node, label, state);
}
private void loadTestAndJump(final Expression node, final Label label, final boolean state) {
codegen.loadExpressionAsBoolean(node);
if (state) {
method.ifne(label);
} else {

View File

@ -49,25 +49,27 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE;
import static jdk.nashorn.internal.codegen.CompilerConstants.className;
import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.SplitNode;
import jdk.nashorn.internal.ir.debug.NashornClassReader;
import jdk.nashorn.internal.ir.debug.NashornTextifier;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.RewriteException;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.Source;
@ -106,6 +108,8 @@ import jdk.nashorn.internal.runtime.Source;
* @see Compiler
*/
public class ClassEmitter implements Emitter {
/** Default flags for class generation - public class */
private static final EnumSet<Flag> DEFAULT_METHOD_FLAGS = EnumSet.of(Flag.PUBLIC);
/** Sanity check flag - have we started on a class? */
private boolean classStarted;
@ -123,10 +127,7 @@ public class ClassEmitter implements Emitter {
protected final ClassWriter cw;
/** The script environment */
protected final ScriptEnvironment env;
/** Default flags for class generation - oublic class */
private static final EnumSet<Flag> DEFAULT_METHOD_FLAGS = EnumSet.of(Flag.PUBLIC);
protected final Context context;
/** Compile unit class name. */
private String unitClassName;
@ -141,10 +142,8 @@ public class ClassEmitter implements Emitter {
* @param env script environment
* @param cw ASM classwriter
*/
private ClassEmitter(final ScriptEnvironment env, final ClassWriter cw) {
assert env != null;
this.env = env;
private ClassEmitter(final Context context, final ClassWriter cw) {
this.context = context;
this.cw = cw;
this.methodsStarted = new HashSet<>();
}
@ -157,8 +156,8 @@ public class ClassEmitter implements Emitter {
* @param superClassName super class name for class
* @param interfaceNames names of interfaces implemented by this class, or null if none
*/
ClassEmitter(final ScriptEnvironment env, final String className, final String superClassName, final String... interfaceNames) {
this(env, new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS));
ClassEmitter(final Context context, final String className, final String superClassName, final String... interfaceNames) {
this(context, new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS));
cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, className, null, superClassName, interfaceNames);
}
@ -170,8 +169,8 @@ public class ClassEmitter implements Emitter {
* @param unitClassName Compile unit class name.
* @param strictMode Should we generate this method in strict mode
*/
ClassEmitter(final ScriptEnvironment env, final String sourceName, final String unitClassName, final boolean strictMode) {
this(env,
ClassEmitter(final Context context, final String sourceName, final String unitClassName, final boolean strictMode) {
this(context,
new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) {
private static final String OBJECT_CLASS = "java/lang/Object";
@ -197,6 +196,10 @@ public class ClassEmitter implements Emitter {
defineCommonStatics(strictMode);
}
Context getContext() {
return context;
}
/**
* Returns the name of the compile unit class name.
* @return the name of the compile unit class name.
@ -274,51 +277,51 @@ public class ClassEmitter implements Emitter {
}
// $getXXXX$array - get the ith entry from the constants table and cast to XXXX[].
for (final Class<?> cls : constantMethodNeeded) {
if (cls.isArray()) {
defineGetArrayMethod(cls);
for (final Class<?> clazz : constantMethodNeeded) {
if (clazz.isArray()) {
defineGetArrayMethod(clazz);
}
}
}
/**
* Constructs a primitive specific method for getting the ith entry from the constants table and cast.
* @param cls Array class.
* Constructs a primitive specific method for getting the ith entry from the constants table as an array.
* @param clazz Array class.
*/
private void defineGetArrayMethod(final Class<?> cls) {
private void defineGetArrayMethod(final Class<?> clazz) {
assert unitClassName != null;
final String methodName = getArrayMethodName(cls);
final MethodEmitter getArrayMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), methodName, cls, int.class);
final String methodName = getArrayMethodName(clazz);
final MethodEmitter getArrayMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), methodName, clazz, int.class);
getArrayMethod.begin();
getArrayMethod.getStatic(unitClassName, CONSTANTS.symbolName(), CONSTANTS.descriptor())
.load(Type.INT, 0)
.arrayload()
.checkcast(cls)
.dup()
.arraylength()
.invoke(staticCallNoLookup(Arrays.class, "copyOf", cls, cls, int.class))
.checkcast(clazz)
.invoke(virtualCallNoLookup(clazz, "clone", Object.class))
.checkcast(clazz)
._return();
getArrayMethod.end();
}
/**
* Generate the name of a get array from constant pool method.
* @param cls Name of array class.
* @param clazz Name of array class.
* @return Method name.
*/
static String getArrayMethodName(final Class<?> cls) {
assert cls.isArray();
return GET_ARRAY_PREFIX.symbolName() + cls.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.symbolName();
static String getArrayMethodName(final Class<?> clazz) {
assert clazz.isArray();
return GET_ARRAY_PREFIX.symbolName() + clazz.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.symbolName();
}
/**
* Ensure a get constant method is issued for the class.
* @param cls Class of constant.
* @param clazz Class of constant.
*/
void needGetConstantMethod(final Class<?> cls) {
constantMethodNeeded.add(cls);
void needGetConstantMethod(final Class<?> clazz) {
constantMethodNeeded.add(clazz);
}
/**
@ -376,16 +379,19 @@ public class ClassEmitter implements Emitter {
static String disassemble(final byte[] bytecode) {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (final PrintWriter pw = new PrintWriter(baos)) {
new ClassReader(bytecode).accept(new TraceClassVisitor(pw), 0);
final NashornClassReader cr = new NashornClassReader(bytecode);
final Context ctx = AccessController.doPrivileged(new PrivilegedAction<Context>() {
@Override
public Context run() {
return Context.getContext();
}
});
final TraceClassVisitor tcv = new TraceClassVisitor(null, new NashornTextifier(ctx.getEnv(), cr), pw);
cr.accept(tcv, 0);
}
return new String(baos.toByteArray());
}
/**
* @return env used for class emission
*/
ScriptEnvironment getEnv() {
return env;
final String str = new String(baos.toByteArray());
return str;
}
/**
@ -475,16 +481,35 @@ public class ClassEmitter implements Emitter {
* @return method emitter to use for weaving this method
*/
MethodEmitter method(final FunctionNode functionNode) {
final FunctionSignature signature = new FunctionSignature(functionNode);
final MethodVisitor mv = cw.visitMethod(
ACC_PUBLIC | ACC_STATIC | (functionNode.isVarArg() ? ACC_VARARGS : 0),
functionNode.getName(),
new FunctionSignature(functionNode).toString(),
signature.toString(),
null,
null);
return new MethodEmitter(this, mv, functionNode);
}
/**
* Add a new method to the class, representing a rest-of version of the function node
*
* @param functionNode the function node to generate a method for
* @return method emitter to use for weaving this method
*/
MethodEmitter restOfMethod(final FunctionNode functionNode) {
final MethodVisitor mv = cw.visitMethod(
ACC_PUBLIC | ACC_STATIC,
functionNode.getName(),
Type.getMethodDescriptor(functionNode.getReturnType().getTypeClass(), RewriteException.class),
null,
null);
return new MethodEmitter(this, mv, functionNode);
}
/**
* Start generating the <clinit> method in the class
*
@ -636,7 +661,7 @@ public class ClassEmitter implements Emitter {
}
}
private MethodVisitor methodVisitor(EnumSet<Flag> flags, final String methodName, final Class<?> rtype, final Class<?>... ptypes) {
private MethodVisitor methodVisitor(final EnumSet<Flag> flags, final String methodName, final Class<?> rtype, final Class<?>... ptypes) {
return cw.visitMethod(Flag.getValue(flags), methodName, methodDescriptor(rtype, ptypes), null, null);
}

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,7 @@ import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
import jdk.nashorn.internal.IntDeque;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.FunctionNode;
@ -63,6 +63,10 @@ final class CodeGeneratorLexicalContext extends LexicalContext {
* i.e. should we keep it or throw it away */
private final Deque<Node> discard = new ArrayDeque<>();
private final Deque<Map<String, Collection<Label>>> unwarrantedOptimismHandlers = new ArrayDeque<>();
private final Deque<StringBuilder> slotTypesDescriptors = new ArrayDeque<>();
private final IntDeque splitNodes = new IntDeque();
/** A stack tracking the next free local variable slot in the blocks. There's one entry for every block
* currently on the lexical context stack. */
private int[] nextFreeSlots = new int[16];
@ -70,46 +74,56 @@ final class CodeGeneratorLexicalContext extends LexicalContext {
/** size of next free slot vector */
private int nextFreeSlotsSize;
private boolean isWithBoundary(final LexicalContextNode node) {
return node instanceof Block && !isEmpty() && peek() instanceof WithNode;
}
@Override
public <T extends LexicalContextNode> T push(final T node) {
if (isDynamicScopeBoundary(node)) {
++dynamicScopeCount;
if (isWithBoundary(node)) {
dynamicScopeCount++;
} else if (node instanceof FunctionNode) {
if (((FunctionNode)node).inDynamicContext()) {
dynamicScopeCount++;
}
splitNodes.push(0);
}
return super.push(node);
}
void enterSplitNode() {
splitNodes.getAndIncrement();
pushFreeSlots(methodEmitters.peek().getUsedSlotsWithLiveTemporaries());
}
void exitSplitNode() {
final int count = splitNodes.decrementAndGet();
assert count >= 0;
}
@Override
public <T extends LexicalContextNode> T pop(final T node) {
final T popped = super.pop(node);
if (isDynamicScopeBoundary(popped)) {
--dynamicScopeCount;
}
if (node instanceof Block) {
--nextFreeSlotsSize;
if (isWithBoundary(node)) {
dynamicScopeCount--;
assert dynamicScopeCount >= 0;
} else if (node instanceof FunctionNode) {
if (((FunctionNode)node).inDynamicContext()) {
dynamicScopeCount--;
assert dynamicScopeCount >= 0;
}
assert splitNodes.peek() == 0;
splitNodes.pop();
}
return popped;
}
private boolean isDynamicScopeBoundary(final LexicalContextNode node) {
if (node instanceof Block) {
// Block's immediate parent is a with node. Note we aren't testing for a WithNode, as that'd capture
// processing of WithNode.expression too, but it should be unaffected.
return !isEmpty() && peek() instanceof WithNode;
} else if (node instanceof FunctionNode) {
// Function has a direct eval in it (so a top-level "var ..." in the eval code can introduce a new
// variable into the function's scope), and it isn't strict (as evals in strict functions get an
// isolated scope).
return isFunctionDynamicScope((FunctionNode)node);
}
return false;
}
boolean inDynamicScope() {
return dynamicScopeCount > 0;
}
static boolean isFunctionDynamicScope(FunctionNode fn) {
return fn.hasEval() && !fn.isStrict();
boolean inSplitNode() {
return !splitNodes.isEmpty() && splitNodes.peek() > 0;
}
MethodEmitter pushMethodEmitter(final MethodEmitter newMethod) {
@ -123,6 +137,20 @@ final class CodeGeneratorLexicalContext extends LexicalContext {
return methodEmitters.isEmpty() ? null : methodEmitters.peek();
}
void pushUnwarrantedOptimismHandlers() {
unwarrantedOptimismHandlers.push(new HashMap<String, Collection<Label>>());
slotTypesDescriptors.push(new StringBuilder());
}
Map<String, Collection<Label>> getUnwarrantedOptimismHandlers() {
return unwarrantedOptimismHandlers.peek();
}
Map<String, Collection<Label>> popUnwarrantedOptimismHandlers() {
slotTypesDescriptors.pop();
return unwarrantedOptimismHandlers.pop();
}
CompileUnit pushCompileUnit(final CompileUnit newUnit) {
compileUnits.push(newUnit);
return newUnit;
@ -167,50 +195,77 @@ final class CodeGeneratorLexicalContext extends LexicalContext {
* Get a shared static method representing a dynamic scope get access.
*
* @param unit current compile unit
* @param type the type of the variable
* @param symbol the symbol
* @param valueType the type of the variable
* @param flags the callsite flags
* @return an object representing a shared scope call
*/
SharedScopeCall getScopeGet(final CompileUnit unit, final Type type, final Symbol symbol, final int flags) {
final SharedScopeCall scopeCall = new SharedScopeCall(symbol, type, type, null, flags);
if (scopeCalls.containsKey(scopeCall)) {
return scopeCalls.get(scopeCall);
}
scopeCall.setClassAndName(unit, getCurrentFunction().uniqueName(":scopeCall"));
scopeCalls.put(scopeCall, scopeCall);
return scopeCall;
SharedScopeCall getScopeGet(final CompileUnit unit, final Symbol symbol, final Type valueType, final int flags) {
return getScopeCall(unit, symbol, valueType, valueType, null, flags);
}
void onEnterBlock(final Block block) {
pushFreeSlots(assignSlots(block, isFunctionBody() ? 0 : getUsedSlotCount()));
}
void nextFreeSlot(final Block block) {
final boolean isFunctionBody = isFunctionBody();
final int nextFreeSlot;
if (isFunctionBody) {
// On entry to function, start with slot 0
nextFreeSlot = 0;
} else {
// Otherwise, continue from previous block's first free slot
nextFreeSlot = nextFreeSlots[nextFreeSlotsSize - 1];
}
private void pushFreeSlots(final int freeSlots) {
if (nextFreeSlotsSize == nextFreeSlots.length) {
final int[] newNextFreeSlots = new int[nextFreeSlotsSize * 2];
System.arraycopy(nextFreeSlots, 0, newNextFreeSlots, 0, nextFreeSlotsSize);
nextFreeSlots = newNextFreeSlots;
}
nextFreeSlots[nextFreeSlotsSize++] = assignSlots(block, nextFreeSlot);
nextFreeSlots[nextFreeSlotsSize++] = freeSlots;
}
private static int assignSlots(final Block block, final int firstSlot) {
int nextSlot = firstSlot;
int getUsedSlotCount() {
return nextFreeSlots[nextFreeSlotsSize - 1];
}
void releaseSlots() {
--nextFreeSlotsSize;
final int undefinedFromSlot = nextFreeSlotsSize == 0 ? 0 : nextFreeSlots[nextFreeSlotsSize - 1];
if(!slotTypesDescriptors.isEmpty()) {
slotTypesDescriptors.peek().setLength(undefinedFromSlot);
}
methodEmitters.peek().undefineLocalVariables(undefinedFromSlot, false);
}
private int assignSlots(final Block block, final int firstSlot) {
int fromSlot = firstSlot;
final MethodEmitter method = methodEmitters.peek();
for (final Symbol symbol : block.getSymbols()) {
if (symbol.hasSlot()) {
symbol.setSlot(nextSlot);
nextSlot += symbol.slotCount();
symbol.setFirstSlot(fromSlot);
final int toSlot = fromSlot + symbol.slotCount();
method.defineBlockLocalVariable(fromSlot, toSlot);
fromSlot = toSlot;
}
}
return nextSlot;
return fromSlot;
}
static Type getTypeForSlotDescriptor(final char typeDesc) {
// Recognizing both lowercase and uppercase as we're using both to signify symbol boundaries; see
// MethodEmitter.markSymbolBoundariesInLvarTypesDescriptor().
switch(typeDesc) {
case 'I':
case 'i':
return Type.INT;
case 'J':
case 'j':
return Type.LONG;
case 'D':
case 'd':
return Type.NUMBER;
case 'A':
case 'a':
return Type.OBJECT;
case 'U':
case 'u':
return Type.UNKNOWN;
default:
throw new AssertionError();
}
}
void pushDiscard(final Node node) {
@ -225,11 +280,8 @@ final class CodeGeneratorLexicalContext extends LexicalContext {
return discard.peek();
}
int quickSlot(final Symbol symbol) {
final int quickSlot = nextFreeSlots[nextFreeSlotsSize - 1];
nextFreeSlots[nextFreeSlotsSize - 1] = quickSlot + symbol.slotCount();
return quickSlot;
int quickSlot(final Type type) {
return methodEmitters.peek().defineTemporaryLocalVariable(type.getSlots());
}
}

View File

@ -25,10 +25,17 @@
package jdk.nashorn.internal.codegen;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
/**
* Used to track split class compilation.
*/
public class CompileUnit implements Comparable<CompileUnit> {
public final class CompileUnit implements Comparable<CompileUnit> {
/** Current class name */
private final String className;
@ -39,14 +46,44 @@ public class CompileUnit implements Comparable<CompileUnit> {
private Class<?> clazz;
CompileUnit(final String className, final ClassEmitter classEmitter) {
this(className, classEmitter, 0L);
private Set<FunctionInitializer> functionInitializers = new LinkedHashSet<>();
private static class FunctionInitializer {
final RecompilableScriptFunctionData data;
final FunctionNode functionNode;
FunctionInitializer(final RecompilableScriptFunctionData data, final FunctionNode functionNode) {
this.data = data;
this.functionNode = functionNode;
}
void initializeCode() {
data.initializeCode(functionNode);
}
@Override
public int hashCode() {
return data.hashCode() + 31 * functionNode.hashCode();
}
@Override
public boolean equals(final Object obj) {
if (obj == null || obj.getClass() != FunctionInitializer.class) {
return false;
}
final FunctionInitializer other = (FunctionInitializer)obj;
return data == other.data && functionNode == other.functionNode;
}
}
CompileUnit(final String className, final ClassEmitter classEmitter, final long initialWeight) {
this.className = className;
this.classEmitter = classEmitter;
this.weight = initialWeight;
this.classEmitter = classEmitter;
}
static Set<CompileUnit> createCompileUnitSet() {
return new TreeSet<>();
}
/**
@ -71,6 +108,29 @@ public class CompileUnit implements Comparable<CompileUnit> {
this.classEmitter = null;
}
void addFunctionInitializer(final RecompilableScriptFunctionData data, final FunctionNode functionNode) {
functionInitializers.add(new FunctionInitializer(data, functionNode));
}
/**
* Returns true if this compile unit is responsible for initializing the specified function data with specified
* function node.
* @param data the function data to check
* @param functionNode the function node to check
* @return true if this unit is responsible for initializing the function data with the function node, otherwise
* false
*/
public boolean isInitializing(final RecompilableScriptFunctionData data, final FunctionNode functionNode) {
return functionInitializers.contains(new FunctionInitializer(data, functionNode));
}
void initializeFunctionsCode() {
for(final FunctionInitializer init : functionInitializers) {
init.initializeCode();
}
functionInitializers = Collections.emptySet();
}
/**
* Add weight to this compile unit
* @param w weight to add
@ -112,13 +172,17 @@ public class CompileUnit implements Comparable<CompileUnit> {
return className;
}
@Override
public String toString() {
return "[classname=" + className + " weight=" + weight + '/' + Splitter.SPLIT_THRESHOLD + ']';
private static String shortName(final String name) {
return name.lastIndexOf('/') == -1 ? name : name.substring(name.lastIndexOf('/') + 1);
}
@Override
public int compareTo(CompileUnit o) {
public String toString() {
return "[CompileUnit className=" + shortName(className) + " weight=" + weight + '/' + Splitter.SPLIT_THRESHOLD + ']';
}
@Override
public int compareTo(final CompileUnit o) {
return className.compareTo(o.className);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,11 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
@ -41,7 +45,6 @@ import jdk.nashorn.internal.runtime.Source;
*/
public enum CompilerConstants {
/** the __FILE__ variable */
__FILE__,
@ -51,9 +54,6 @@ public enum CompilerConstants {
/** the __LINE__ variable */
__LINE__,
/** lazy prefix for classes of jitted methods */
LAZY("Lazy"),
/** constructor name */
INIT("<init>"),
@ -78,15 +78,18 @@ public enum CompilerConstants {
/** function prefix for anonymous functions */
ANON_FUNCTION_PREFIX("L:"),
/** method name for Java method that is script entry point */
RUN_SCRIPT("runScript"),
/** method name for Java method that is the program entry point */
PROGRAM(":program"),
/** method name for Java method that creates the script function for the program */
CREATE_PROGRAM_FUNCTION(":createProgramFunction"),
/**
* "this" name symbol for a parameter representing ECMAScript "this" in static methods that are compiled
* representations of ECMAScript functions. It is not assigned a slot, as its position in the method signature is
* dependent on other factors (most notably, callee can precede it).
*/
THIS("this"),
THIS("this", Object.class),
/** this debugger symbol */
THIS_DEBUGGER(":this"),
@ -110,13 +113,16 @@ public enum CompilerConstants {
/** the internal arguments object, when necessary (not visible to scripts, can't be reassigned). */
ARGUMENTS(":arguments", ScriptObject.class),
/** prefix for apply-to-call exploded arguments */
EXPLODED_ARGUMENT_PREFIX(":xarg"),
/** prefix for iterators for for (x in ...) */
ITERATOR_PREFIX(":i", Iterator.class),
/** prefix for tag variable used for switch evaluation */
SWITCH_TAG_PREFIX(":s"),
/** prefix for all exceptions */
/** prefix for JVM exceptions */
EXCEPTION_PREFIX(":e", Throwable.class),
/** prefix for quick slots generated in Store */
@ -161,7 +167,7 @@ public enum CompilerConstants {
/** get map */
GET_MAP(":getMap"),
/** get map */
/** set map */
SET_MAP(":setMap"),
/** get array prefix */
@ -170,10 +176,22 @@ public enum CompilerConstants {
/** get array suffix */
GET_ARRAY_SUFFIX("$array");
/** To save memory - intern the compiler constant symbol names, as they are frequently reused */
static {
for (final CompilerConstants c : values()) {
final String symbolName = c.symbolName();
if (symbolName != null) {
symbolName.intern();
}
}
}
private static Set<String> symbolNames;
/**
* Prefix used for internal methods generated in script clases.
*/
public static final String INTERNAL_METHOD_PREFIX = ":";
private static final String INTERNAL_METHOD_PREFIX = ":";
private final String symbolName;
private final Class<?> type;
@ -198,9 +216,28 @@ public enum CompilerConstants {
}
private CompilerConstants(final String symbolName, final Class<?> type, final int slot) {
this.symbolName = symbolName;
this.type = type;
this.slot = slot;
this.symbolName = symbolName;
this.type = type;
this.slot = slot;
}
/**
* Check whether a name is that of a reserved compiler constnat
* @param name name
* @return true if compiler constant name
*/
public static boolean isCompilerConstant(final String name) {
ensureSymbolNames();
return symbolNames.contains(name);
}
private static void ensureSymbolNames() {
if(symbolNames == null) {
symbolNames = new HashSet<>();
for(final CompilerConstants cc: CompilerConstants.values()) {
symbolNames.add(cc.symbolName);
}
}
}
/**
@ -327,9 +364,14 @@ public enum CompilerConstants {
public static Call specialCallNoLookup(final String className, final String name, final String desc) {
return new Call(null, className, name, desc) {
@Override
public MethodEmitter invoke(final MethodEmitter method) {
MethodEmitter invoke(final MethodEmitter method) {
return method.invokespecial(className, name, descriptor);
}
@Override
public void invoke(final MethodVisitor mv) {
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, className, name, desc, false);
}
};
}
@ -361,9 +403,14 @@ public enum CompilerConstants {
public static Call staticCallNoLookup(final String className, final String name, final String desc) {
return new Call(null, className, name, desc) {
@Override
public MethodEmitter invoke(final MethodEmitter method) {
MethodEmitter invoke(final MethodEmitter method) {
return method.invokestatic(className, name, descriptor);
}
@Override
public void invoke(final MethodVisitor mv) {
mv.visitMethodInsn(Opcodes.INVOKESTATIC, className, name, desc, false);
}
};
}
@ -396,9 +443,14 @@ public enum CompilerConstants {
public static Call virtualCallNoLookup(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
return new Call(null, className(clazz), name, methodDescriptor(rtype, ptypes)) {
@Override
public MethodEmitter invoke(final MethodEmitter method) {
MethodEmitter invoke(final MethodEmitter method) {
return method.invokevirtual(className, name, descriptor);
}
@Override
public void invoke(final MethodVisitor mv) {
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, name, descriptor, false);
}
};
}
@ -416,9 +468,14 @@ public enum CompilerConstants {
public static Call interfaceCallNoLookup(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
return new Call(null, className(clazz), name, methodDescriptor(rtype, ptypes)) {
@Override
public MethodEmitter invoke(final MethodEmitter method) {
MethodEmitter invoke(final MethodEmitter method) {
return method.invokeinterface(className, name, descriptor);
}
@Override
public void invoke(final MethodVisitor mv) {
mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, className, name, descriptor, true);
}
};
}
@ -512,9 +569,14 @@ public enum CompilerConstants {
public static Call staticCall(final MethodHandles.Lookup lookup, final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
return new Call(MH.findStatic(lookup, clazz, name, MH.type(rtype, ptypes)), className(clazz), name, methodDescriptor(rtype, ptypes)) {
@Override
public MethodEmitter invoke(final MethodEmitter method) {
MethodEmitter invoke(final MethodEmitter method) {
return method.invokestatic(className, name, descriptor);
}
@Override
public void invoke(final MethodVisitor mv) {
mv.visitMethodInsn(Opcodes.INVOKESTATIC, className, name, descriptor, false);
}
};
}
@ -532,12 +594,55 @@ public enum CompilerConstants {
public static Call virtualCall(final MethodHandles.Lookup lookup, final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
return new Call(MH.findVirtual(lookup, clazz, name, MH.type(rtype, ptypes)), className(clazz), name, methodDescriptor(rtype, ptypes)) {
@Override
public MethodEmitter invoke(final MethodEmitter method) {
MethodEmitter invoke(final MethodEmitter method) {
return method.invokevirtual(className, name, descriptor);
}
@Override
public void invoke(final MethodVisitor mv) {
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, name, descriptor, false);
}
};
}
/**
* Create a special call, given an explicit lookup, looking up the method handle for it at the same time.
* clazz is used as this class
*
* @param lookup the lookup
* @param clazz the class
* @param name the name of the method
* @param rtype the return type
* @param ptypes the parameter types
*
* @return the call object representing the virtual call
*/
public static Call specialCall(final MethodHandles.Lookup lookup, final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
return new Call(MH.findSpecial(lookup, clazz, name, MH.type(rtype, ptypes), clazz), className(clazz), name, methodDescriptor(rtype, ptypes)) {
@Override
MethodEmitter invoke(final MethodEmitter method) {
return method.invokespecial(className, name, descriptor);
}
@Override
public void invoke(final MethodVisitor mv) {
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, className, name, descriptor, false);
}
};
}
/**
* Returns true if the passed string looks like a method name of an internally generated Nashorn method. Basically,
* if it starts with a colon character {@code :} but is not the name of the program method {@code :program}.
* Program function is not considered internal as we want it to show up in exception stack traces.
* @param methodName the name of a method
* @return true if it looks like an internal Nashorn method name.
* @throws NullPointerException if passed null
*/
public static boolean isInternalMethodName(final String methodName) {
return methodName.startsWith(INTERNAL_METHOD_PREFIX) && !methodName.equals(PROGRAM.symbolName);
}
/**
* Private class representing an access. This can generate code into a method code or
* a field access.
@ -668,7 +773,14 @@ public enum CompilerConstants {
*
* @return the method emitter
*/
protected abstract MethodEmitter invoke(final MethodEmitter emitter);
abstract MethodEmitter invoke(final MethodEmitter emitter);
/**
* Generate invocation code for the method
*
* @param mv a method visitor
*/
public abstract void invoke(final MethodVisitor mv);
}
}

View File

@ -66,8 +66,7 @@ enum Condition {
case GT:
return IFGT;
default:
assert false;
return -1;
throw new UnsupportedOperationException("toUnary:" + c.toString());
}
}
@ -86,8 +85,7 @@ enum Condition {
case GT:
return IF_ICMPGT;
default:
assert false;
return -1;
throw new UnsupportedOperationException("toBinary:" + c.toString());
}
}
}

View File

@ -25,20 +25,19 @@
package jdk.nashorn.internal.codegen;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
/**
* Manages constants needed by code generation. Objects are maintained in an
* interning maps to remove duplicates.
*/
class ConstantData {
final class ConstantData {
/** Constant table. */
final List<Object> constants;
@ -64,7 +63,7 @@ class ConstantData {
private int calcHashCode() {
final Class<?> cls = array.getClass();
if (cls == Object[].class) {
if (!cls.getComponentType().isPrimitive()) {
return Arrays.hashCode((Object[])array);
} else if (cls == double[].class) {
return Arrays.hashCode((double[])array);
@ -92,7 +91,7 @@ class ConstantData {
final Class<?> cls = array.getClass();
if (cls == otherArray.getClass()) {
if (cls == Object[].class) {
if (!cls.getComponentType().isPrimitive()) {
return Arrays.equals((Object[])array, (Object[])otherArray);
} else if (cls == double[].class) {
return Arrays.equals((double[])array, (double[])otherArray);
@ -185,6 +184,7 @@ class ConstantData {
* @return the index in the constant pool that the object was given
*/
public int add(final Object object) {
assert object != null;
final Object entry;
if (object.getClass().isArray()) {
entry = new ArrayWrapper(object);

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.codegen;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import jdk.nashorn.internal.runtime.ECMAErrors;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
/**
* Class that facilitates printing bytecode and dumping it to disk.
*/
public final class DumpBytecode {
/**
* Dump bytecode to console and potentially disk.
* @param env the script environment defining options for printing bytecode
* @param logger a logger used to write diagnostics about bytecode dumping
* @param bytecode the actual code to dump
* @param className the name of the class being dumped
*/
public static void dumpBytecode(final ScriptEnvironment env, final DebugLogger logger, final byte[] bytecode, final String className) {
File dir = null;
try {
// should could be printed to stderr for generate class?
if (env._print_code) {
final StringBuilder sb = new StringBuilder();
sb.append("class: " + className).
append('\n').
append(ClassEmitter.disassemble(bytecode)).
append("=====");
if (env._print_code_dir != null) {
String name = className;
final int dollar = name.lastIndexOf('$');
if (dollar != -1) {
name = name.substring(dollar + 1);
}
dir = new File(env._print_code_dir);
if (!dir.exists() && !dir.mkdirs()) {
throw new IOException(dir.toString());
}
File file;
String fileName;
int uniqueId = 0;
do {
fileName = name + (uniqueId == 0 ? "" : "_" + uniqueId) + ".bytecode";
file = new File(env._print_code_dir, fileName);
uniqueId++;
} while (file.exists());
try (final PrintWriter pw = new PrintWriter(new FileOutputStream(file))) {
pw.print(sb.toString());
pw.flush();
}
} else {
env.getErr().println(sb);
}
}
// should code be dumped to disk - only valid in compile_only mode?
if (env._dest_dir != null && env._compile_only) {
final String fileName = className.replace('.', File.separatorChar) + ".class";
final int index = fileName.lastIndexOf(File.separatorChar);
if (index != -1) {
dir = new File(env._dest_dir, fileName.substring(0, index));
} else {
dir = new File(env._dest_dir);
}
if (!dir.exists() && !dir.mkdirs()) {
throw new IOException(dir.toString());
}
final File file = new File(env._dest_dir, fileName);
try (final FileOutputStream fos = new FileOutputStream(file)) {
fos.write(bytecode);
}
logger.info("Wrote class to '" + file.getAbsolutePath() + '\'');
}
} catch (final IOException e) {
logger.warning("Skipping class dump for ",
className,
": ",
ECMAErrors.getMessage(
"io.error.cant.write",
dir.toString()));
}
}
}

Some files were not shown because too many files have changed in this diff Show More