diff --git a/.hgtags b/.hgtags index 11f22d17598..aee5d6a2d78 100644 --- a/.hgtags +++ b/.hgtags @@ -202,3 +202,5 @@ d17eb2e13e362085e866d46235314c50cc4661cc jdk8-b77 6d3dcd34b5b962ea1ef9eed0dafdee9e812401bc jdk8-b78 a1313a8d90d17d363a3b2a645dc4030ec204b168 jdk8-b79 3fa21fbf9be7e6b482af43aacb6a09acfa30bdb6 jdk8-b80 +e41d716405b209d3eddef8bd4240cec2bd34dcca jdk8-b81 +5e8c55025644730385a6f8fa029ecdb2d2c98a07 jdk8-b82 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index e869333243b..7b38704aae9 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -202,3 +202,5 @@ b43aa5bd8ca5c8121336495382d35ecfa7a71536 jdk8-b74 fd1a5574cf68af24bfd52decc37ac6361afb278a jdk8-b78 91d35211e74464dca5edf9b66ab01d0d0d8cded7 jdk8-b79 907a926d3c96472f357617b48b6b968ea855c23c jdk8-b80 +145dbc56f931c134e837b675b9e6e7bf08902e93 jdk8-b81 +29153d0df68f84162ffe8c2cf4f402a3f2245e85 jdk8-b82 diff --git a/Makefile b/Makefile index f9162f0b641..f7b9d1b35e3 100644 --- a/Makefile +++ b/Makefile @@ -90,6 +90,7 @@ include ./make/corba-rules.gmk include ./make/jaxp-rules.gmk include ./make/jaxws-rules.gmk include ./make/jdk-rules.gmk +include ./make/nashorn-rules.gmk include ./make/install-rules.gmk include ./make/sponsors-rules.gmk include ./make/deploy-rules.gmk @@ -174,6 +175,11 @@ ifeq ($(BUILD_JDK), true) clobber:: jdk-clobber endif +ifeq ($(BUILD_NASHORN), true) + generic_build_repo_series:: $(NASHORN) + clobber:: nashorn-clobber +endif + ifeq ($(BUILD_DEPLOY), true) generic_build_repo_series:: $(DEPLOY) clobber:: deploy-clobber @@ -336,6 +342,7 @@ deploy_fastdebug_only: BUILD_HOTSPOT=false \ BUILD_JDK=false \ BUILD_LANGTOOLS=false \ + BUILD_NASHORN=false \ BUILD_CORBA=false \ BUILD_JAXP=false \ BUILD_JAXWS=false \ diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac index da9996f74d9..5e632c4ecb8 100644 --- a/common/autoconf/configure.ac +++ b/common/autoconf/configure.ac @@ -194,6 +194,7 @@ BASIC_COMPILE_FIXPATH ############################################################################### JDKOPT_SETUP_BUILD_TWEAKS +JDKOPT_DETECT_INTREE_EC ############################################################################### # diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 132eccc50a1..4d9ec980421 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -612,6 +612,7 @@ SJAVAC_SERVER_JAVA JOBS MEMORY_SIZE NUM_CORES +ENABLE_INTREE_EC SALIB_NAME HOTSPOT_MAKE_ARGS FIXPATH @@ -749,6 +750,7 @@ BUILD_OUTPUT OVERRIDE_SRC_ROOT ADD_SRC_ROOT JDK_TOPDIR +NASHORN_TOPDIR HOTSPOT_TOPDIR JAXWS_TOPDIR JAXP_TOPDIR @@ -3751,7 +3753,7 @@ fi #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1363150186 +DATE_WHEN_GENERATED=1363706268 ############################################################################### # @@ -10783,6 +10785,12 @@ else fi +############################################################################### +# +# Enable or disable the elliptic curve crypto implementation +# + + ############################################################################### # # Compress jars @@ -15682,6 +15690,7 @@ CORBA_TOPDIR="$SRC_ROOT/corba" JAXP_TOPDIR="$SRC_ROOT/jaxp" JAXWS_TOPDIR="$SRC_ROOT/jaxws" HOTSPOT_TOPDIR="$SRC_ROOT/hotspot" +NASHORN_TOPDIR="$SRC_ROOT/nashorn" JDK_TOPDIR="$SRC_ROOT/jdk" @@ -15692,6 +15701,7 @@ JDK_TOPDIR="$SRC_ROOT/jdk" + ############################################################################### # # Pickup additional source for a component from outside of the source root @@ -15922,6 +15932,19 @@ $as_echo_n "checking if hotspot should be overridden... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes with $HOTSPOT_TOPDIR" >&5 $as_echo "yes with $HOTSPOT_TOPDIR" >&6; } fi +if test "x$with_override_nashorn" != x; then + CURDIR="$PWD" + cd "$with_override_nashorn" + NASHORN_TOPDIR="`pwd`" + cd "$CURDIR" + if ! test -f $NASHORN_TOPDIR/makefiles/BuildNashorn.gmk; then + as_fn_error $? "You have to override nashorn with a full nashorn repo!" "$LINENO" 5 + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if nashorn should be overridden" >&5 +$as_echo_n "checking if nashorn should be overridden... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes with $NASHORN_TOPDIR" >&5 +$as_echo "yes with $NASHORN_TOPDIR" >&6; } +fi if test "x$with_override_jdk" != x; then CURDIR="$PWD" cd "$with_override_jdk" @@ -18534,14 +18557,18 @@ fi ### Locate C compiler (CC) -# gcc is almost always present, but on Windows we -# prefer cl.exe and on Solaris we prefer CC. -# Thus test for them in this order. -if test "x$OPENJDK_TARGET_OS" = xmacosx; then - # Do not probe for cc on MacOSX. - COMPILER_CHECK_LIST="cl gcc" +# On windows, only cl.exe is supported. +# On Solaris, cc is preferred to gcc. +# Elsewhere, gcc is preferred to cc. + +if test "x$CC" != x; then + COMPILER_CHECK_LIST="$CC" +elif test "x$OPENJDK_TARGET_OS" = "xwindows"; then + COMPILER_CHECK_LIST="cl" +elif test "x$OPENJDK_TARGET_OS" = "xsolaris"; then + COMPILER_CHECK_LIST="cc gcc" else - COMPILER_CHECK_LIST="cl cc gcc" + COMPILER_CHECK_LIST="gcc cc" fi @@ -19505,7 +19532,7 @@ $as_echo "$as_me: The result from running with --version was: \"$COMPILER_VERSIO $as_echo "$as_me: Using $COMPILER_VENDOR $COMPILER_NAME compiler version $COMPILER_VERSION (located at $COMPILER)" >&6;} -# Now that we have resolved CC ourself, let autoconf have it's go at it +# Now that we have resolved CC ourself, let autoconf have its go at it ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -20107,13 +20134,17 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ### Locate C++ compiler (CXX) -if test "x$OPENJDK_TARGET_OS" = xmacosx; then - # Do not probe for CC on MacOSX. - COMPILER_CHECK_LIST="cl g++" +if test "x$CXX" != x; then + COMPILER_CHECK_LIST="$CXX" +elif test "x$OPENJDK_TARGET_OS" = "xwindows"; then + COMPILER_CHECK_LIST="cl" +elif test "x$OPENJDK_TARGET_OS" = "xsolaris"; then + COMPILER_CHECK_LIST="CC g++" else - COMPILER_CHECK_LIST="cl CC g++" + COMPILER_CHECK_LIST="g++ CC" fi + COMPILER_NAME=C++ CXX= @@ -21074,7 +21105,7 @@ $as_echo "$as_me: The result from running with --version was: \"$COMPILER_VERSIO $as_echo "$as_me: Using $COMPILER_VENDOR $COMPILER_NAME compiler version $COMPILER_VERSION (located at $COMPILER)" >&6;} -# Now that we have resolved CXX ourself, let autoconf have it's go at it +# Now that we have resolved CXX ourself, let autoconf have its go at it ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -29799,7 +29830,7 @@ if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : _ACEOF X11_A_OK=yes else - X11_A_OK=no + X11_A_OK=no; break fi done @@ -31670,6 +31701,22 @@ fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if elliptic curve crypto implementation is present" >&5 +$as_echo_n "checking if elliptic curve crypto implementation is present... " >&6; } + +if test -d "${SRC_ROOT}/jdk/src/share/native/sun/security/ec/impl"; then + ENABLE_INTREE_EC=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + ENABLE_INTREE_EC=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + ############################################################################### # # Configure parts of the build that only affect the build performance, diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 index 48eb3f85c0e..d3d55e52952 100644 --- a/common/autoconf/jdk-options.m4 +++ b/common/autoconf/jdk-options.m4 @@ -364,6 +364,25 @@ else fi AC_SUBST(UNLIMITED_CRYPTO) +############################################################################### +# +# Enable or disable the elliptic curve crypto implementation +# +AC_DEFUN_ONCE([JDKOPT_DETECT_INTREE_EC], +[ +AC_MSG_CHECKING([if elliptic curve crypto implementation is present]) + +if test -d "${SRC_ROOT}/jdk/src/share/native/sun/security/ec/impl"; then + ENABLE_INTREE_EC=yes + AC_MSG_RESULT([yes]) +else + ENABLE_INTREE_EC=no + AC_MSG_RESULT([no]) +fi + +AC_SUBST(ENABLE_INTREE_EC) +]) + ############################################################################### # # Compress jars diff --git a/common/autoconf/libraries.m4 b/common/autoconf/libraries.m4 index 91b0a846e5f..6cc9d634b60 100644 --- a/common/autoconf/libraries.m4 +++ b/common/autoconf/libraries.m4 @@ -182,7 +182,7 @@ CFLAGS="$CFLAGS $X_CFLAGS" # Need to include Xlib.h and Xutil.h to avoid "present but cannot be compiled" warnings on Solaris 10 AC_CHECK_HEADERS([X11/extensions/shape.h X11/extensions/Xrender.h X11/extensions/XTest.h], [X11_A_OK=yes], - [X11_A_OK=no], + [X11_A_OK=no; break], [ # include # include ]) diff --git a/common/autoconf/source-dirs.m4 b/common/autoconf/source-dirs.m4 index eacd056066b..bb0aba1b826 100644 --- a/common/autoconf/source-dirs.m4 +++ b/common/autoconf/source-dirs.m4 @@ -33,12 +33,14 @@ CORBA_TOPDIR="$SRC_ROOT/corba" JAXP_TOPDIR="$SRC_ROOT/jaxp" JAXWS_TOPDIR="$SRC_ROOT/jaxws" HOTSPOT_TOPDIR="$SRC_ROOT/hotspot" +NASHORN_TOPDIR="$SRC_ROOT/nashorn" JDK_TOPDIR="$SRC_ROOT/jdk" AC_SUBST(LANGTOOLS_TOPDIR) AC_SUBST(CORBA_TOPDIR) AC_SUBST(JAXP_TOPDIR) AC_SUBST(JAXWS_TOPDIR) AC_SUBST(HOTSPOT_TOPDIR) +AC_SUBST(NASHORN_TOPDIR) AC_SUBST(JDK_TOPDIR) ]) @@ -233,7 +235,18 @@ if test "x$with_override_hotspot" != x; then fi AC_MSG_CHECKING([if hotspot should be overridden]) AC_MSG_RESULT([yes with $HOTSPOT_TOPDIR]) -fi +fi +if test "x$with_override_nashorn" != x; then + CURDIR="$PWD" + cd "$with_override_nashorn" + NASHORN_TOPDIR="`pwd`" + cd "$CURDIR" + if ! test -f $NASHORN_TOPDIR/makefiles/BuildNashorn.gmk; then + AC_MSG_ERROR([You have to override nashorn with a full nashorn repo!]) + fi + AC_MSG_CHECKING([if nashorn should be overridden]) + AC_MSG_RESULT([yes with $NASHORN_TOPDIR]) +fi if test "x$with_override_jdk" != x; then CURDIR="$PWD" cd "$with_override_jdk" diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index 5753b5f8200..bfba636a7b1 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -141,6 +141,7 @@ CORBA_TOPDIR:=@CORBA_TOPDIR@ JAXP_TOPDIR:=@JAXP_TOPDIR@ JAXWS_TOPDIR:=@JAXWS_TOPDIR@ HOTSPOT_TOPDIR:=@HOTSPOT_TOPDIR@ +NASHORN_TOPDIR:=@NASHORN_TOPDIR@ COPYRIGHT_YEAR:=@COPYRIGHT_YEAR@ # Location where build customization files may be found @@ -230,6 +231,7 @@ JAXP_OUTPUTDIR=$(BUILD_OUTPUT)/jaxp JAXWS_OUTPUTDIR=$(BUILD_OUTPUT)/jaxws HOTSPOT_OUTPUTDIR=$(BUILD_OUTPUT)/hotspot JDK_OUTPUTDIR=$(BUILD_OUTPUT)/jdk +NASHORN_OUTPUTDIR=$(BUILD_OUTPUT)/nashorn IMAGES_OUTPUTDIR=$(BUILD_OUTPUT)/images JCE_OUTPUTDIR=$(BUILD_OUTPUT)/jce-release @@ -238,6 +240,7 @@ CORBA_DIST=$(CORBA_OUTPUTDIR)/dist JAXP_DIST=$(JAXP_OUTPUTDIR)/dist JAXWS_DIST=$(JAXWS_OUTPUTDIR)/dist HOTSPOT_DIST=@HOTSPOT_DIST@ +NASHORN_DIST=$(NASHORN_OUTPUTDIR)/dist BUILD_HOTSPOT=@BUILD_HOTSPOT@ @@ -536,6 +539,7 @@ endif # Build setup ENABLE_JFR=@ENABLE_JFR@ +ENABLE_INTREE_EC=@ENABLE_INTREE_EC@ USE_EXTERNAL_LIBJPEG:=@USE_EXTERNAL_LIBJPEG@ USE_EXTERNAL_LIBGIF:=@USE_EXTERNAL_LIBGIF@ USE_EXTERNAL_LIBZ:=@USE_EXTERNAL_LIBZ@ diff --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4 index 9a464aac1ae..bacff783414 100644 --- a/common/autoconf/toolchain.m4 +++ b/common/autoconf/toolchain.m4 @@ -249,30 +249,38 @@ fi ### Locate C compiler (CC) -# gcc is almost always present, but on Windows we -# prefer cl.exe and on Solaris we prefer CC. -# Thus test for them in this order. -if test "x$OPENJDK_TARGET_OS" = xmacosx; then - # Do not probe for cc on MacOSX. - COMPILER_CHECK_LIST="cl gcc" +# On windows, only cl.exe is supported. +# On Solaris, cc is preferred to gcc. +# Elsewhere, gcc is preferred to cc. + +if test "x$CC" != x; then + COMPILER_CHECK_LIST="$CC" +elif test "x$OPENJDK_TARGET_OS" = "xwindows"; then + COMPILER_CHECK_LIST="cl" +elif test "x$OPENJDK_TARGET_OS" = "xsolaris"; then + COMPILER_CHECK_LIST="cc gcc" else - COMPILER_CHECK_LIST="cl cc gcc" + COMPILER_CHECK_LIST="gcc cc" fi TOOLCHAIN_FIND_COMPILER([CC],[C],[$COMPILER_CHECK_LIST]) -# Now that we have resolved CC ourself, let autoconf have it's go at it +# Now that we have resolved CC ourself, let autoconf have its go at it AC_PROG_CC([$CC]) ### Locate C++ compiler (CXX) -if test "x$OPENJDK_TARGET_OS" = xmacosx; then - # Do not probe for CC on MacOSX. - COMPILER_CHECK_LIST="cl g++" +if test "x$CXX" != x; then + COMPILER_CHECK_LIST="$CXX" +elif test "x$OPENJDK_TARGET_OS" = "xwindows"; then + COMPILER_CHECK_LIST="cl" +elif test "x$OPENJDK_TARGET_OS" = "xsolaris"; then + COMPILER_CHECK_LIST="CC g++" else - COMPILER_CHECK_LIST="cl CC g++" + COMPILER_CHECK_LIST="g++ CC" fi + TOOLCHAIN_FIND_COMPILER([CXX],[C++],[$COMPILER_CHECK_LIST]) -# Now that we have resolved CXX ourself, let autoconf have it's go at it +# Now that we have resolved CXX ourself, let autoconf have its go at it AC_PROG_CXX([$CXX]) ### Locate other tools diff --git a/common/bin/hgforest.sh b/common/bin/hgforest.sh index 29e80301a06..9f0db97d578 100644 --- a/common/bin/hgforest.sh +++ b/common/bin/hgforest.sh @@ -96,7 +96,7 @@ pull_default="" repos="" repos_extra="" if [ "${command}" = "clone" -o "${command}" = "fclone" ] ; then - subrepos="corba jaxp jaxws langtools jdk hotspot" + subrepos="corba jaxp jaxws langtools jdk hotspot nashorn" if [ -f .hg/hgrc ] ; then pull_default=`hg paths default` if [ "${pull_default}" = "" ] ; then diff --git a/common/makefiles/Main.gmk b/common/makefiles/Main.gmk index 76a6faabfee..11dda4bcff2 100644 --- a/common/makefiles/Main.gmk +++ b/common/makefiles/Main.gmk @@ -120,6 +120,12 @@ jdk-only: start-make @($(CD) $(JDK_TOPDIR)/makefiles && $(BUILD_LOG_WRAPPER) $(MAKE) $(MAKE_ARGS) -f BuildJdk.gmk $(JDK_TARGET)) @$(call TargetExit) +nashorn: jdk nashorn-only +nashorn-only: start-make + @$(call TargetEnter) + @($(CD) $(NASHORN_TOPDIR)/makefiles && $(BUILD_LOG_WRAPPER) $(MAKE) $(MAKE_ARGS) -f BuildNashorn.gmk) + @$(call TargetExit) + demos: jdk demos-only demos-only: start-make @$(call TargetEnter) @@ -128,7 +134,7 @@ demos-only: start-make # Note: This double-colon rule is intentional, to support # custom make file integration. -images:: source-tips demos images-only +images:: source-tips demos nashorn images-only images-only: start-make @$(call TargetEnter) @($(CD) $(JDK_TOPDIR)/makefiles && $(BUILD_LOG_WRAPPER) $(MAKE) $(MAKE_ARGS) -f BuildJdk.gmk images) @@ -175,9 +181,10 @@ bootcycle-images: @$(ECHO) Boot cycle build step 2: Building a new JDK image using previously built image @($(CD) $(SRC_ROOT)/common/makefiles && $(BUILD_LOG_WRAPPER) $(MAKE) SPEC=$(dir $(SPEC))bootcycle-spec.gmk images) -test: start-make +test: images test-only +test-only: start-make @$(call TargetEnter) - @($(CD) $(SRC_ROOT)/test && $(BUILD_LOG_WRAPPER) $(MAKE) -j1 -k MAKEFLAGS= PRODUCT_HOME=$(OUTPUT_ROOT)/jdk JPRT_JAVA_HOME=$(OUTPUT_ROOT)/jdk ALT_OUTPUTDIR=$(OUTPUT_ROOT) $(TEST)) || true + @($(CD) $(SRC_ROOT)/test && $(BUILD_LOG_WRAPPER) $(MAKE) -j1 -k MAKEFLAGS= PRODUCT_HOME=$(JDK_IMAGE_DIR) JPRT_JAVA_HOME=$(JDK_IMAGE_DIR) ALT_OUTPUTDIR=$(OUTPUT_ROOT) $(TEST)) || true @$(call TargetExit) # Stores the tips for each repository. This file is be used when constructing the jdk image and can be @@ -190,7 +197,7 @@ $(OUTPUT_ROOT)/source_tips: FRC # Remove everything, except the output from configure. -clean: clean-langtools clean-corba clean-jaxp clean-jaxws clean-hotspot clean-jdk clean-images clean-overlay-images clean-bootcycle-build clean-docs +clean: clean-langtools clean-corba clean-jaxp clean-jaxws clean-hotspot clean-jdk clean-nashorn clean-images clean-overlay-images clean-bootcycle-build clean-docs @($(CD) $(OUTPUT_ROOT) && $(RM) -r tmp source_tips build.log* build-trace*.log*) @$(ECHO) Cleaned all build artifacts. @@ -220,6 +227,8 @@ clean-hotspot: $(call CleanComponent,hotspot) clean-jdk: $(call CleanComponent,jdk) +clean-nashorn: + $(call CleanComponent,nashorn) clean-images: $(call CleanComponent,images) clean-overlay-images: @@ -230,10 +239,10 @@ clean-docs: $(call CleanComponent,docs) $(call CleanComponent,docstemp) -.PHONY: langtools corba jaxp jaxws hotspot jdk images overlay-images install -.PHONY: langtools-only corba-only jaxp-only jaxws-only hotspot-only jdk-only images-only overlay-images-only install-only +.PHONY: langtools corba jaxp jaxws hotspot jdk nashorn images overlay-images install +.PHONY: langtools-only corba-only jaxp-only jaxws-only hotspot-only jdk-only nashorn-only images-only overlay-images-only install-only .PHONY: all test clean dist-clean bootcycle-images start-make -.PHONY: clean-langtools clean-corba clean-jaxp clean-jaxws clean-hotspot clean-jdk clean-images clean-overlay-images clean-bootcycle-build +.PHONY: clean-langtools clean-corba clean-jaxp clean-jaxws clean-hotspot clean-jdk clean-nashorn clean-images clean-overlay-images clean-bootcycle-build .PHONY: profiles profiles-only profiles-oscheck FRC: # Force target diff --git a/common/makefiles/MakeBase.gmk b/common/makefiles/MakeBase.gmk index 708cbada085..4c1ecc8c8b7 100644 --- a/common/makefiles/MakeBase.gmk +++ b/common/makefiles/MakeBase.gmk @@ -51,8 +51,9 @@ decompress_paths=$(SED) -f $(SRC_ROOT)/common/makefiles/support/ListPathsSafely- -e 's|X98|$(OUTPUT_ROOT)|g' -e 's|X97|$(SRC_ROOT)|g' \ -e 's|X00|X|g' | tr '\n' '$2' +# Subst in an extra $ to prevent it from disappearing. define ListPathsSafely_If - $(if $(word $3,$($1)),$(eval $1_LPS$3:=$(call compress_paths,$(wordlist $3,$4,$($1))))) + $(if $(word $3,$($1)),$(eval $1_LPS$3:=$(call compress_paths,$(subst $$,$$$$,$(wordlist $3,$4,$($1)))))) endef define ListPathsSafely_Printf diff --git a/common/makefiles/javadoc/NON_CORE_PKGS.gmk b/common/makefiles/javadoc/NON_CORE_PKGS.gmk index 1d944d3dd19..c2e481119eb 100644 --- a/common/makefiles/javadoc/NON_CORE_PKGS.gmk +++ b/common/makefiles/javadoc/NON_CORE_PKGS.gmk @@ -80,7 +80,8 @@ JCONSOLE_PKGS = com.sun.tools.jconsole TREEAPI_PKGS = com.sun.source.doctree \ com.sun.source.tree \ - com.sun.source.util + com.sun.source.util \ + jdk SMARTCARDIO_PKGS = javax.smartcardio @@ -93,6 +94,8 @@ APPLE_EXT_PKGS = com.apple.concurrent \ com.apple.eio endif +JDK_PKGS = jdk + # non-core packages in rt.jar NON_CORE_PKGS = $(DOMAPI_PKGS) \ $(MGMT_PKGS) \ @@ -103,5 +106,5 @@ NON_CORE_PKGS = $(DOMAPI_PKGS) \ $(HTTPSERVER_PKGS) \ $(SMARTCARDIO_PKGS) \ $(SCTPAPI_PKGS) \ - $(APPLE_EXT_PKGS) - + $(APPLE_EXT_PKGS) \ + $(JDK_PKGS) diff --git a/corba/.hgtags b/corba/.hgtags index 7e7b0160fc2..92bf938663c 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -202,3 +202,5 @@ d4e68ce17795601017ac2f952baad7272942c36e jdk8-b75 27d6368ae8ba570c31c2f0e696d39c99fa2f4538 jdk8-b78 e41fb1aa0329767b2737303c994e38bede1baa07 jdk8-b79 5f3d4a6bdd027a1631d97e2dfff63fd5e46987a4 jdk8-b80 +2a00aeeb466b9dee22508f6261f63b70f9c696fe jdk8-b81 +48e1bc77004d9af575b733c04637b98fd17603c2 jdk8-b82 diff --git a/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_orbutil.jmk b/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_orbutil.jmk index 5009bb508e3..465c546ec59 100644 --- a/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_orbutil.jmk +++ b/corba/make/com/sun/corba/minclude/com_sun_corba_se_impl_orbutil.jmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -29,10 +29,6 @@ com_sun_corba_se_impl_orbutil_java = \ com/sun/corba/se/impl/orbutil/DenseIntMapImpl.java \ com/sun/corba/se/impl/orbutil/GetPropertyAction.java \ com/sun/corba/se/impl/orbutil/HexOutputStream.java \ - com/sun/corba/se/impl/orbutil/IIOPInputStream_1_3.java \ - com/sun/corba/se/impl/orbutil/IIOPInputStream_1_3_1.java \ - com/sun/corba/se/impl/orbutil/IIOPOutputStream_1_3.java \ - com/sun/corba/se/impl/orbutil/IIOPOutputStream_1_3_1.java \ com/sun/corba/se/impl/orbutil/LegacyHookGetFields.java \ com/sun/corba/se/impl/orbutil/LegacyHookPutFields.java \ com/sun/corba/se/impl/orbutil/LogKeywords.java \ @@ -45,19 +41,11 @@ com_sun_corba_se_impl_orbutil_java = \ com/sun/corba/se/impl/orbutil/ORBUtility.java \ com/sun/corba/se/impl/orbutil/ORBClassLoader.java \ com/sun/corba/se/impl/orbutil/RepIdDelegator.java \ - com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3.java \ - com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3_1.java \ - com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3.java \ - com/sun/corba/se/impl/orbutil/RepositoryId_1_3.java \ com/sun/corba/se/impl/orbutil/RepositoryIdFactory.java \ com/sun/corba/se/impl/orbutil/RepositoryIdStrings.java \ com/sun/corba/se/impl/orbutil/RepositoryIdUtility.java \ com/sun/corba/se/impl/orbutil/RepositoryIdInterface.java \ - com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3_1.java \ - com/sun/corba/se/impl/orbutil/RepositoryId_1_3_1.java \ com/sun/corba/se/impl/orbutil/StackImpl.java \ - com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3_1.java \ - com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3.java \ com/sun/corba/se/impl/orbutil/closure/Future.java \ com/sun/corba/se/impl/orbutil/closure/Constant.java \ com/sun/corba/se/impl/orbutil/concurrent/Sync.java \ diff --git a/corba/src/share/classes/com/sun/corba/se/impl/activation/ServerMain.java b/corba/src/share/classes/com/sun/corba/se/impl/activation/ServerMain.java index c51b08966bd..cd6d534af49 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/activation/ServerMain.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/activation/ServerMain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -322,9 +322,9 @@ class ServerCallback extends com.sun.corba.se.spi.activation._ServerImplBase { private ORB orb; - private Method installMethod ; - private Method uninstallMethod ; - private Method shutdownMethod ; + private transient Method installMethod ; + private transient Method uninstallMethod ; + private transient Method shutdownMethod ; private Object methodArgs[] ; ServerCallback(ORB orb, Method installMethod, Method uninstallMethod, diff --git a/corba/src/share/classes/com/sun/corba/se/impl/corba/AnyImpl.java b/corba/src/share/classes/com/sun/corba/se/impl/corba/AnyImpl.java index 6b33f34b9a9..0177bdd6407 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/corba/AnyImpl.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/corba/AnyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1218,7 +1218,7 @@ public class AnyImpl extends Any // See bug 4391648 for more info about the tcORB in this // case. RepositoryIdStrings repStrs - = RepositoryIdFactory.getRepIdStringsFactory(tcORB); + = RepositoryIdFactory.getRepIdStringsFactory(); // Assertion: c instanceof Serializable? @@ -1251,7 +1251,7 @@ public class AnyImpl extends Any // Anything else // We know that this is a TypeCodeImpl since it is our ORB classTC = (TypeCodeImpl)ValueUtility.createTypeCodeForClass( - tcORB, c, ORBUtility.createValueHandler(tcORB)); + tcORB, c, ORBUtility.createValueHandler()); // Intruct classTC to store its buffer classTC.setCaching(true); // Update the cache diff --git a/corba/src/share/classes/com/sun/corba/se/impl/corba/TypeCodeImpl.java b/corba/src/share/classes/com/sun/corba/se/impl/corba/TypeCodeImpl.java index c9b6e55fd6a..7e926ddba63 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/corba/TypeCodeImpl.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/corba/TypeCodeImpl.java @@ -2189,10 +2189,7 @@ public final class TypeCodeImpl extends TypeCode if (labelIndex == _unionLabels.length) { // check if label has not been found - if (_defaultIndex == -1) - // throw exception if default was not expected - throw wrapper.unexpectedUnionDefault() ; - else + if (_defaultIndex != -1) // must be of the default branch type _memberTypes[_defaultIndex].copy(src, dst); } diff --git a/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDRInputStream_1_0.java b/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDRInputStream_1_0.java index d17d6f378e2..a00d66cb5b5 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDRInputStream_1_0.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDRInputStream_1_0.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -269,8 +269,8 @@ public class CDRInputStream_1_0 extends CDRInputStreamBase private final void createRepositoryIdHandlers() { - repIdUtil = RepositoryIdFactory.getRepIdUtility(orb); - repIdStrs = RepositoryIdFactory.getRepIdStringsFactory(orb); + repIdUtil = RepositoryIdFactory.getRepIdUtility(); + repIdStrs = RepositoryIdFactory.getRepIdStringsFactory(); } public GIOPVersion getGIOPVersion() { @@ -564,10 +564,7 @@ public class CDRInputStream_1_0 extends CDRInputStreamBase checkForNegativeLength(len); - if (orb != null && ORBUtility.isLegacyORB((ORB)orb)) - return legacyReadString(len); - else - return internalReadString(len); + return internalReadString(len); } private final String internalReadString(int len) { @@ -588,54 +585,6 @@ public class CDRInputStream_1_0 extends CDRInputStreamBase return new String(result, 0, getCharConverter().getNumChars()); } - private final String legacyReadString(int len) { - - // - // Workaround for ORBs which send string lengths of - // zero to mean empty string. - // - // - // IMPORTANT: Do not replace 'new String("")' with "", it may result - // in a Serialization bug (See serialization.zerolengthstring) and - // bug id: 4728756 for details - if (len == 0) - return new String(""); - - len--; - char[] c = new char[len]; - - int n = 0; - while (n < len) { - int avail; - int bytes; - int wanted; - - avail = bbwi.buflen - bbwi.position(); - if (avail <= 0) { - grow(1, 1); - avail = bbwi.buflen - bbwi.position(); - } - wanted = len - n; - bytes = (wanted < avail) ? wanted : avail; - // Microbenchmarks are showing a loop of ByteBuffer.get(int) being - // faster than ByteBuffer.get(byte[], int, int). - for (int i=0; i bbwi.buflen) - alignAndCheck(1, 1); - bbwi.position(bbwi.position() + 1); - - return new String(c); - } - public final String read_string() { return readStringOrIndirection(false); } @@ -1045,7 +994,7 @@ public class CDRInputStream_1_0 extends CDRInputStreamBase try { if (valueHandler == null) - valueHandler = ORBUtility.createValueHandler(orb); + valueHandler = ORBUtility.createValueHandler(); value = valueHandler.readValue(parent, indirection, diff --git a/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDROutputStream_1_0.java b/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDROutputStream_1_0.java index 25e15286978..3e60c4801b0 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDROutputStream_1_0.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/encoding/CDROutputStream_1_0.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -189,18 +189,8 @@ public class CDROutputStream_1_0 extends CDROutputStreamBase private final void createRepositoryIdHandlers() { - if (orb != null) { - // Get the appropriate versions based on the ORB version. The - // ORB versioning info is only in the core ORB. - repIdUtil - = RepositoryIdFactory.getRepIdUtility(orb); - repIdStrs - = RepositoryIdFactory.getRepIdStringsFactory(orb); - } else { - // Get the latest versions - repIdUtil = RepositoryIdFactory.getRepIdUtility(); - repIdStrs = RepositoryIdFactory.getRepIdStringsFactory(); - } + repIdUtil = RepositoryIdFactory.getRepIdUtility(); + repIdStrs = RepositoryIdFactory.getRepIdStringsFactory(); } public BufferManagerWrite getBufferManager() @@ -705,7 +695,7 @@ public class CDROutputStream_1_0 extends CDROutputStreamBase private void writeArray(Serializable array, Class clazz) { if (valueHandler == null) - valueHandler = ORBUtility.createValueHandler(orb); //d11638 + valueHandler = ORBUtility.createValueHandler(); //d11638 // Write value_tag int indirection = writeValueTag(mustChunk, true, @@ -768,7 +758,7 @@ public class CDROutputStream_1_0 extends CDROutputStreamBase private void writeRMIIIOPValueType(Serializable object, Class clazz) { if (valueHandler == null) - valueHandler = ORBUtility.createValueHandler(orb); //d11638 + valueHandler = ORBUtility.createValueHandler(); //d11638 Serializable key = object; diff --git a/corba/src/share/classes/com/sun/corba/se/impl/io/FVDCodeBaseImpl.java b/corba/src/share/classes/com/sun/corba/se/impl/io/FVDCodeBaseImpl.java index f87ef71d45d..c69fb42421b 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/io/FVDCodeBaseImpl.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/io/FVDCodeBaseImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,7 +86,7 @@ public class FVDCodeBaseImpl extends _CodeBaseImplBase // default to using the current ORB version in case the // vhandler is not set if (vhandler == null) { - vhandler = new ValueHandlerImpl(false); + vhandler = ValueHandlerImpl.getInstance(false); } // Util.getCodebase may return null which would @@ -120,7 +120,7 @@ public class FVDCodeBaseImpl extends _CodeBaseImplBase // default to using the current ORB version in case the // vhandler is not set if (vhandler == null) { - vhandler = new ValueHandlerImpl(false); + vhandler = ValueHandlerImpl.getInstance(false); } try{ @@ -161,7 +161,7 @@ public class FVDCodeBaseImpl extends _CodeBaseImplBase // default to using the current ORB version in case the // vhandler is not set if (vhandler == null) { - vhandler = new ValueHandlerImpl(false); + vhandler = ValueHandlerImpl.getInstance(false); } Stack repIds = new Stack(); diff --git a/corba/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java b/corba/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java index c2e23a41387..2c6e3bc08bb 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ /* * Licensed Materials - Property of IBM * RMI-IIOP v1.0 - * Copyright IBM Corp. 1998 1999 All Rights Reserved + * Copyright IBM Corp. 1998 2012 All Rights Reserved * */ @@ -56,7 +56,6 @@ import java.io.Serializable; import java.util.Arrays; import java.util.Comparator; -import java.util.Hashtable; import com.sun.corba.se.impl.util.RepositoryId; @@ -83,8 +82,6 @@ public class ObjectStreamClass implements java.io.Serializable { private static Object noArgsList[] = {}; private static Class noTypesList[] = {}; - private static Hashtable translatedFields; - /** true if represents enum type */ private boolean isEnum; @@ -384,6 +381,42 @@ public class ObjectStreamClass implements java.io.Serializable { */ } + private static final class PersistentFieldsValue + extends ClassValue { + PersistentFieldsValue() { } + + protected ObjectStreamField[] computeValue(Class type) { + try { + Field pf = type.getDeclaredField("serialPersistentFields"); + int mods = pf.getModifiers(); + if (Modifier.isPrivate(mods) && Modifier.isStatic(mods) && + Modifier.isFinal(mods)) { + pf.setAccessible(true); + java.io.ObjectStreamField[] fields = + (java.io.ObjectStreamField[])pf.get(type); + return translateFields(fields); + } + } catch (NoSuchFieldException | IllegalAccessException | + IllegalArgumentException | ClassCastException e) { + } + return null; + } + + private static ObjectStreamField[] translateFields( + java.io.ObjectStreamField[] fields) { + ObjectStreamField[] translation = + new ObjectStreamField[fields.length]; + for (int i = 0; i < fields.length; i++) { + translation[i] = new ObjectStreamField(fields[i].getName(), + fields[i].getType()); + } + return translation; + } + } + + private static final PersistentFieldsValue persistentFieldsValue = + new PersistentFieldsValue(); + /* * Initialize class descriptor. This method is only invoked on class * descriptors created via calls to lookupInternal(). This method is kept @@ -416,35 +449,7 @@ public class ObjectStreamClass implements java.io.Serializable { * If it is declared, use the declared serialPersistentFields. * Otherwise, extract the fields from the class itself. */ - try { - Field pf = cl.getDeclaredField("serialPersistentFields"); - // serial bug 7; the serialPersistentFields were not - // being read and stored as Accessible bit was not set - pf.setAccessible(true); - // serial bug 7; need to find if the field is of type - // java.io.ObjectStreamField - java.io.ObjectStreamField[] f = - (java.io.ObjectStreamField[])pf.get(cl); - int mods = pf.getModifiers(); - if ((Modifier.isPrivate(mods)) && - (Modifier.isStatic(mods)) && - (Modifier.isFinal(mods))) - { - fields = (ObjectStreamField[])translateFields((Object[])pf.get(cl)); - } - } catch (NoSuchFieldException e) { - fields = null; - } catch (IllegalAccessException e) { - fields = null; - } catch (IllegalArgumentException e) { - fields = null; - } catch (ClassCastException e) { - /* Thrown if a field serialPersistentField exists - * but it is not of type ObjectStreamField. - */ - fields = null; - } - + fields = persistentFieldsValue.get(cl); if (fields == null) { /* Get all of the declared fields for this @@ -641,43 +646,6 @@ public class ObjectStreamClass implements java.io.Serializable { superclass = null; } - private static Object[] translateFields(Object objs[]) - throws NoSuchFieldException { - try{ - java.io.ObjectStreamField fields[] = (java.io.ObjectStreamField[])objs; - Object translation[] = null; - - if (translatedFields == null) - translatedFields = new Hashtable(); - - translation = (Object[])translatedFields.get(fields); - - if (translation != null) - return translation; - else { - Class osfClass = Class.forName("com.sun.corba.se.impl.io.ObjectStreamField"); - translation = (Object[])java.lang.reflect.Array.newInstance(osfClass, objs.length); - Object arg[] = new Object[2]; - Class types[] = {String.class, Class.class}; - Constructor constructor = osfClass.getDeclaredConstructor(types); - for (int i = fields.length -1; i >= 0; i--){ - arg[0] = fields[i].getName(); - arg[1] = fields[i].getType(); - - translation[i] = constructor.newInstance(arg); - } - translatedFields.put(fields, translation); - - } - - return (Object[])translation; - } - catch(Throwable t){ - NoSuchFieldException nsfe = new NoSuchFieldException(); - nsfe.initCause( t ) ; - throw nsfe ; - } - } /* * Set the class this version descriptor matches. @@ -1555,8 +1523,8 @@ public class ObjectStreamClass implements java.io.Serializable { private boolean hasExternalizableBlockData; Method writeObjectMethod; Method readObjectMethod; - private Method writeReplaceObjectMethod; - private Method readResolveObjectMethod; + private transient Method writeReplaceObjectMethod; + private transient Method readResolveObjectMethod; private Constructor cons ; /** diff --git a/corba/src/share/classes/com/sun/corba/se/impl/io/ValueHandlerImpl.java b/corba/src/share/classes/com/sun/corba/se/impl/io/ValueHandlerImpl.java index e1c82cf9bfc..fdf35018275 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/io/ValueHandlerImpl.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/io/ValueHandlerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ import com.sun.corba.se.spi.logging.CORBALogDomains; import com.sun.corba.se.impl.logging.OMGSystemException; import com.sun.corba.se.impl.logging.UtilSystemException; -public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat { +public final class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat { // Property to override our maximum stream format version public static final String FORMAT_VERSION_PROPERTY @@ -150,14 +150,22 @@ public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat writeValueWithVersion(out, value, streamFormatVersion); } - public ValueHandlerImpl(){} + private ValueHandlerImpl(){} - public ValueHandlerImpl(boolean isInputStream) { + private ValueHandlerImpl(boolean isInputStream) { this(); useHashtables = false; this.isInputStream = isInputStream; } + static ValueHandlerImpl getInstance() { + return new ValueHandlerImpl(); + } + + static ValueHandlerImpl getInstance(boolean isInputStream) { + return new ValueHandlerImpl(isInputStream); + } + /** * Writes the value to the stream using java semantics. * @param out The stream to write the value to @@ -458,12 +466,7 @@ public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat return ObjectStreamClass.lookup(value.getClass()).writeReplace(value); } - /** - * Encapsulates writing of Java char arrays so that the 1.3 subclass - * can override it without exposing internals across packages. This - * is a fix for bug 4367783. - */ - protected void writeCharArray(org.omg.CORBA_2_3.portable.OutputStream out, + private void writeCharArray(org.omg.CORBA_2_3.portable.OutputStream out, char[] array, int offset, int length) @@ -576,12 +579,7 @@ public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat } } - /** - * Encapsulates reading of Java char arrays so that the 1.3 subclass - * can override it without exposing internals across packages. This - * is a fix for bug 4367783. - */ - protected void readCharArray(org.omg.CORBA_2_3.portable.InputStream in, + private void readCharArray(org.omg.CORBA_2_3.portable.InputStream in, char[] array, int offset, int length) @@ -795,7 +793,7 @@ public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat return RepositoryId.cache.getId(repId).isSequence(); } - protected String getOutputStreamClassName() { + private String getOutputStreamClassName() { return "com.sun.corba.se.impl.io.IIOPOutputStream"; } @@ -843,29 +841,11 @@ public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat private IIOPOutputStream createOutputStreamBuiltInNoPriv( final String name ) throws IOException { - return - name.equals( - IIOPOutputStream - .class.getName() - ) ? - new IIOPOutputStream() : - - name.equals( - com.sun.corba.se.impl.orbutil.IIOPOutputStream_1_3 - .class.getName() - ) ? - new com.sun.corba.se.impl.orbutil.IIOPOutputStream_1_3() : - - name.equals( - com.sun.corba.se.impl.orbutil.IIOPOutputStream_1_3_1 - .class.getName() - ) ? - new com.sun.corba.se.impl.orbutil.IIOPOutputStream_1_3_1() : - - null; + return name.equals(IIOPOutputStream.class.getName()) ? + new IIOPOutputStream() : null; } - protected String getInputStreamClassName() { + private String getInputStreamClassName() { return "com.sun.corba.se.impl.io.IIOPInputStream"; } @@ -913,26 +893,8 @@ public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat private IIOPInputStream createInputStreamBuiltInNoPriv( final String name ) throws IOException { - return - name.equals( - IIOPInputStream - .class.getName() - ) ? - new IIOPInputStream() : - - name.equals( - com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3 - .class.getName() - ) ? - new com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3() : - - name.equals( - com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3_1 - .class.getName() - ) ? - new com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3_1() : - - null; + return name.equals(IIOPInputStream.class.getName()) ? + new IIOPInputStream() : null; } /** @@ -958,12 +920,7 @@ public class ValueHandlerImpl implements javax.rmi.CORBA.ValueHandlerMultiFormat } - /** - * Our JDK 1.3 and JDK 1.3.1 behavior subclasses override this. - * The correct behavior is for a Java char to map to a CORBA wchar, - * but our older code mapped it to a CORBA char. - */ - protected TCKind getJavaCharTCKind() { + TCKind getJavaCharTCKind() { return TCKind.tk_wchar; } } diff --git a/corba/src/share/classes/com/sun/corba/se/impl/io/ValueUtility.java b/corba/src/share/classes/com/sun/corba/se/impl/io/ValueUtility.java index 84bb1685515..41d85a265fc 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/io/ValueUtility.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/io/ValueUtility.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,6 +93,14 @@ public class ValueUtility { null, // tk_abstract_interface 32 }; + static { + sun.corba.SharedSecrets.setJavaCorbaAccess(new sun.corba.JavaCorbaAccess() { + public ValueHandlerImpl newValueHandlerImpl() { + return ValueHandlerImpl.getInstance(); + } + }); + } + public static String getSignature(ValueMember member) throws ClassNotFoundException { diff --git a/corba/src/share/classes/com/sun/corba/se/impl/javax/rmi/CORBA/Util.java b/corba/src/share/classes/com/sun/corba/se/impl/javax/rmi/CORBA/Util.java index 7721999591c..aa2c6483804 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/javax/rmi/CORBA/Util.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/javax/rmi/CORBA/Util.java @@ -112,6 +112,9 @@ import com.sun.corba.se.impl.util.JDKBridge; import com.sun.corba.se.impl.orbutil.ORBClassLoader; import com.sun.corba.se.impl.logging.UtilSystemException; import com.sun.corba.se.spi.logging.CORBALogDomains; +import sun.corba.SharedSecrets; +import sun.corba.JavaCorbaAccess; + /** * Provides utility methods that can be used by stubs and ties to @@ -125,7 +128,8 @@ public class Util implements javax.rmi.CORBA.UtilDelegate // Maps targets to ties. private static IdentityHashtable exportedServants = new IdentityHashtable(); - private static ValueHandlerImpl valueHandlerSingleton = new ValueHandlerImpl(); + private static final ValueHandlerImpl valueHandlerSingleton = + SharedSecrets.getJavaCorbaAccess().newValueHandlerImpl(); private UtilSystemException utilWrapper = UtilSystemException.get( CORBALogDomains.RPC_ENCODING); diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orb/ORBImpl.java b/corba/src/share/classes/com/sun/corba/se/impl/orb/ORBImpl.java index 9c03173238b..5db85734a95 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/orb/ORBImpl.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/orb/ORBImpl.java @@ -840,7 +840,7 @@ public class ORBImpl extends com.sun.corba.se.spi.orb.ORB // backward compatability 4365188 CodeBase cb; - ValueHandler vh = ORBUtility.createValueHandler(this); + ValueHandler vh = ORBUtility.createValueHandler(); cb = (CodeBase)vh.getRunTimeCodeBase(); return ORBUtility.connectAndGetIOR( this, cb ) ; diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPOutputStream_1_3.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPOutputStream_1_3.java deleted file mode 100644 index e9d81cdd254..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/IIOPOutputStream_1_3.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.corba.se.impl.orbutil; - -import java.io.*; - -/** - * Implements legacy behavior from before Ladybird to maintain - * backwards compatibility. - */ -public class IIOPOutputStream_1_3 extends com.sun.corba.se.impl.io.IIOPOutputStream -{ - // We can't assume that the superclass's putFields - // member will be non-private. We must allow - // the RI to run on JDK 1.3.1 FCS as well as - // the JDK 1.3.1_01 patch. - private ObjectOutputStream.PutField putFields_1_3; - - // The newer version in the io package correctly writes a wstring instead. - // This concerns bug 4379597. - protected void internalWriteUTF(org.omg.CORBA.portable.OutputStream stream, - String data) - { - stream.write_string(data); - } - - public IIOPOutputStream_1_3() - throws java.io.IOException { - super(); - } - - /** - * Before JDK 1.3.1_01, the PutField/GetField implementation - * actually sent a Hashtable. - */ - public ObjectOutputStream.PutField putFields() - throws IOException { - putFields_1_3 = new LegacyHookPutFields(); - return putFields_1_3; - } - - public void writeFields() - throws IOException { - putFields_1_3.write(this); - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ORBUtility.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ORBUtility.java index b4cc902ee7a..23d51f9008a 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ORBUtility.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ORBUtility.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -160,44 +160,12 @@ public final class ORBUtility { } /** - * Creates the correct ValueHandler for the given ORB, - * querying ORBVersion information. If the ORB or - * ORBVersion is null, gets the ValueHandler from - * Util.createValueHandler. + * Return default ValueHandler */ - public static ValueHandler createValueHandler(ORB orb) { - - if (orb == null) - return Util.createValueHandler(); - - ORBVersion version = orb.getORBVersion(); - - if (version == null) - return Util.createValueHandler(); - - if (version.equals(ORBVersionFactory.getOLD())) - return new ValueHandlerImpl_1_3(); - if (version.equals(ORBVersionFactory.getNEW())) - return new ValueHandlerImpl_1_3_1(); - + public static ValueHandler createValueHandler() { return Util.createValueHandler(); } - /** - * Returns true if the given ORB could accurately be determined to be a - * Kestrel or earlier ORB. Note: If passed the ORBSingleton, this will return - * false. - */ - public static boolean isLegacyORB(ORB orb) - { - try { - ORBVersion currentORB = orb.getORBVersion(); - return currentORB.equals( ORBVersionFactory.getOLD() ) ; - } catch (SecurityException se) { - return false; - } - } - /** * Returns true if it was accurately determined that the remote ORB is * a foreign (non-JavaSoft) ORB. Note: If passed the ORBSingleton, this diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ObjectStreamClass_1_3_1.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ObjectStreamClass_1_3_1.java index c9a6f8f1d51..891a4887123 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ObjectStreamClass_1_3_1.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ObjectStreamClass_1_3_1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1119,8 +1119,8 @@ public class ObjectStreamClass_1_3_1 implements java.io.Serializable { private boolean hasExternalizableBlockData; Method writeObjectMethod; Method readObjectMethod; - private Method writeReplaceObjectMethod; - private Method readResolveObjectMethod; + private transient Method writeReplaceObjectMethod; + private transient Method readResolveObjectMethod; /* * ObjectStreamClass_1_3_1 that this one was built from. diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3.java deleted file mode 100644 index c4e218304cb..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.corba.se.impl.orbutil; - -import org.omg.CORBA.ORB; -import java.io.Serializable; -import java.util.Hashtable; -import java.net.MalformedURLException; -import com.sun.corba.se.impl.io.TypeMismatchException; -import com.sun.corba.se.impl.util.RepositoryId; - -/** - * Delegates to the RepositoryId_1_3 implementation in - * com.sun.corba.se.impl.orbutil. This is necessary to - * overcome the fact that many of RepositoryId's methods - * are static. - */ -public final class RepIdDelegator_1_3 - implements RepositoryIdStrings, - RepositoryIdUtility, - RepositoryIdInterface -{ - // RepositoryIdFactory methods - - public String createForAnyType(Class type) { - return RepositoryId_1_3.createForAnyType(type); - } - - public String createForJavaType(Serializable ser) - throws TypeMismatchException - { - return RepositoryId_1_3.createForJavaType(ser); - } - - public String createForJavaType(Class clz) - throws TypeMismatchException - { - return RepositoryId_1_3.createForJavaType(clz); - } - - public String createSequenceRepID(java.lang.Object ser) { - return RepositoryId_1_3.createSequenceRepID(ser); - } - - public String createSequenceRepID(Class clazz) { - return RepositoryId_1_3.createSequenceRepID(clazz); - } - - public RepositoryIdInterface getFromString(String repIdString) { - return new RepIdDelegator_1_3(RepositoryId_1_3.cache.getId(repIdString)); - } - - // RepositoryIdUtility methods - - public boolean isChunkedEncoding(int valueTag) { - return RepositoryId.isChunkedEncoding(valueTag); - } - - public boolean isCodeBasePresent(int valueTag) { - return RepositoryId.isCodeBasePresent(valueTag); - } - - public String getClassDescValueRepId() { - return RepositoryId_1_3.kClassDescValueRepID; - } - - public String getWStringValueRepId() { - return RepositoryId_1_3.kWStringValueRepID; - } - - public int getTypeInfo(int valueTag) { - return RepositoryId.getTypeInfo(valueTag); - } - - public int getStandardRMIChunkedNoRepStrId() { - return RepositoryId.kPreComputed_StandardRMIChunked_NoRep; - } - - public int getCodeBaseRMIChunkedNoRepStrId() { - return RepositoryId.kPreComputed_CodeBaseRMIChunked_NoRep; - } - - public int getStandardRMIChunkedId() { - return RepositoryId.kPreComputed_StandardRMIChunked; - } - - public int getCodeBaseRMIChunkedId() { - return RepositoryId.kPreComputed_CodeBaseRMIChunked; - } - - public int getStandardRMIUnchunkedId() { - return RepositoryId.kPreComputed_StandardRMIUnchunked; - } - - public int getCodeBaseRMIUnchunkedId() { - return RepositoryId.kPreComputed_CodeBaseRMIUnchunked; - } - - public int getStandardRMIUnchunkedNoRepStrId() { - return RepositoryId.kPreComputed_StandardRMIUnchunked_NoRep; - } - - public int getCodeBaseRMIUnchunkedNoRepStrId() { - return RepositoryId.kPreComputed_CodeBaseRMIUnchunked_NoRep; - } - - // RepositoryIdInterface methods - - public Class getClassFromType() throws ClassNotFoundException { - return delegate.getClassFromType(); - } - - public Class getClassFromType(String codebaseURL) - throws ClassNotFoundException, MalformedURLException - { - return delegate.getClassFromType(codebaseURL); - } - - public Class getClassFromType(Class expectedType, - String codebaseURL) - throws ClassNotFoundException, MalformedURLException - { - return delegate.getClassFromType(expectedType, codebaseURL); - } - - public String getClassName() { - return delegate.getClassName(); - } - - // Constructor used for factory/utility cases - public RepIdDelegator_1_3() {} - - // Constructor used by getIdFromString. All non-static - // RepositoryId methods will use the provided delegate. - private RepIdDelegator_1_3(RepositoryId_1_3 _delegate) { - this.delegate = _delegate; - } - - private RepositoryId_1_3 delegate = null; - - public String toString() { - if (delegate != null) - return delegate.toString(); - else - return this.getClass().getName(); - } - - public boolean equals(Object obj) { - if (delegate != null) - return delegate.equals(obj); - else - return super.equals(obj); - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3_1.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3_1.java deleted file mode 100644 index dc1195fa073..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepIdDelegator_1_3_1.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.corba.se.impl.orbutil; - -import org.omg.CORBA.ORB; -import java.io.Serializable; -import java.util.Hashtable; -import java.net.MalformedURLException; -import com.sun.corba.se.impl.io.TypeMismatchException; -import com.sun.corba.se.impl.util.RepositoryId; - -/** - * Delegates to the RepositoryId_1_3_1 implementation in - * com.sun.corba.se.impl.orbutil. This is necessary to - * overcome the fact that many of RepositoryId's methods - * are static. - */ -public final class RepIdDelegator_1_3_1 - implements RepositoryIdStrings, - RepositoryIdUtility, - RepositoryIdInterface -{ - // RepositoryIdFactory methods - - public String createForAnyType(Class type) { - return RepositoryId_1_3_1.createForAnyType(type); - } - - public String createForJavaType(Serializable ser) - throws TypeMismatchException - { - return RepositoryId_1_3_1.createForJavaType(ser); - } - - public String createForJavaType(Class clz) - throws TypeMismatchException - { - return RepositoryId_1_3_1.createForJavaType(clz); - } - - public String createSequenceRepID(java.lang.Object ser) { - return RepositoryId_1_3_1.createSequenceRepID(ser); - } - - public String createSequenceRepID(Class clazz) { - return RepositoryId_1_3_1.createSequenceRepID(clazz); - } - - public RepositoryIdInterface getFromString(String repIdString) { - return new RepIdDelegator_1_3_1(RepositoryId_1_3_1.cache.getId(repIdString)); - } - - // RepositoryIdUtility methods - - public boolean isChunkedEncoding(int valueTag) { - return RepositoryId.isChunkedEncoding(valueTag); - } - - public boolean isCodeBasePresent(int valueTag) { - return RepositoryId.isCodeBasePresent(valueTag); - } - - public String getClassDescValueRepId() { - return RepositoryId_1_3_1.kClassDescValueRepID; - } - - public String getWStringValueRepId() { - return RepositoryId_1_3_1.kWStringValueRepID; - } - - public int getTypeInfo(int valueTag) { - return RepositoryId.getTypeInfo(valueTag); - } - - public int getStandardRMIChunkedNoRepStrId() { - return RepositoryId.kPreComputed_StandardRMIChunked_NoRep; - } - - public int getCodeBaseRMIChunkedNoRepStrId() { - return RepositoryId.kPreComputed_CodeBaseRMIChunked_NoRep; - } - - public int getStandardRMIChunkedId() { - return RepositoryId.kPreComputed_StandardRMIChunked; - } - - public int getCodeBaseRMIChunkedId() { - return RepositoryId.kPreComputed_CodeBaseRMIChunked; - } - - public int getStandardRMIUnchunkedId() { - return RepositoryId.kPreComputed_StandardRMIUnchunked; - } - - public int getCodeBaseRMIUnchunkedId() { - return RepositoryId.kPreComputed_CodeBaseRMIUnchunked; - } - - public int getStandardRMIUnchunkedNoRepStrId() { - return RepositoryId.kPreComputed_StandardRMIUnchunked_NoRep; - } - - public int getCodeBaseRMIUnchunkedNoRepStrId() { - return RepositoryId.kPreComputed_CodeBaseRMIUnchunked_NoRep; - } - - // RepositoryIdInterface methods - - public Class getClassFromType() throws ClassNotFoundException { - return delegate.getClassFromType(); - } - - public Class getClassFromType(String codebaseURL) - throws ClassNotFoundException, MalformedURLException - { - return delegate.getClassFromType(codebaseURL); - } - - public Class getClassFromType(Class expectedType, - String codebaseURL) - throws ClassNotFoundException, MalformedURLException - { - return delegate.getClassFromType(expectedType, codebaseURL); - } - - public String getClassName() { - return delegate.getClassName(); - } - - // Constructor used for factory/utility cases - public RepIdDelegator_1_3_1() {} - - // Constructor used by getIdFromString. All non-static - // RepositoryId methods will use the provided delegate. - private RepIdDelegator_1_3_1(RepositoryId_1_3_1 _delegate) { - this.delegate = _delegate; - } - - private RepositoryId_1_3_1 delegate = null; - - public String toString() { - if (delegate != null) - return delegate.toString(); - else - return this.getClass().getName(); - } - - public boolean equals(Object obj) { - if (delegate != null) - return delegate.equals(obj); - else - return super.equals(obj); - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3.java deleted file mode 100644 index 3a35b33a645..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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. - */ -/* - * Licensed Materials - Property of IBM - * RMI-IIOP v1.0 - * Copyright IBM Corp. 1998 1999 All Rights Reserved - * - */ - -package com.sun.corba.se.impl.orbutil; - -import java.util.Stack; -import java.util.Hashtable; -import java.util.EmptyStackException; -import java.util.Enumeration; - -// Really limited pool - in this case just creating several at a time... -class RepositoryIdPool_1_3 extends Stack { - - private static int MAX_CACHE_SIZE = 4; - private RepositoryIdCache_1_3 cache; - - public final synchronized RepositoryId_1_3 popId() { - - try { - return (RepositoryId_1_3)super.pop(); - } - catch(EmptyStackException e) { - increasePool(5); - return (RepositoryId_1_3)super.pop(); - } - - } - - // Pool management - final void increasePool(int size) { - //if (cache.size() <= MAX_CACHE_SIZE) - for (int i = size; i > 0; i--) - push(new RepositoryId_1_3()); - /* - // _REVISIT_ This will not work w/out either thread tracing or weak references. I am - // betting that thread tracing almost completely negates benefit of reuse. Until either - // 1.2 only inclusion or proof to the contrary, I'll leave it this way... - else { - int numToReclaim = cache.size() / 2; - Enumeration keys = cache.keys(); - Enumeration elements = cache.elements(); - for (int i = numToReclaim; i > 0; i--) { - Object key = keys.nextElement(); - Object element = elements.nextElement(); - - push(element); - cache.remove(key); - } - } - */ - } - - final void setCaches(RepositoryIdCache_1_3 cache) { - this.cache = cache; - } - -} - -public class RepositoryIdCache_1_3 extends Hashtable { - - private RepositoryIdPool_1_3 pool = new RepositoryIdPool_1_3(); - - public RepositoryIdCache_1_3() { - pool.setCaches(this); - } - - public final synchronized RepositoryId_1_3 getId(String key) { - RepositoryId_1_3 repId = (RepositoryId_1_3)super.get(key); - - if (repId != null) - return repId; - else { - //repId = pool.popId().init(key); - repId = new RepositoryId_1_3(key); - put(key, repId); - return repId; - } - - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3_1.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3_1.java deleted file mode 100644 index 11acc5b522a..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdCache_1_3_1.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2001, 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.corba.se.impl.orbutil; - -import java.util.Stack; -import java.util.Hashtable; -import java.util.EmptyStackException; -import java.util.Enumeration; - -// Really limited pool - in this case just creating several at a time... -class RepositoryIdPool_1_3_1 extends Stack { - - private static int MAX_CACHE_SIZE = 4; - private RepositoryIdCache_1_3_1 cache; - - public final synchronized RepositoryId_1_3_1 popId() { - - try { - return (RepositoryId_1_3_1)super.pop(); - } - catch(EmptyStackException e) { - increasePool(5); - return (RepositoryId_1_3_1)super.pop(); - } - - } - - // Pool management - final void increasePool(int size) { - //if (cache.size() <= MAX_CACHE_SIZE) - for (int i = size; i > 0; i--) - push(new RepositoryId_1_3_1()); - /* - // _REVISIT_ This will not work w/out either thread tracing or weak references. I am - // betting that thread tracing almost completely negates benefit of reuse. Until either - // 1.2 only inclusion or proof to the contrary, I'll leave it this way... - else { - int numToReclaim = cache.size() / 2; - Enumeration keys = cache.keys(); - Enumeration elements = cache.elements(); - for (int i = numToReclaim; i > 0; i--) { - Object key = keys.nextElement(); - Object element = elements.nextElement(); - - push(element); - cache.remove(key); - } - } - */ - } - - final void setCaches(RepositoryIdCache_1_3_1 cache) { - this.cache = cache; - } - -} - -public class RepositoryIdCache_1_3_1 extends Hashtable { - - private RepositoryIdPool_1_3_1 pool = new RepositoryIdPool_1_3_1(); - - public RepositoryIdCache_1_3_1() { - pool.setCaches(this); - } - - public final synchronized RepositoryId_1_3_1 getId(String key) { - RepositoryId_1_3_1 repId = (RepositoryId_1_3_1)super.get(key); - - if (repId != null) - return repId; - else { - //repId = pool.popId().init(key); - repId = new RepositoryId_1_3_1(key); - put(key, repId); - return repId; - } - - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdFactory.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdFactory.java index 35014680527..5f3a237e995 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdFactory.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryIdFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,12 +30,6 @@ import com.sun.corba.se.spi.orb.ORB; public abstract class RepositoryIdFactory { - private static final RepIdDelegator_1_3 legacyDelegator - = new RepIdDelegator_1_3(); - - private static final RepIdDelegator_1_3_1 ladybirdDelegator - = new RepIdDelegator_1_3_1(); - private static final RepIdDelegator currentDelegator = new RepIdDelegator(); @@ -47,29 +41,6 @@ public abstract class RepositoryIdFactory return currentDelegator; } - /** - * Checks the version of the ORB and returns the appropriate - * RepositoryIdStrings instance. - */ - public static RepositoryIdStrings getRepIdStringsFactory(ORB orb) - { - if (orb != null) { - switch (orb.getORBVersion().getORBType()) { - case ORBVersion.NEWER: - case ORBVersion.FOREIGN: - case ORBVersion.JDK1_3_1_01: - return currentDelegator; - case ORBVersion.OLD: - return legacyDelegator; - case ORBVersion.NEW: - return ladybirdDelegator; - default: - return currentDelegator; - } - } else - return currentDelegator; - } - /** * Returns the latest version RepositoryIdUtility instance */ @@ -78,26 +49,4 @@ public abstract class RepositoryIdFactory return currentDelegator; } - /** - * Checks the version of the ORB and returns the appropriate - * RepositoryIdUtility instance. - */ - public static RepositoryIdUtility getRepIdUtility(ORB orb) - { - if (orb != null) { - switch (orb.getORBVersion().getORBType()) { - case ORBVersion.NEWER: - case ORBVersion.FOREIGN: - case ORBVersion.JDK1_3_1_01: - return currentDelegator; - case ORBVersion.OLD: - return legacyDelegator; - case ORBVersion.NEW: - return ladybirdDelegator; - default: - return currentDelegator; - } - } else - return currentDelegator; - } } diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryId_1_3.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryId_1_3.java deleted file mode 100644 index 8cf9edd4834..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryId_1_3.java +++ /dev/null @@ -1,990 +0,0 @@ -/* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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. - */ -/* - * Licensed Materials - Property of IBM - * RMI-IIOP v1.0 - * Copyright IBM Corp. 1998 1999 All Rights Reserved - * - */ - -package com.sun.corba.se.impl.orbutil; - -import java.util.StringTokenizer; -import java.util.Hashtable; -import java.io.IOException; -import java.lang.reflect.Method; - -// Imports for using codebase URL to load class -import java.net.MalformedURLException; -import org.omg.CORBA.portable.ValueBase; -import org.omg.CORBA.portable.IDLEntity; - -import com.sun.corba.se.impl.util.JDKBridge; -import com.sun.corba.se.impl.util.Utility; -import com.sun.corba.se.impl.util.PackagePrefixChecker; -import com.sun.corba.se.impl.util.IdentityHashtable; -import com.sun.corba.se.impl.io.ObjectStreamClass; - -import javax.rmi.CORBA.Util; - -// keeping the original RepositoryId class that was shipped in -// JDK 1.3. It has interoperability bugs - -public class RepositoryId_1_3 { - - // Legal IDL Identifier characters (1 = legal). Note - // that '.' (2E) is marked as legal even though it is - // not legal in IDL. This allows us to treat a fully - // qualified Java name with '.' package separators - // uniformly, and is safe because that is the only - // legal use of '.' in a Java name. - - public static final RepositoryIdCache_1_3 cache = new RepositoryIdCache_1_3(); - private static final byte[] IDL_IDENTIFIER_CHARS = { - - // 0 1 2 3 4 5 6 7 8 9 a b c d e f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 00-0f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 10-1f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,1,0, // 20-2f - 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0, // 30-3f - 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // 40-4f - 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1, // 50-5f - 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // 60-6f - 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0, // 70-7f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 80-8f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 90-9f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // a0-af - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // b0-bf - 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // c0-cf - 0,1,1,1, 1,1,1,0, 1,1,1,1, 1,0,0,1, // d0-df - 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // e0-ef - 0,1,1,1, 1,1,1,0, 1,1,1,1, 1,0,0,1, // f0-ff - }; - - private static String defaultServerURL = null; - private static boolean useCodebaseOnly = false; - - static { - if (defaultServerURL == null) - defaultServerURL = (String)JDKBridge.getLocalCodebase(); - useCodebaseOnly = JDKBridge.useCodebaseOnly(); - - } - - private static IdentityHashtable classToRepStr = new IdentityHashtable(); - private static IdentityHashtable classIDLToRepStr = new IdentityHashtable(); - private static IdentityHashtable classSeqToRepStr = new IdentityHashtable(); - - private static IdentityHashtable repStrToByteArray = new IdentityHashtable(); - private static Hashtable repStrToClass = new Hashtable(); - - private String repId = null; - private boolean isSupportedFormat = true; - private String typeString = null; - private String versionString = null; - private boolean isSequence = false; - private boolean isRMIValueType = false; - private boolean isIDLType = false; - private String completeClassName = null; - private String unqualifiedName = null; - private String definedInId = null; - private Class clazz = null; - private String suid = null, actualSuid = null; - private long suidLong = ObjectStreamClass.kDefaultUID, actualSuidLong = ObjectStreamClass.kDefaultUID; - - // Repository ID fragments - private static final String kValuePrefix = "RMI:"; - private static final String kIDLPrefix = "IDL:"; - private static final String kIDLNamePrefix = "omg.org/"; - private static final String kIDLClassnamePrefix = "org.omg."; - private static final String kSequencePrefix = "["; - private static final String kCORBAPrefix = "CORBA/"; - private static final String kArrayPrefix = kValuePrefix + kSequencePrefix + kCORBAPrefix; - private static final int kValuePrefixLength = kValuePrefix.length(); - private static final int kIDLPrefixLength = kIDLPrefix.length(); - private static final int kSequencePrefixLength = kSequencePrefix.length(); - private static final String kInterfaceHashCode = ":0000000000000000"; - private static final String kInterfaceOnlyHashStr = "0000000000000000"; - private static final String kExternalizableHashStr = "0000000000000001"; - - // Value tag utility methods and constants - public static final int kInitialValueTag= 0x7fffff00; - public static final int kNoTypeInfo = 0; - public static final int kSingleRepTypeInfo = 0x02; - public static final int kPartialListTypeInfo = 0x06; - public static final int kChunkedMask = 0x08; - - // Public, well known repository IDs - - // _REVISIT_ : A table structure with a good search routine for all of this - // would be more efficient and easier to maintain... - - // String - public static final String kWStringValueVersion = "1.0"; - public static final String kWStringValueHash = ":"+kWStringValueVersion; - public static final String kWStringStubValue = "WStringValue"; - public static final String kWStringTypeStr = "omg.org/CORBA/"+kWStringStubValue; - public static final String kWStringValueRepID = kIDLPrefix + kWStringTypeStr + kWStringValueHash; - - // Any - public static final String kAnyRepID = kIDLPrefix + "omg.org/CORBA/Any"; - - // Class - public static final String kClassDescValueHash = ":" + Long.toHexString( - ObjectStreamClass.getSerialVersionUID(javax.rmi.CORBA.ClassDesc.class)); - public static final String kClassDescStubValue = "ClassDesc"; - public static final String kClassDescTypeStr = "javax.rmi.CORBA."+kClassDescStubValue; - public static final String kClassDescValueRepID = kValuePrefix + kClassDescTypeStr + kClassDescValueHash; - - // Object - public static final String kObjectValueHash = ":1.0"; - public static final String kObjectStubValue = "Object"; - - // Sequence - public static final String kSequenceValueHash = ":1.0"; - public static final String kPrimitiveSequenceValueHash = ":0000000000000000"; - - // Serializable - public static final String kSerializableValueHash = ":1.0"; - public static final String kSerializableStubValue = "Serializable"; - - // Externalizable - public static final String kExternalizableValueHash = ":1.0"; - public static final String kExternalizableStubValue = "Externalizable"; - - // Remote (The empty string is used for java.rmi.Remote) - public static final String kRemoteValueHash = ""; - public static final String kRemoteStubValue = ""; - public static final String kRemoteTypeStr = ""; - public static final String kRemoteValueRepID = ""; - - private static final Hashtable kSpecialArrayTypeStrings = new Hashtable(); - - static { - kSpecialArrayTypeStrings.put("CORBA.WStringValue", new StringBuffer(java.lang.String.class.getName())); - kSpecialArrayTypeStrings.put("javax.rmi.CORBA.ClassDesc", new StringBuffer(java.lang.Class.class.getName())); - kSpecialArrayTypeStrings.put("CORBA.Object", new StringBuffer(java.rmi.Remote.class.getName())); - - } - - private static final Hashtable kSpecialCasesRepIDs = new Hashtable(); - - static { - kSpecialCasesRepIDs.put(java.lang.String.class, kWStringValueRepID); - kSpecialCasesRepIDs.put(java.lang.Class.class, kClassDescValueRepID); - kSpecialCasesRepIDs.put(java.rmi.Remote.class, kRemoteValueRepID); - } - - private static final Hashtable kSpecialCasesStubValues = new Hashtable(); - - static { - kSpecialCasesStubValues.put(java.lang.String.class, kWStringStubValue); - kSpecialCasesStubValues.put(java.lang.Class.class, kClassDescStubValue); - kSpecialCasesStubValues.put(java.lang.Object.class, kObjectStubValue); - kSpecialCasesStubValues.put(java.io.Serializable.class, kSerializableStubValue); - kSpecialCasesStubValues.put(java.io.Externalizable.class, kExternalizableStubValue); - kSpecialCasesStubValues.put(java.rmi.Remote.class, kRemoteStubValue); - } - - - private static final Hashtable kSpecialCasesVersions = new Hashtable(); - - static { - kSpecialCasesVersions.put(java.lang.String.class, kWStringValueHash); - kSpecialCasesVersions.put(java.lang.Class.class, kClassDescValueHash); - kSpecialCasesVersions.put(java.lang.Object.class, kObjectValueHash); - kSpecialCasesVersions.put(java.io.Serializable.class, kSerializableValueHash); - kSpecialCasesVersions.put(java.io.Externalizable.class, kExternalizableValueHash); - kSpecialCasesVersions.put(java.rmi.Remote.class, kRemoteValueHash); - } - - private static final Hashtable kSpecialCasesClasses = new Hashtable(); - - static { - kSpecialCasesClasses.put(kWStringTypeStr, java.lang.String.class); - kSpecialCasesClasses.put(kClassDescTypeStr, java.lang.Class.class); - kSpecialCasesClasses.put(kRemoteTypeStr, java.rmi.Remote.class); - - kSpecialCasesClasses.put("org.omg.CORBA.WStringValue", java.lang.String.class); - kSpecialCasesClasses.put("javax.rmi.CORBA.ClassDesc", java.lang.Class.class); - //kSpecialCasesClasses.put(kRemoteTypeStr, java.rmi.Remote.class); - } - - private static final Hashtable kSpecialCasesArrayPrefix = new Hashtable(); - - static { - kSpecialCasesArrayPrefix.put(java.lang.String.class, kValuePrefix + kSequencePrefix + kCORBAPrefix); - kSpecialCasesArrayPrefix.put(java.lang.Class.class, kValuePrefix + kSequencePrefix + "javax/rmi/CORBA/"); - kSpecialCasesArrayPrefix.put(java.lang.Object.class, kValuePrefix + kSequencePrefix + "java/lang/"); - kSpecialCasesArrayPrefix.put(java.io.Serializable.class, kValuePrefix + kSequencePrefix + "java/io/"); - kSpecialCasesArrayPrefix.put(java.io.Externalizable.class, kValuePrefix + kSequencePrefix + "java/io/"); - kSpecialCasesArrayPrefix.put(java.rmi.Remote.class, kValuePrefix + kSequencePrefix + kCORBAPrefix); - } - - private static final Hashtable kSpecialPrimitives = new Hashtable(); - - static { - kSpecialPrimitives.put("int","long"); - kSpecialPrimitives.put("long","longlong"); - kSpecialPrimitives.put("byte","octet"); - } - - /** - * Used to convert ascii to hex. - */ - private static final byte ASCII_HEX[] = { - (byte)'0', - (byte)'1', - (byte)'2', - (byte)'3', - (byte)'4', - (byte)'5', - (byte)'6', - (byte)'7', - (byte)'8', - (byte)'9', - (byte)'A', - (byte)'B', - (byte)'C', - (byte)'D', - (byte)'E', - (byte)'F', - }; - - - // Interface Rep ID Strings - public static final String kjava_rmi_Remote = createForAnyType(java.rmi.Remote.class); - public static final String korg_omg_CORBA_Object = createForAnyType(org.omg.CORBA.Object.class); - - // Dummy arguments for getIdFromHelper method - public static final Class kNoParamTypes[] ={}; - public static final Object kNoArgs[] = {}; - - - RepositoryId_1_3(){} - - RepositoryId_1_3(String aRepId){ - init(aRepId); - } - - RepositoryId_1_3 init(String aRepId){ - - this.repId = aRepId; - - // Special case for remote - if (aRepId.length() == 0) { - clazz = java.rmi.Remote.class; - typeString = ""; - isRMIValueType = true; - suid = kInterfaceOnlyHashStr; - return this; - } - else if (aRepId.equals(kWStringValueRepID)) { - clazz = java.lang.String.class; - typeString = kWStringTypeStr; - isIDLType = true; - versionString = kWStringValueVersion; - return this; - } - else { - - String repId = convertFromISOLatin1(aRepId); - - versionString = repId.substring(repId.indexOf(':', repId.indexOf(':')+1)); - if (repId.startsWith(kIDLPrefix)) { - typeString = - repId.substring(kIDLPrefixLength, repId.indexOf(':', kIDLPrefixLength)); - isIDLType = true; - if (typeString.startsWith(kIDLNamePrefix)) - completeClassName = kIDLClassnamePrefix + - typeString.substring(kIDLNamePrefix.length()).replace('/','.'); - else completeClassName = typeString.replace('/','.'); - - } - else if (repId.startsWith(kValuePrefix)) { - typeString = - repId.substring(kValuePrefixLength, repId.indexOf(':', kValuePrefixLength)); - isRMIValueType = true; - - if (versionString.indexOf('.') == -1) { - actualSuid = versionString.substring(1); - suid = actualSuid; // default if not explicitly specified - - if (actualSuid.indexOf(':') != -1){ - // we have a declared hash also - int pos = actualSuid.indexOf(':')+1; - // actualSuid = suid.substring(pos); - // suid = suid.substring(0, pos-1); - suid = actualSuid.substring(pos); - actualSuid = actualSuid.substring(0, pos-1); - } - - } - else { - // _REVISIT_ : Special case version failure ? - } - } - else isSupportedFormat = false; - - if (typeString.startsWith(kSequencePrefix)) { - isSequence = true; - } - - - return this; - } - } - - public final String getUnqualifiedName() { - if (unqualifiedName == null){ - String className = getClassName(); - int index = (className != null) ? className.lastIndexOf('.') : -1; - if (index == -1){ - unqualifiedName = className; - definedInId = "IDL::1.0"; - } - else { - unqualifiedName = className.substring(index); - definedInId = "IDL:" + className.substring(0, index).replace('.','/') + ":1.0"; - } - } - - return unqualifiedName; - } - - public final String getDefinedInId() { - if (definedInId == null){ - getUnqualifiedName(); - } - - return definedInId; - } - - public final String getTypeString() { - return typeString; - } - - public final String getVersionString() { - return versionString; - } - - public final String getSerialVersionUID() { - return suid; - } - - public final String getActualSerialVersionUID() { - return actualSuid; - } - public final long getSerialVersionUIDAsLong() { - return suidLong; - } - - public final long getActualSerialVersionUIDAsLong() { - return actualSuidLong; - } - - public final boolean isRMIValueType() { - return isRMIValueType; - } - - public final boolean isIDLType() { - return isIDLType; - } - - public final String getRepositoryId() { - return repId; - } - - public static byte[] getByteArray(String repStr) { - synchronized (repStrToByteArray){ - return (byte[]) repStrToByteArray.get(repStr); - } - } - - public static void setByteArray(String repStr, byte[] repStrBytes) { - synchronized (repStrToByteArray){ - repStrToByteArray.put(repStr, repStrBytes); - } - } - - public final boolean isSequence() { - return isSequence; - } - - public final boolean isSupportedFormat() { - return isSupportedFormat; - } - - - // This method will return the classname from the typestring OR if the classname turns out to be - // a special class "pseudo" name, then the matching real classname is returned. - public final String getClassName() { - - if (isRMIValueType) - return typeString; - else if (isIDLType) - return completeClassName; - else return null; - - } - - // This method calls getClazzFromType() and falls back to the repStrToClass - // cache if no class was found. It's used where any class matching the - // given repid is an acceptable result. - public final Class getAnyClassFromType() throws ClassNotFoundException { - try { - return getClassFromType(); - } catch (ClassNotFoundException cnfe) { - Class clz = (Class)repStrToClass.get(repId); - if (clz != null) - return clz; - else - throw cnfe; - } - } - - public final Class getClassFromType() - throws ClassNotFoundException { - if (clazz != null) - return clazz; - - Class specialCase = (Class)kSpecialCasesClasses.get(getClassName()); - - if (specialCase != null){ - clazz = specialCase; - return specialCase; - } - else - { - try{ - return Util.loadClass(getClassName(), null, null); - } - catch(ClassNotFoundException cnfe){ - if (defaultServerURL != null) { - try{ - return getClassFromType(defaultServerURL); - } - catch(MalformedURLException mue){ - throw cnfe; - } - } - else throw cnfe; - } - } - - } - - public final Class getClassFromType(Class expectedType, String codebase) - throws ClassNotFoundException { - if (clazz != null) - return clazz; - - Class specialCase = (Class)kSpecialCasesClasses.get(getClassName()); - - if (specialCase != null){ - clazz = specialCase; - return specialCase; - } else { - ClassLoader expectedTypeClassLoader = (expectedType == null ? null : expectedType.getClassLoader()); - return loadClassOfType(getClassName(), - codebase, - expectedTypeClassLoader, - expectedType, - expectedTypeClassLoader); - } - - } - - public final Class getClassFromType(String url) - throws ClassNotFoundException, MalformedURLException { - return Util.loadClass(getClassName(), url, null); - } - - public final String toString() { - return repId; - } - - private static String createHashString(java.io.Serializable ser) { - - return createHashString(ser.getClass()); - } - - private static String createHashString(java.lang.Class clazz) { - - if (clazz.isInterface() || !java.io.Serializable.class.isAssignableFrom(clazz)) - return kInterfaceHashCode; - - - long actualLong = ObjectStreamClassUtil_1_3.computeStructuralUID(false, clazz); - String hash = null; - if (actualLong == 0) - hash = kInterfaceOnlyHashStr; - else if (actualLong == 1) - hash = kExternalizableHashStr; - else - hash = Long.toHexString(actualLong).toUpperCase(); - while(hash.length() < 16){ - hash = "0" + hash; - } - - long declaredLong = ObjectStreamClassUtil_1_3.computeSerialVersionUID(clazz); - String declared = null; - if (declaredLong == 0) - declared = kInterfaceOnlyHashStr; - else if (declaredLong == 1) - declared = kExternalizableHashStr; - else - declared = Long.toHexString(declaredLong).toUpperCase(); - while (declared.length() < 16){ - declared = "0" + declared; - } - hash = hash + ":" + declared; - - return ":" + hash; - } - - /** - * Creates a repository ID for a sequence. This is for expert users only as - * this method assumes the object passed is an array. If passed an object - * that is not an array, it will produce a rep id for a sequence of zero - * length. This would be an error. - * @param ser The Java object to create a repository ID for - **/ - public static String createSequenceRepID(java.lang.Object ser){ - return createSequenceRepID(ser.getClass()); - } - - /** - * Creates a repository ID for a sequence. This is for expert users only as - * this method assumes the object passed is an array. If passed an object - * that is not an array, it will produce a malformed rep id. - * @param clazz The Java class to create a repository ID for - **/ - public static String createSequenceRepID(java.lang.Class clazz){ - synchronized (classSeqToRepStr){ - - String repid = (String)classSeqToRepStr.get(clazz); - if (repid != null) - return repid; - - Class originalClazz = clazz; - - Class type = null; - int numOfDims = 0; - - while ((type = clazz.getComponentType()) != null) { - numOfDims++; - clazz = type; - } - - if (clazz.isPrimitive()) - repid = kValuePrefix + originalClazz.getName() + kPrimitiveSequenceValueHash; - else { - StringBuffer buf = new StringBuffer(); - buf.append(kValuePrefix); - while(numOfDims-- > 0) { - buf.append("["); - } - buf.append("L"); - buf.append(convertToISOLatin1(clazz.getName())); - buf.append(";"); - buf.append(createHashString(clazz)); - repid = buf.toString(); - } - classSeqToRepStr.put(originalClazz,repid); - return repid; - } - - } - - - public static String createForSpecialCase(java.lang.Class clazz){ - if (clazz.isArray()){ - return createSequenceRepID(clazz); - } - else { - return (String)kSpecialCasesRepIDs.get(clazz); - } - } - - public static String createForSpecialCase(java.io.Serializable ser){ - Class clazz = ser.getClass(); - if (clazz.isArray()){ - return createSequenceRepID(ser); - } - else - return createForSpecialCase(clazz); - } - - /** - * Creates a repository ID for a normal Java Type. - * @param ser The Java object to create a repository ID for - * @exception com.sun.corba.se.impl.io.TypeMismatchException if ser implements the - * org.omg.CORBA.portable.IDLEntity interface which indicates it is an IDL Value type. - **/ - public static String createForJavaType(java.io.Serializable ser) - throws com.sun.corba.se.impl.io.TypeMismatchException - { - synchronized (classToRepStr) { - String repid = createForSpecialCase(ser); - if (repid != null) - return repid; - Class clazz = ser.getClass(); - repid = (String)classToRepStr.get(clazz); - - if (repid != null) - return repid; - - repid = kValuePrefix + convertToISOLatin1(clazz.getName()) + - createHashString(clazz); - - classToRepStr.put(clazz, repid); - repStrToClass.put(repid, clazz); - return repid; - } - } - - /** - * Creates a repository ID for a normal Java Type. - * @param clz The Java class to create a repository ID for - * @exception com.sun.corba.se.impl.io.TypeMismatchException if ser implements the - * org.omg.CORBA.portable.IDLEntity interface which indicates it is an IDL Value type. - **/ - public static String createForJavaType(Class clz) - throws com.sun.corba.se.impl.io.TypeMismatchException - { - synchronized (classToRepStr){ - String repid = createForSpecialCase(clz); - if (repid != null) - return repid; - - repid = (String)classToRepStr.get(clz); - if (repid != null) - return repid; - - repid = kValuePrefix + convertToISOLatin1(clz.getName()) + - createHashString(clz); - - classToRepStr.put(clz, repid); - repStrToClass.put(repid, clz); - return repid; - } - } - - /** - * Creates a repository ID for an IDL Java Type. - * @param ser The IDL Value object to create a repository ID for - * @param major The major version number - * @param minor The minor version number - * @exception com.sun.corba.se.impl.io.TypeMismatchException if ser does not implement the - * org.omg.CORBA.portable.IDLEntity interface which indicates it is an IDL Value type. - **/ - public static String createForIDLType(Class ser, int major, int minor) - throws com.sun.corba.se.impl.io.TypeMismatchException - { - synchronized (classIDLToRepStr){ - String repid = (String)classIDLToRepStr.get(ser); - if (repid != null) - return repid; - - repid = kIDLPrefix + convertToISOLatin1(ser.getName()).replace('.','/') + - ":" + major + "." + minor; - classIDLToRepStr.put(ser, repid); - return repid; - } - } - - private static String getIdFromHelper(Class clazz){ - try { - Class helperClazz = Utility.loadClassForClass(clazz.getName()+"Helper", null, - clazz.getClassLoader(), clazz, clazz.getClassLoader()); - Method idMethod = helperClazz.getDeclaredMethod("id", kNoParamTypes); - return (String)idMethod.invoke(null, kNoArgs); - } - catch(java.lang.ClassNotFoundException cnfe) - { - throw new org.omg.CORBA.MARSHAL(cnfe.toString()); - } - catch(java.lang.NoSuchMethodException nsme) - { - throw new org.omg.CORBA.MARSHAL(nsme.toString()); - } - catch(java.lang.reflect.InvocationTargetException ite) - { - throw new org.omg.CORBA.MARSHAL(ite.toString()); - } - catch(java.lang.IllegalAccessException iae) - { - throw new org.omg.CORBA.MARSHAL(iae.toString()); - } - } - - /** - * Createa a repository ID for the type if it is either a java type - * or an IDL type. - * @param type The type to create rep. id for - * @return The rep. id. - **/ - public static String createForAnyType(Class type) { - try{ - if (type.isArray()) - return createSequenceRepID(type); - else if (IDLEntity.class.isAssignableFrom(type)) - { - try{ - return getIdFromHelper(type); - } - catch(Throwable t) { - return createForIDLType(type, 1, 0); - } - } - else return createForJavaType(type); - } - catch(com.sun.corba.se.impl.io.TypeMismatchException e){ - return null; - } - - } - - public static boolean isAbstractBase(Class clazz) { - return (clazz.isInterface() && - IDLEntity.class.isAssignableFrom(clazz) && - (!ValueBase.class.isAssignableFrom(clazz)) && - (!org.omg.CORBA.Object.class.isAssignableFrom(clazz))); - - } - - /** - * Convert strings with illegal IDL identifier characters. - *

- * Section 5.5.7 of OBV spec. - */ - private static String convertToISOLatin1 (String name) { - - int length = name.length(); - if (length == 0) { - return name; - } - StringBuffer buffer = null; - - for (int i = 0; i < length; i++) { - - char c = name.charAt(i); - - if (c > 255 || IDL_IDENTIFIER_CHARS[c] == 0) { - - // We gotta convert. Have we already started? - - if (buffer == null) { - - // No, so get set up... - - buffer = new StringBuffer(name.substring(0,i)); - } - - // Convert the character into the IDL escape syntax... - buffer.append( - "\\U" + - (char)ASCII_HEX[(c & 0xF000) >>> 12] + - (char)ASCII_HEX[(c & 0x0F00) >>> 8] + - (char)ASCII_HEX[(c & 0x00F0) >>> 4] + - (char)ASCII_HEX[(c & 0x000F)]); - - } else { - if (buffer != null) { - buffer.append(c); - } - } - } - - if (buffer != null) { - name = buffer.toString(); - } - - return name; - } - - /** - * Convert strings with ISO Latin 1 escape sequences back to original strings. - *

- * Section 5.5.7 of OBV spec. - */ - private static String convertFromISOLatin1 (String name) { - - int index = -1; - StringBuffer buf = new StringBuffer(name); - - while ((index = buf.toString().indexOf("\\U")) != -1){ - String str = "0000" + buf.toString().substring(index+2, index+6); - - // Convert Hexadecimal - byte[] buffer = new byte[(str.length() - 4) / 2]; - for (int i=4, j=0; i < str.length(); i +=2, j++) { - buffer[j] = (byte)((ORBUtility.hexOf(str.charAt(i)) << 4) & 0xF0); - buffer[j] |= (byte)((ORBUtility.hexOf(str.charAt(i+1)) << 0) & 0x0F); - } - buf = new StringBuffer(delete(buf.toString(), index, index+6)); - buf.insert(index, (char)buffer[1]); - } - - return buf.toString(); - - - } - - private static String delete(String str, int from, int to) - { - return str.substring(0, from) + str.substring(to, str.length()); - } - - private static String replace(String target, String arg, String source) - { - int i = 0; - i = target.indexOf(arg); - - while(i != -1) - { - String left = target.substring(0, i); - String right = target.substring(i+arg.length()); - target = new String(left+source+right); - i = target.indexOf(arg); - } - return target; - } - - /* - * Load a class and check that it is assignable to a given type. - * @param className the class name. - * @param remoteCodebase the codebase to use. May be null. - * @param loader the class loader of last resort. May be null. - * @param expectedType the expected type. May be null. - * @return the loaded class. - */ - private Class loadClassOfType (String className, - String remoteCodebase, - ClassLoader loader, - Class expectedType, - ClassLoader expectedTypeClassLoader) - throws ClassNotFoundException { - - Class loadedClass = null; - - try { - //Sequence finding of the stubs according to spec - try{ - //If-else is put here for speed up of J2EE. - //According to the OMG spec, the if clause is not dead code. - //It can occur if some compiler has allowed generation - //into org.omg.stub hierarchy for non-offending - //classes. This will encourage people to - //produce non-offending class stubs in their own hierarchy. - if(!PackagePrefixChecker - .hasOffendingPrefix(PackagePrefixChecker - .withoutPackagePrefix(className))){ - loadedClass = Util.loadClass - (PackagePrefixChecker.withoutPackagePrefix(className), - remoteCodebase, - loader); - } else { - loadedClass = Util.loadClass - (className, - remoteCodebase, - loader); - } - } catch (ClassNotFoundException cnfe) { - loadedClass = Util.loadClass - (className, - remoteCodebase, - loader); - } - if (expectedType == null) - return loadedClass; - } catch (ClassNotFoundException cnfe) { - if (expectedType == null) - throw cnfe; - } - - // If no class was not loaded, or if the loaded class is not of the - // correct type, make a further attempt to load the correct class - // using the classloader of the expected type. - // _REVISIT_ Is this step necessary, or should the Util,loadClass - // algorithm always produce a valid class if the setup is correct? - // Does the OMG standard algorithm need to be changed to include - // this step? - if (loadedClass == null || !expectedType.isAssignableFrom(loadedClass)) { - if (expectedType.getClassLoader() != expectedTypeClassLoader) - throw new IllegalArgumentException("expectedTypeClassLoader not class loader of expectedType."); - - if (expectedTypeClassLoader != null) - loadedClass = expectedTypeClassLoader.loadClass(className); - else - loadedClass = ORBClassLoader.loadClass(className); - } - - return loadedClass; - } - - /** - * Checks to see if the FullValueDescription should be retrieved. - * @exception Throws IOException if suids do not match or if the repositoryID - * is not an RMIValueType - */ - public static boolean useFullValueDescription(Class clazz, String repositoryID) - throws IOException{ - - String clazzRepIDStr = createForAnyType(clazz); - - if (clazzRepIDStr.equals(repositoryID)) - return false; - - RepositoryId_1_3 targetRepid; - RepositoryId_1_3 clazzRepid; - - synchronized(cache) { - // to avoid race condition where multiple threads could be - // accessing this method, and their access to the cache may - // be interleaved giving unexpected results - - targetRepid = cache.getId(repositoryID); - clazzRepid = cache.getId(clazzRepIDStr); - } - - if ((targetRepid.isRMIValueType()) && (clazzRepid.isRMIValueType())){ - if (!targetRepid.getSerialVersionUID().equals(clazzRepid.getSerialVersionUID())) { - - String mssg = "Mismatched serialization UIDs : Source (Rep. ID" + - clazzRepid + ") = " + - clazzRepid.getSerialVersionUID() + " whereas Target (Rep. ID " + repositoryID + - ") = " + targetRepid.getSerialVersionUID(); - throw new IOException(mssg); - } else { - return true; - } - } else { - - throw new IOException("The repository ID is not of an RMI value type (Expected ID = " + clazzRepIDStr + "; Received ID = " + repositoryID +")"); - } - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryId_1_3_1.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryId_1_3_1.java deleted file mode 100644 index 8c1ab6e7390..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/RepositoryId_1_3_1.java +++ /dev/null @@ -1,1065 +0,0 @@ -/* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - */ -package com.sun.corba.se.impl.orbutil; - -import java.util.StringTokenizer; -import java.util.Hashtable; -import java.io.IOException; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import org.omg.CORBA.portable.ValueBase; -import org.omg.CORBA.portable.IDLEntity; - -//d11638 files in the same package, therefore remove their reference -//import com.sun.corba.se.impl.util.JDKBridge; -//import com.sun.corba.se.impl.util.IdentityHashtable; -import com.sun.corba.se.impl.util.JDKBridge; -import com.sun.corba.se.impl.util.Utility; -import com.sun.corba.se.impl.util.PackagePrefixChecker; -import com.sun.corba.se.impl.util.IdentityHashtable; - -import javax.rmi.CORBA.Util; - -/** - * Because all methods in RepositoryId are static, we have - * to duplicate all of this code, freezing it in its 1.3.1 - * form for backwards compatibility. - * - * For security reasons, we can't expose enough of - * io/ObjectStreamClass, so it has to be duplicated in - * orbutil. - */ -public class RepositoryId_1_3_1 { - - // Legal IDL Identifier characters (1 = legal). Note - // that '.' (2E) is marked as legal even though it is - // not legal in IDL. This allows us to treat a fully - // qualified Java name with '.' package separators - // uniformly, and is safe because that is the only - // legal use of '.' in a Java name. - - private static final byte[] IDL_IDENTIFIER_CHARS = { - - // 0 1 2 3 4 5 6 7 8 9 a b c d e f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 00-0f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 10-1f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,1,0, // 20-2f - 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0, // 30-3f - 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // 40-4f - 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1, // 50-5f - 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // 60-6f - 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0, // 70-7f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 80-8f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 90-9f - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // a0-af - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // b0-bf - 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // c0-cf - 0,1,1,1, 1,1,1,0, 1,1,1,1, 1,0,0,1, // d0-df - 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // e0-ef - 0,1,1,1, 1,1,1,0, 1,1,1,1, 1,0,0,1, // f0-ff - }; - - - private static final long serialVersionUID = 123456789L; - - private static String defaultServerURL = null; - private static boolean useCodebaseOnly = false; - - static { - if (defaultServerURL == null) - defaultServerURL = (String)JDKBridge.getLocalCodebase(); - useCodebaseOnly = JDKBridge.useCodebaseOnly(); - - } - - private static IdentityHashtable classToRepStr = new IdentityHashtable(); - private static IdentityHashtable classIDLToRepStr = new IdentityHashtable(); - private static IdentityHashtable classSeqToRepStr = new IdentityHashtable(); - - private static IdentityHashtable repStrToByteArray = new IdentityHashtable(); - private static Hashtable repStrToClass = new Hashtable(); - - private String repId = null; - private boolean isSupportedFormat = true; - private String typeString = null; - private String versionString = null; - private boolean isSequence = false; - private boolean isRMIValueType = false; - private boolean isIDLType = false; - private String completeClassName = null; - private String unqualifiedName = null; - private String definedInId = null; - private Class clazz = null; - private String suid = null, actualSuid = null; - private long suidLong = ObjectStreamClass_1_3_1.kDefaultUID, actualSuidLong = ObjectStreamClass_1_3_1.kDefaultUID; - - // Repository ID fragments - private static final String kSequenceKeyword = "seq"; - private static final String kValuePrefix = "RMI:"; - private static final String kIDLPrefix = "IDL:"; - private static final String kIDLNamePrefix = "omg.org/"; - private static final String kIDLClassnamePrefix = "org.omg."; - private static final String kSequencePrefix = "["; - private static final String kCORBAPrefix = "CORBA/"; - private static final String kArrayPrefix = kValuePrefix + kSequencePrefix + kCORBAPrefix; - private static final int kValuePrefixLength = kValuePrefix.length(); - private static final int kIDLPrefixLength = kIDLPrefix.length(); - private static final int kSequencePrefixLength = kSequencePrefix.length(); - private static final String kInterfaceHashCode = ":0000000000000000"; - private static final String kInterfaceOnlyHashStr = "0000000000000000"; - private static final String kExternalizableHashStr = "0000000000000001"; - - // Value tag utility methods and constants - public static final int kInitialValueTag= 0x7fffff00; - public static final int kNoTypeInfo = 0; - public static final int kSingleRepTypeInfo = 0x02; - public static final int kPartialListTypeInfo = 0x06; - public static final int kChunkedMask = 0x08; - public static final int kPreComputed_StandardRMIUnchunked = RepositoryId_1_3_1.computeValueTag(false, RepositoryId_1_3_1.kSingleRepTypeInfo, false); - public static final int kPreComputed_CodeBaseRMIUnchunked = RepositoryId_1_3_1.computeValueTag(true, RepositoryId_1_3_1.kSingleRepTypeInfo, false); - public static final int kPreComputed_StandardRMIChunked = RepositoryId_1_3_1.computeValueTag(false, RepositoryId_1_3_1.kSingleRepTypeInfo, true); - public static final int kPreComputed_CodeBaseRMIChunked = RepositoryId_1_3_1.computeValueTag(true, RepositoryId_1_3_1.kSingleRepTypeInfo, true); - - public static final int kPreComputed_StandardRMIUnchunked_NoRep = RepositoryId_1_3_1.computeValueTag(false, RepositoryId_1_3_1.kNoTypeInfo, false); - public static final int kPreComputed_CodeBaseRMIUnchunked_NoRep = RepositoryId_1_3_1.computeValueTag(true, RepositoryId_1_3_1.kNoTypeInfo, false); - public static final int kPreComputed_StandardRMIChunked_NoRep = RepositoryId_1_3_1.computeValueTag(false, RepositoryId_1_3_1.kNoTypeInfo, true); - public static final int kPreComputed_CodeBaseRMIChunked_NoRep = RepositoryId_1_3_1.computeValueTag(true, RepositoryId_1_3_1.kNoTypeInfo, true); - - // Public, well known repository IDs - - // _REVISIT_ : A table structure with a good search routine for all of this - // would be more efficient and easier to maintain... - - // String - public static final String kWStringValueVersion = "1.0"; - public static final String kWStringValueHash = ":"+kWStringValueVersion; - public static final String kWStringStubValue = "WStringValue"; - public static final String kWStringTypeStr = "omg.org/CORBA/"+kWStringStubValue; - public static final String kWStringValueRepID = kIDLPrefix + kWStringTypeStr + kWStringValueHash; - - // Any - public static final String kAnyRepID = kIDLPrefix + "omg.org/CORBA/Any"; - - // Class - // Anita4: convert to uppercase - public static final String kClassDescValueHash = ":" + - Long.toHexString( - ObjectStreamClass_1_3_1.getActualSerialVersionUID(javax.rmi.CORBA.ClassDesc.class)).toUpperCase() + ":" + - Long.toHexString( - ObjectStreamClass_1_3_1.getSerialVersionUID(javax.rmi.CORBA.ClassDesc.class)).toUpperCase(); - public static final String kClassDescStubValue = "ClassDesc"; - public static final String kClassDescTypeStr = "javax.rmi.CORBA."+kClassDescStubValue; - public static final String kClassDescValueRepID = kValuePrefix + kClassDescTypeStr + kClassDescValueHash; - - // Object - public static final String kObjectValueHash = ":1.0"; - public static final String kObjectStubValue = "Object"; - - // Sequence - public static final String kSequenceValueHash = ":1.0"; - public static final String kPrimitiveSequenceValueHash = ":0000000000000000"; - - // Serializable - public static final String kSerializableValueHash = ":1.0"; - public static final String kSerializableStubValue = "Serializable"; - - // Externalizable - public static final String kExternalizableValueHash = ":1.0"; - public static final String kExternalizableStubValue = "Externalizable"; - - // Remote (The empty string is used for java.rmi.Remote) - public static final String kRemoteValueHash = ""; - public static final String kRemoteStubValue = ""; - public static final String kRemoteTypeStr = ""; - public static final String kRemoteValueRepID = ""; - - private static final Hashtable kSpecialArrayTypeStrings = new Hashtable(); - - static { - kSpecialArrayTypeStrings.put("CORBA.WStringValue", new StringBuffer(java.lang.String.class.getName())); - kSpecialArrayTypeStrings.put("javax.rmi.CORBA.ClassDesc", new StringBuffer(java.lang.Class.class.getName())); - kSpecialArrayTypeStrings.put("CORBA.Object", new StringBuffer(java.rmi.Remote.class.getName())); - - } - - private static final Hashtable kSpecialCasesRepIDs = new Hashtable(); - - static { - kSpecialCasesRepIDs.put(java.lang.String.class, kWStringValueRepID); - kSpecialCasesRepIDs.put(java.lang.Class.class, kClassDescValueRepID); - kSpecialCasesRepIDs.put(java.rmi.Remote.class, kRemoteValueRepID); - } - - private static final Hashtable kSpecialCasesStubValues = new Hashtable(); - - static { - kSpecialCasesStubValues.put(java.lang.String.class, kWStringStubValue); - kSpecialCasesStubValues.put(java.lang.Class.class, kClassDescStubValue); - kSpecialCasesStubValues.put(java.lang.Object.class, kObjectStubValue); - kSpecialCasesStubValues.put(java.io.Serializable.class, kSerializableStubValue); - kSpecialCasesStubValues.put(java.io.Externalizable.class, kExternalizableStubValue); - kSpecialCasesStubValues.put(java.rmi.Remote.class, kRemoteStubValue); - } - - - private static final Hashtable kSpecialCasesVersions = new Hashtable(); - - static { - kSpecialCasesVersions.put(java.lang.String.class, kWStringValueHash); - kSpecialCasesVersions.put(java.lang.Class.class, kClassDescValueHash); - kSpecialCasesVersions.put(java.lang.Object.class, kObjectValueHash); - kSpecialCasesVersions.put(java.io.Serializable.class, kSerializableValueHash); - kSpecialCasesVersions.put(java.io.Externalizable.class, kExternalizableValueHash); - kSpecialCasesVersions.put(java.rmi.Remote.class, kRemoteValueHash); - } - - private static final Hashtable kSpecialCasesClasses = new Hashtable(); - - static { - kSpecialCasesClasses.put(kWStringTypeStr, java.lang.String.class); - kSpecialCasesClasses.put(kClassDescTypeStr, java.lang.Class.class); - kSpecialCasesClasses.put(kRemoteTypeStr, java.rmi.Remote.class); - - kSpecialCasesClasses.put("org.omg.CORBA.WStringValue", java.lang.String.class); - kSpecialCasesClasses.put("javax.rmi.CORBA.ClassDesc", java.lang.Class.class); - //kSpecialCasesClasses.put(kRemoteTypeStr, java.rmi.Remote.class); - } - - private static final Hashtable kSpecialCasesArrayPrefix = new Hashtable(); - - static { - kSpecialCasesArrayPrefix.put(java.lang.String.class, kValuePrefix + kSequencePrefix + kCORBAPrefix); - kSpecialCasesArrayPrefix.put(java.lang.Class.class, kValuePrefix + kSequencePrefix + "javax/rmi/CORBA/"); - kSpecialCasesArrayPrefix.put(java.lang.Object.class, kValuePrefix + kSequencePrefix + "java/lang/"); - kSpecialCasesArrayPrefix.put(java.io.Serializable.class, kValuePrefix + kSequencePrefix + "java/io/"); - kSpecialCasesArrayPrefix.put(java.io.Externalizable.class, kValuePrefix + kSequencePrefix + "java/io/"); - kSpecialCasesArrayPrefix.put(java.rmi.Remote.class, kValuePrefix + kSequencePrefix + kCORBAPrefix); - } - - private static final Hashtable kSpecialPrimitives = new Hashtable(); - - static { - kSpecialPrimitives.put("int","long"); - kSpecialPrimitives.put("long","longlong"); - kSpecialPrimitives.put("byte","octet"); - } - - /** - * Used to convert ascii to hex. - */ - private static final byte ASCII_HEX[] = { - (byte)'0', - (byte)'1', - (byte)'2', - (byte)'3', - (byte)'4', - (byte)'5', - (byte)'6', - (byte)'7', - (byte)'8', - (byte)'9', - (byte)'A', - (byte)'B', - (byte)'C', - (byte)'D', - (byte)'E', - (byte)'F', - }; - - - // bug fix for 4328952; to eliminate possibility of overriding this - // in a subclass. - public static final RepositoryIdCache_1_3_1 cache = new RepositoryIdCache_1_3_1(); - - // Interface Rep ID Strings - public static final String kjava_rmi_Remote = createForAnyType(java.rmi.Remote.class); - public static final String korg_omg_CORBA_Object = createForAnyType(org.omg.CORBA.Object.class); - - // Dummy arguments for getIdFromHelper method - public static final Class kNoParamTypes[] ={}; - public static final Object kNoArgs[] = {}; - - - // To create a RepositoryID, use code similar to the following: - // RepositoryId.cache.getId( id ); - - RepositoryId_1_3_1(){} - - RepositoryId_1_3_1(String aRepId){ - init(aRepId); - } - - RepositoryId_1_3_1 init(String aRepId){ - - this.repId = aRepId; - - // Special case for remote - if (aRepId.length() == 0) { - clazz = java.rmi.Remote.class; - typeString = ""; - isRMIValueType = true; - suid = kInterfaceOnlyHashStr; - return this; - } - else if (aRepId.equals(kWStringValueRepID)) { - clazz = java.lang.String.class; - typeString = kWStringTypeStr; - isIDLType = true; - // fix where Attempting to obtain a FullValueDescription - // for an RMI value type with a String field causes an exception. - completeClassName = "java.lang.String"; - versionString = kWStringValueVersion; - return this; - } - else { - - String repId = convertFromISOLatin1(aRepId); - - versionString = repId.substring(repId.indexOf(':', repId.indexOf(':')+1)); - if (repId.startsWith(kIDLPrefix)) { - typeString = - repId.substring(kIDLPrefixLength, repId.indexOf(':', kIDLPrefixLength)); - isIDLType = true; - if (typeString.startsWith(kIDLNamePrefix)) - completeClassName = kIDLClassnamePrefix + - typeString.substring(kIDLNamePrefix.length()).replace('/','.'); - else completeClassName = typeString.replace('/','.'); - - } - else if (repId.startsWith(kValuePrefix)) { - typeString = - repId.substring(kValuePrefixLength, repId.indexOf(':', kValuePrefixLength)); - isRMIValueType = true; - - if (versionString.indexOf('.') == -1) { - actualSuid = versionString.substring(1); - suid = actualSuid; // default if not explicitly specified - - if (actualSuid.indexOf(':') != -1){ - // we have a declared hash also - int pos = actualSuid.indexOf(':')+1; - // actualSuid = suid.substring(pos); - // suid = suid.substring(0, pos-1); - suid = actualSuid.substring(pos); - actualSuid = actualSuid.substring(0, pos-1); - } - - } - else { - // _REVISIT_ : Special case version failure ? - } - } - else isSupportedFormat = false; - - if (typeString.startsWith(kSequencePrefix)) { - isSequence = true; - } - - - return this; - } - } - - public final String getUnqualifiedName() { - if (unqualifiedName == null){ - String className = getClassName(); - int index = className.lastIndexOf('.'); - if (index == -1){ - unqualifiedName = className; - definedInId = "IDL::1.0"; - } - else { - unqualifiedName = className.substring(index); - definedInId = "IDL:" + className.substring(0, index).replace('.','/') + ":1.0"; - } - } - - return unqualifiedName; - } - - public final String getDefinedInId() { - if (definedInId == null){ - getUnqualifiedName(); - } - - return definedInId; - } - - public final String getTypeString() { - return typeString; - } - - public final String getVersionString() { - return versionString; - } - - public final String getSerialVersionUID() { - return suid; - } - - public final String getActualSerialVersionUID() { - return actualSuid; - } - public final long getSerialVersionUIDAsLong() { - return suidLong; - } - - public final long getActualSerialVersionUIDAsLong() { - return actualSuidLong; - } - - public final boolean isRMIValueType() { - return isRMIValueType; - } - - public final boolean isIDLType() { - return isIDLType; - } - - public final String getRepositoryId() { - return repId; - } - - public static byte[] getByteArray(String repStr) { - synchronized (repStrToByteArray){ - return (byte[]) repStrToByteArray.get(repStr); - } - } - - public static void setByteArray(String repStr, byte[] repStrBytes) { - synchronized (repStrToByteArray){ - repStrToByteArray.put(repStr, repStrBytes); - } - } - - public final boolean isSequence() { - return isSequence; - } - - public final boolean isSupportedFormat() { - return isSupportedFormat; - } - - - // This method will return the classname from the typestring OR if the classname turns out to be - // a special class "pseudo" name, then the matching real classname is returned. - public final String getClassName() { - - if (isRMIValueType) - return typeString; - else if (isIDLType) - return completeClassName; - else return null; - - } - - // This method calls getClazzFromType() and falls back to the repStrToClass - // cache if no class was found. It's used where any class matching the - // given repid is an acceptable result. - public final Class getAnyClassFromType() throws ClassNotFoundException { - try { - return getClassFromType(); - } catch (ClassNotFoundException cnfe) { - Class clz = (Class)repStrToClass.get(repId); - if (clz != null) - return clz; - else - throw cnfe; - } - } - - public final Class getClassFromType() - throws ClassNotFoundException { - if (clazz != null) - return clazz; - - Class specialCase = (Class)kSpecialCasesClasses.get(getClassName()); - - if (specialCase != null){ - clazz = specialCase; - return specialCase; - } - else - { - try{ - return Util.loadClass(getClassName(), null, null); - } - catch(ClassNotFoundException cnfe){ - if (defaultServerURL != null) { - try{ - return getClassFromType(defaultServerURL); - } - catch(MalformedURLException mue){ - throw cnfe; - } - } - else throw cnfe; - } - } - - } - - public final Class getClassFromType(Class expectedType, String codebase) - throws ClassNotFoundException { - if (clazz != null) - return clazz; - - Class specialCase = (Class)kSpecialCasesClasses.get(getClassName()); - - if (specialCase != null){ - clazz = specialCase; - return specialCase; - } else { - ClassLoader expectedTypeClassLoader = (expectedType == null ? null : expectedType.getClassLoader()); - return loadClassOfType(getClassName(), - codebase, - expectedTypeClassLoader, - expectedType, - expectedTypeClassLoader); - } - - } - - public final Class getClassFromType(String url) - throws ClassNotFoundException, MalformedURLException { - return Util.loadClass(getClassName(), url, null); - } - - public final String toString() { - return repId; - } - - /** - * Checks to see if the FullValueDescription should be retrieved. - * @exception Throws IOException if suids do not match or if the repositoryID - * is not an RMIValueType - */ - public static boolean useFullValueDescription(Class clazz, String repositoryID) - throws IOException{ - - String clazzRepIDStr = createForAnyType(clazz); - - if (clazzRepIDStr.equals(repositoryID)) - return false; - - RepositoryId_1_3_1 targetRepid; - RepositoryId_1_3_1 clazzRepid; - - synchronized(cache) { - // to avoid race condition where multiple threads could be - // accessing this method, and their access to the cache may - // be interleaved giving unexpected results - - targetRepid = cache.getId(repositoryID); - clazzRepid = cache.getId(clazzRepIDStr); - } - //ObjectStreamClass osc = ObjectStreamClass.lookup(clazz); - - if ((targetRepid.isRMIValueType()) && (clazzRepid.isRMIValueType())){ - if (!targetRepid.getSerialVersionUID().equals(clazzRepid.getSerialVersionUID())) { - - String mssg = "Mismatched serialization UIDs : Source (Rep. ID" + - clazzRepid + ") = " + - clazzRepid.getSerialVersionUID() + " whereas Target (Rep. ID " + repositoryID + - ") = " + targetRepid.getSerialVersionUID(); - //com.sun.corba.se.impl.io.ValueUtility.log("RepositoryId",mssg); - throw new IOException(mssg); - } - else { - return true; - } - } - else { - - throw new IOException("The repository ID is not of an RMI value type (Expected ID = " + clazzRepIDStr + "; Received ID = " + repositoryID +")"); - } - } - - private static String createHashString(java.io.Serializable ser) { - - return createHashString(ser.getClass()); - } - - private static String createHashString(java.lang.Class clazz) { - - if (clazz.isInterface() || !java.io.Serializable.class.isAssignableFrom(clazz)) - return kInterfaceHashCode; - - //ObjectStreamClass osc = ObjectStreamClass.lookup(clazz); - - long actualLong = ObjectStreamClass_1_3_1.getActualSerialVersionUID(clazz); - String hash = null; - if (actualLong == 0) - hash = kInterfaceOnlyHashStr; - else if (actualLong == 1) - hash = kExternalizableHashStr; - else - hash = Long.toHexString(actualLong).toUpperCase(); - while(hash.length() < 16){ - hash = "0" + hash; - } - - long declaredLong = ObjectStreamClass_1_3_1.getSerialVersionUID(clazz); - String declared = null; - if (declaredLong == 0) - declared = kInterfaceOnlyHashStr; - else if (declaredLong == 1) - declared = kExternalizableHashStr; - else - declared = Long.toHexString(declaredLong).toUpperCase(); - while (declared.length() < 16){ - declared = "0" + declared; - } - hash = hash + ":" + declared; - - return ":" + hash; - } - - /** - * Creates a repository ID for a sequence. This is for expert users only as - * this method assumes the object passed is an array. If passed an object - * that is not an array, it will produce a rep id for a sequence of zero - * length. This would be an error. - * @param ser The Java object to create a repository ID for - **/ - public static String createSequenceRepID(java.lang.Object ser){ - return createSequenceRepID(ser.getClass()); - } - - /** - * Creates a repository ID for a sequence. This is for expert users only as - * this method assumes the object passed is an array. If passed an object - * that is not an array, it will produce a malformed rep id. - * @param clazz The Java class to create a repository ID for - **/ - public static String createSequenceRepID(java.lang.Class clazz){ - synchronized (classSeqToRepStr){ - - String repid = (String)classSeqToRepStr.get(clazz); - if (repid != null) - return repid; - - Class originalClazz = clazz; - - Class type = null; - int numOfDims = 0; - - while ((type = clazz.getComponentType()) != null) { - numOfDims++; - clazz = type; - } - - if (clazz.isPrimitive()) - repid = kValuePrefix + originalClazz.getName() + kPrimitiveSequenceValueHash; - else { - StringBuffer buf = new StringBuffer(); - buf.append(kValuePrefix); - while(numOfDims-- > 0) { - buf.append("["); - } - buf.append("L"); - buf.append(convertToISOLatin1(clazz.getName())); - buf.append(";"); - buf.append(createHashString(clazz)); - repid = buf.toString(); - } - classSeqToRepStr.put(originalClazz,repid); - return repid; - } - - } - - - public static String createForSpecialCase(java.lang.Class clazz){ - if (clazz.isArray()){ - return createSequenceRepID(clazz); - } - else { - return (String)kSpecialCasesRepIDs.get(clazz); - } - } - - public static String createForSpecialCase(java.io.Serializable ser){ - Class clazz = ser.getClass(); - if (clazz.isArray()){ - return createSequenceRepID(ser); - } - else - return createForSpecialCase(clazz); - } - - /** - * Creates a repository ID for a normal Java Type. - * @param ser The Java object to create a repository ID for - * @exception com.sun.corba.se.impl.io.TypeMismatchException if ser implements the - * org.omg.CORBA.portable.IDLEntity interface which indicates it is an IDL Value type. - **/ - public static String createForJavaType(java.io.Serializable ser) - throws com.sun.corba.se.impl.io.TypeMismatchException - { - synchronized (classToRepStr) { - String repid = createForSpecialCase(ser); - if (repid != null) - return repid; - Class clazz = ser.getClass(); - repid = (String)classToRepStr.get(clazz); - - if (repid != null) - return repid; - - repid = kValuePrefix + convertToISOLatin1(clazz.getName()) + - createHashString(clazz); - - classToRepStr.put(clazz, repid); - repStrToClass.put(repid, clazz); - return repid; - } - } - - /** - * Creates a repository ID for a normal Java Type. - * @param clz The Java class to create a repository ID for - * @exception com.sun.corba.se.impl.io.TypeMismatchException if ser implements the - * org.omg.CORBA.portable.IDLEntity interface which indicates it is an IDL Value type. - **/ - public static String createForJavaType(Class clz) - throws com.sun.corba.se.impl.io.TypeMismatchException - { - synchronized (classToRepStr){ - String repid = createForSpecialCase(clz); - if (repid != null) - return repid; - - repid = (String)classToRepStr.get(clz); - if (repid != null) - return repid; - - repid = kValuePrefix + convertToISOLatin1(clz.getName()) + - createHashString(clz); - - classToRepStr.put(clz, repid); - repStrToClass.put(repid, clz); - return repid; - } - } - - /** - * Creates a repository ID for an IDL Java Type. - * @param ser The IDL Value object to create a repository ID for - * @param major The major version number - * @param minor The minor version number - * @exception com.sun.corba.se.impl.io.TypeMismatchException if ser does not implement the - * org.omg.CORBA.portable.IDLEntity interface which indicates it is an IDL Value type. - **/ - public static String createForIDLType(Class ser, int major, int minor) - throws com.sun.corba.se.impl.io.TypeMismatchException - { - synchronized (classIDLToRepStr){ - String repid = (String)classIDLToRepStr.get(ser); - if (repid != null) - return repid; - - repid = kIDLPrefix + convertToISOLatin1(ser.getName()).replace('.','/') + - ":" + major + "." + minor; - classIDLToRepStr.put(ser, repid); - return repid; - } - } - - private static String getIdFromHelper(Class clazz){ - try { - Class helperClazz = Utility.loadClassForClass(clazz.getName()+"Helper", null, - clazz.getClassLoader(), clazz, clazz.getClassLoader()); - Method idMethod = helperClazz.getDeclaredMethod("id", kNoParamTypes); - return (String)idMethod.invoke(null, kNoArgs); - } - catch(java.lang.ClassNotFoundException cnfe) - { - throw new org.omg.CORBA.MARSHAL(cnfe.toString()); - } - catch(java.lang.NoSuchMethodException nsme) - { - throw new org.omg.CORBA.MARSHAL(nsme.toString()); - } - catch(java.lang.reflect.InvocationTargetException ite) - { - throw new org.omg.CORBA.MARSHAL(ite.toString()); - } - catch(java.lang.IllegalAccessException iae) - { - throw new org.omg.CORBA.MARSHAL(iae.toString()); - } - } - - /** - * Createa a repository ID for the type if it is either a java type - * or an IDL type. - * @param type The type to create rep. id for - * @return The rep. id. - **/ - public static String createForAnyType(Class type) { - try{ - if (type.isArray()) - return createSequenceRepID(type); - else if (IDLEntity.class.isAssignableFrom(type)) - { - try{ - return getIdFromHelper(type); - } - catch(Throwable t) { - return createForIDLType(type, 1, 0); - } - } - else return createForJavaType(type); - } - catch(com.sun.corba.se.impl.io.TypeMismatchException e){ - return null; - } - - } - - public static boolean isAbstractBase(Class clazz) { - return (clazz.isInterface() && - IDLEntity.class.isAssignableFrom(clazz) && - (!ValueBase.class.isAssignableFrom(clazz)) && - (!org.omg.CORBA.Object.class.isAssignableFrom(clazz))); - - } - - public static boolean isAnyRequired(Class clazz) { - return ((clazz == java.lang.Object.class) || - (clazz == java.io.Serializable.class) || - (clazz == java.io.Externalizable.class)); - } - - public static long fromHex(String hexNumber) { - if (hexNumber.startsWith("0x")) - return Long.valueOf(hexNumber.substring(2), 16).longValue(); - else return Long.valueOf(hexNumber, 16).longValue(); - } - - /** - * Convert strings with illegal IDL identifier characters. - *

- * Section 5.5.7 of OBV spec. - */ - private static String convertToISOLatin1 (String name) { - - int length = name.length(); - if (length == 0) { - return name; - } - StringBuffer buffer = null; - - for (int i = 0; i < length; i++) { - - char c = name.charAt(i); - - if (c > 255 || IDL_IDENTIFIER_CHARS[c] == 0) { - - // We gotta convert. Have we already started? - - if (buffer == null) { - - // No, so get set up... - - buffer = new StringBuffer(name.substring(0,i)); - } - - // Convert the character into the IDL escape syntax... - buffer.append( - "\\U" + - (char)ASCII_HEX[(c & 0xF000) >>> 12] + - (char)ASCII_HEX[(c & 0x0F00) >>> 8] + - (char)ASCII_HEX[(c & 0x00F0) >>> 4] + - (char)ASCII_HEX[(c & 0x000F)]); - - } else { - if (buffer != null) { - buffer.append(c); - } - } - } - - if (buffer != null) { - name = buffer.toString(); - } - - return name; - } - - /** - * Convert strings with ISO Latin 1 escape sequences back to original strings. - *

- * Section 5.5.7 of OBV spec. - */ - private static String convertFromISOLatin1 (String name) { - - int index = -1; - StringBuffer buf = new StringBuffer(name); - - while ((index = buf.toString().indexOf("\\U")) != -1){ - String str = "0000" + buf.toString().substring(index+2, index+6); - - // Convert Hexadecimal - byte[] buffer = new byte[(str.length() - 4) / 2]; - for (int i=4, j=0; i < str.length(); i +=2, j++) { - buffer[j] = (byte)((ORBUtility.hexOf(str.charAt(i)) << 4) & 0xF0); - buffer[j] |= (byte)((ORBUtility.hexOf(str.charAt(i+1)) << 0) & 0x0F); - } - buf = new StringBuffer(delete(buf.toString(), index, index+6)); - buf.insert(index, (char)buffer[1]); - } - - return buf.toString(); - - - } - - private static String delete(String str, int from, int to) - { - return str.substring(0, from) + str.substring(to, str.length()); - } - - private static String replace(String target, String arg, String source) - { - int i = 0; - i = target.indexOf(arg); - - while(i != -1) - { - String left = target.substring(0, i); - String right = target.substring(i+arg.length()); - target = new String(left+source+right); - i = target.indexOf(arg); - } - return target; - } - - public static int computeValueTag(boolean codeBasePresent, int typeInfo, boolean chunkedEncoding){ - int value_tag = kInitialValueTag; - - if (codeBasePresent) - value_tag = value_tag | 0x00000001; - - value_tag = value_tag | typeInfo; - - if (chunkedEncoding) - value_tag = value_tag | kChunkedMask; - - return value_tag; - } - - public static boolean isCodeBasePresent(int value_tag){ - return ((value_tag & 0x00000001) == 1); - } - - public static int getTypeInfo(int value_tag){ - return (value_tag & 0x00000006); - } - - public static boolean isChunkedEncoding(int value_tag){ - return ((value_tag & kChunkedMask) != 0); - } - - public static String getServerURL(){ - return defaultServerURL; - } - - /* - * Load a class and check that it is assignable to a given type. - * @param className the class name. - * @param remoteCodebase the codebase to use. May be null. - * @param loader the class loader of last resort. May be null. - * @param expectedType the expected type. May be null. - * @return the loaded class. - */ - private Class loadClassOfType (String className, - String remoteCodebase, - ClassLoader loader, - Class expectedType, - ClassLoader expectedTypeClassLoader) - throws ClassNotFoundException { - - Class loadedClass = null; - - try { - //Sequence finding of the stubs according to spec - try{ - //If-else is put here for speed up of J2EE. - //According to the OMG spec, the if clause is not dead code. - //It can occur if some compiler has allowed generation - //into org.omg.stub hierarchy for non-offending - //classes. This will encourage people to - //produce non-offending class stubs in their own hierarchy. - if(!PackagePrefixChecker - .hasOffendingPrefix(PackagePrefixChecker - .withoutPackagePrefix(className))){ - loadedClass = Util.loadClass - (PackagePrefixChecker.withoutPackagePrefix(className), - remoteCodebase, - loader); - } else { - loadedClass = Util.loadClass - (className, - remoteCodebase, - loader); - } - } catch (ClassNotFoundException cnfe) { - loadedClass = Util.loadClass - (className, - remoteCodebase, - loader); - } - if (expectedType == null) - return loadedClass; - } catch (ClassNotFoundException cnfe) { - if (expectedType == null) - throw cnfe; - } - - // If no class was not loaded, or if the loaded class is not of the - // correct type, make a further attempt to load the correct class - // using the classloader of the expected type. - // _REVISIT_ Is this step necessary, or should the Util,loadClass - // algorithm always produce a valid class if the setup is correct? - // Does the OMG standard algorithm need to be changed to include - // this step? - if (loadedClass == null || !expectedType.isAssignableFrom(loadedClass)) { - if (expectedType.getClassLoader() != expectedTypeClassLoader) - throw new IllegalArgumentException("expectedTypeClassLoader not class loader of expectedType."); - - if (expectedTypeClassLoader != null) - loadedClass = expectedTypeClassLoader.loadClass(className); - else - loadedClass = Class.forName(className); - } - - return loadedClass; - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3.java deleted file mode 100644 index 68b53c32c46..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute 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. - */ -/* - * Licensed Materials - Property of IBM - * RMI-IIOP v1.0 - * Copyright IBM Corp. 1998 1999 All Rights Reserved - * - */ - -package com.sun.corba.se.impl.orbutil; - -import javax.rmi.CORBA.Util; -import javax.rmi.PortableRemoteObject; - -import java.util.Hashtable; -import java.util.Stack; -import java.io.IOException; -import java.util.EmptyStackException; - -import com.sun.corba.se.impl.util.Utility; -import com.sun.corba.se.impl.io.IIOPInputStream; -import com.sun.corba.se.impl.io.IIOPOutputStream; -import com.sun.corba.se.impl.util.RepositoryId; -import com.sun.corba.se.impl.util.Utility; - -import org.omg.CORBA.TCKind; -import org.omg.CORBA.MARSHAL; -import org.omg.CORBA.CompletionStatus; -import org.omg.CORBA.portable.IndirectionException; -import com.sun.org.omg.SendingContext.CodeBase; - -import java.security.AccessController; -import java.security.PrivilegedAction; - -/** - * This class overrides behavior of our current ValueHandlerImpl to - * provide backwards compatibility with JDK 1.3.0. - */ -public class ValueHandlerImpl_1_3 extends com.sun.corba.se.impl.io.ValueHandlerImpl { - - public ValueHandlerImpl_1_3(){ - super(); - } - - public ValueHandlerImpl_1_3(boolean isInputStream) { - super(isInputStream); - } - - /** - * Writes the value to the stream using java semantics. - * @param out The stream to write the value to - * @param value The value to be written to the stream - **/ - public void writeValue(org.omg.CORBA.portable.OutputStream _out, java.io.Serializable value) { - super.writeValue(_out, value); - } - - /** - * Reads a value from the stream using java semantics. - * @param in The stream to read the value from - * @param clazz The type of the value to be read in - * @param sender The sending context runtime - **/ - public java.io.Serializable readValue(org.omg.CORBA.portable.InputStream _in, - int offset, - java.lang.Class clazz, - String repositoryID, - org.omg.SendingContext.RunTime _sender) - { - return super.readValue(_in, offset, clazz, repositoryID, _sender); - } - - /** - * Returns the repository ID for the given RMI value Class. - * @param clz The class to return a repository ID for. - * @return the repository ID of the Class. - **/ - public java.lang.String getRMIRepositoryID(java.lang.Class clz) { - return RepositoryId_1_3.createForJavaType(clz); - } - - /** - * Indicates whether the given Class performs custom or - * default marshaling. - * @param clz The class to test for custom marshaling. - * @return True if the class performs custom marshaling, false - * if it does not. - **/ - public boolean isCustomMarshaled(java.lang.Class clz) { - return super.isCustomMarshaled(clz); - } - - /** - * Returns the CodeBase for this ValueHandler. This is used by - * the ORB runtime. The server sends the service context containing - * the IOR for this CodeBase on the first GIOP reply. The clients - * do the same on the first GIOP request. - * @return the SendingContext.CodeBase of this ValueHandler. - **/ - public org.omg.SendingContext.RunTime getRunTimeCodeBase() { - return super.getRunTimeCodeBase(); - } - - /** - * If the value contains a writeReplace method then the result - * is returned. Otherwise, the value itself is returned. - * @return the true value to marshal on the wire. - **/ - public java.io.Serializable writeReplace(java.io.Serializable value) { - return super.writeReplace(value); - } - - // methods supported for backward compatability so that the appropriate - // Rep-id calculations take place based on the ORB version - - /** - * Returns a boolean of whether or not RepositoryId indicates - * FullValueDescriptor. - * used for backward compatability - */ - - public boolean useFullValueDescription(Class clazz, String repositoryID) - throws IOException - - { - return RepositoryId_1_3.useFullValueDescription(clazz, repositoryID); - } - - public String getClassName(String id) - { - RepositoryId_1_3 repID = RepositoryId_1_3.cache.getId(id); - return repID.getClassName(); - } - - public Class getClassFromType(String id) - throws ClassNotFoundException - { - RepositoryId_1_3 repId = RepositoryId_1_3.cache.getId(id); - return repId.getClassFromType(); - } - - public Class getAnyClassFromType(String id) - throws ClassNotFoundException - { - RepositoryId_1_3 repId = RepositoryId_1_3.cache.getId(id); - return repId.getAnyClassFromType(); - } - - public String createForAnyType(Class cl) - { - return RepositoryId_1_3.createForAnyType(cl); - } - - public String getDefinedInId(String id) - { - RepositoryId_1_3 repId = RepositoryId_1_3.cache.getId(id); - return repId.getDefinedInId(); - } - - public String getUnqualifiedName(String id) - { - RepositoryId_1_3 repId = RepositoryId_1_3.cache.getId(id); - return repId.getUnqualifiedName(); - } - - public String getSerialVersionUID(String id) - { - RepositoryId_1_3 repId = RepositoryId_1_3.cache.getId(id); - return repId.getSerialVersionUID(); - } - - public boolean isAbstractBase(Class clazz) - { - return RepositoryId_1_3.isAbstractBase(clazz); - } - - public boolean isSequence(String id) - { - RepositoryId_1_3 repId = RepositoryId_1_3.cache.getId(id); - return repId.isSequence(); - } - - /** - * Preserves the incorrect 1.3 behavior which truncates Java chars in - * arrays to 8-bit CORBA chars. Bug 4367783. This enables us to - * continue interoperating with our legacy ORBs. If this goes into - * Ladybird, then Ladybird and Kestrel will interoperate as long as - * people don't use chars greater than 8-bits. - */ - protected void writeCharArray(org.omg.CORBA_2_3.portable.OutputStream out, - char[] array, - int offset, - int length) - { - out.write_char_array(array, offset, length); - } - - /** - * Preserves the incorrect 1.3 behavior which truncates Java chars in - * arrays to 8-bit CORBA chars. Bug 4367783. This enables us to - * continue interoperating with our legacy ORBs. If this goes into - * Ladybird, then Ladybird and Kestrel will interoperate as long as - * people don't use chars greater than 8-bits. - */ - protected void readCharArray(org.omg.CORBA_2_3.portable.InputStream in, - char[] array, - int offset, - int length) - { - in.read_char_array(array, offset, length); - } - - protected final String getOutputStreamClassName() { - return "com.sun.corba.se.impl.orbutil.IIOPOutputStream_1_3"; - } - - protected final String getInputStreamClassName() { - return "com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3"; - } - - /** - * Our JDK 1.3 and JDK 1.3.1 behavior subclasses override this. - * The correct behavior is for a Java char to map to a CORBA wchar, - * but our older code mapped it to a CORBA char. - */ - protected TCKind getJavaCharTCKind() { - return TCKind.tk_char; - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3_1.java b/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3_1.java deleted file mode 100644 index 7309ec14c5e..00000000000 --- a/corba/src/share/classes/com/sun/corba/se/impl/orbutil/ValueHandlerImpl_1_3_1.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2001, 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.corba.se.impl.orbutil; - -import org.omg.CORBA.TCKind; - -/** - * This class overrides behavior of our current ValueHandlerImpl to - * provide backwards compatibility with JDK 1.3.1. - */ -public class ValueHandlerImpl_1_3_1 - extends com.sun.corba.se.impl.io.ValueHandlerImpl -{ - public ValueHandlerImpl_1_3_1() {} - - public ValueHandlerImpl_1_3_1(boolean isInputStream) { - super(isInputStream); - } - - /** - * Our JDK 1.3 and JDK 1.3.1 behavior subclasses override this. - * The correct behavior is for a Java char to map to a CORBA wchar, - * but our older code mapped it to a CORBA char. - */ - protected TCKind getJavaCharTCKind() { - return TCKind.tk_char; - } - - /** - * RepositoryId_1_3_1 performs an incorrect repId calculation - * when using serialPersistentFields and one of the fields no longer - * exists on the class itself. - */ - public boolean useFullValueDescription(Class clazz, String repositoryID) - throws java.io.IOException - { - return RepositoryId_1_3_1.useFullValueDescription(clazz, repositoryID); - } - - /** - * Installs the legacy IIOPOutputStream_1_3_1 which does - * PutFields/GetFields incorrectly. Bug 4407244. - */ - protected final String getOutputStreamClassName() { - return "com.sun.corba.se.impl.orbutil.IIOPOutputStream_1_3_1"; - } - - /** - * Installs the legacy IIOPInputStream_1_3_1 which does - * PutFields/GetFields incorrectly. Bug 4407244. - */ - protected final String getInputStreamClassName() { - return "com.sun.corba.se.impl.orbutil.IIOPInputStream_1_3_1"; - } -} diff --git a/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java b/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java index 22b89e73f22..306a9f7d2bf 100644 --- a/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java +++ b/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java @@ -98,6 +98,7 @@ import com.sun.corba.se.impl.logging.OMGSystemException ; import com.sun.corba.se.impl.presentation.rmi.PresentationManagerImpl ; import com.sun.corba.se.impl.orbutil.ORBClassLoader ; +import sun.awt.AppContext; public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB implements Broker, TypeCodeFactory @@ -173,14 +174,7 @@ public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB protected MonitoringManager monitoringManager; - // There is only one instance of the PresentationManager - // that is shared between all ORBs. This is necessary - // because RMI-IIOP requires the PresentationManager in - // places where no ORB is available, so the PresentationManager - // must be global. It is initialized here as well. - protected static PresentationManager globalPM = null ; - - static { + private static PresentationManager setupPresentationManager() { staticWrapper = ORBUtilSystemException.get( CORBALogDomains.RPC_PRESENTATION ) ; @@ -220,10 +214,11 @@ public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB } ) ; - globalPM = new PresentationManagerImpl( useDynamicStub ) ; - globalPM.setStubFactoryFactory( false, + PresentationManager pm = new PresentationManagerImpl( useDynamicStub ) ; + pm.setStubFactoryFactory( false, PresentationDefaults.getStaticStubFactoryFactory() ) ; - globalPM.setStubFactoryFactory( true, dynamicStubFactoryFactory ) ; + pm.setStubFactoryFactory( true, dynamicStubFactoryFactory ) ; + return pm; } public void destroy() { @@ -234,11 +229,19 @@ public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB byteBufferPool = null; } - /** Get the single instance of the PresentationManager + /** + * Returns the Presentation Manager for the current thread group, using the ThreadGroup-specific + * AppContext to hold it. Creates and records one if needed. */ public static PresentationManager getPresentationManager() { - return globalPM ; + AppContext ac = AppContext.getAppContext(); + PresentationManager pm = (PresentationManager) ac.get(PresentationManager.class); + if (pm == null) { + pm = setupPresentationManager(); + ac.put(PresentationManager.class, pm); + } + return pm; } /** Get the appropriate StubFactoryFactory. This @@ -248,8 +251,9 @@ public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB public static PresentationManager.StubFactoryFactory getStubFactoryFactory() { - boolean useDynamicStubs = globalPM.useDynamicStubs() ; - return globalPM.getStubFactoryFactory( useDynamicStubs ) ; + PresentationManager gPM = getPresentationManager(); + boolean useDynamicStubs = gPM.useDynamicStubs() ; + return gPM.getStubFactoryFactory( useDynamicStubs ) ; } protected ORB() diff --git a/corba/src/share/classes/sun/corba/JavaCorbaAccess.java b/corba/src/share/classes/sun/corba/JavaCorbaAccess.java new file mode 100644 index 00000000000..046453f2767 --- /dev/null +++ b/corba/src/share/classes/sun/corba/JavaCorbaAccess.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.corba; + +import com.sun.corba.se.impl.io.ValueHandlerImpl; + +public interface JavaCorbaAccess { + public ValueHandlerImpl newValueHandlerImpl(); +} diff --git a/corba/src/share/classes/sun/corba/SharedSecrets.java b/corba/src/share/classes/sun/corba/SharedSecrets.java new file mode 100644 index 00000000000..aba3ee0767a --- /dev/null +++ b/corba/src/share/classes/sun/corba/SharedSecrets.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.corba; + +import com.sun.corba.se.impl.io.ValueUtility; +import sun.misc.Unsafe; + +import java.security.AccessController; + +/** A repository of "shared secrets", which are a mechanism for + calling implementation-private methods in another package without + using reflection. A package-private class implements a public + interface and provides the ability to call package-private methods + within that package; the object implementing that interface is + provided through a third package to which access is restricted. + This framework avoids the primary disadvantage of using reflection + for this purpose, namely the loss of compile-time checking. */ + +// SharedSecrets cloned in corba repo to avoid build issues +public class SharedSecrets { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static JavaCorbaAccess javaCorbaAccess; + + public static JavaCorbaAccess getJavaCorbaAccess() { + if (javaCorbaAccess == null) { + // Ensure ValueUtility is initialized; we know that that class + // provides the shared secret + unsafe.ensureClassInitialized(ValueUtility.class); + } + return javaCorbaAccess; + } + + public static void setJavaCorbaAccess(JavaCorbaAccess access) { + javaCorbaAccess = access; + } + +} diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 5bf8e9848bb..bfb3baa2ed0 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -322,3 +322,7 @@ d5e12e7d2f719144d84903d9151455661c47b476 jdk8-b78 df5396524152118535c36da5801d828b560d19a2 hs25-b21 4a198b201f3ce84433fa94a3ca65d061473e7c4c jdk8-b80 dd6350b4abc4a6c19c89dd982cc0e4f3d119885c hs25-b22 +65b797426a3bec6e91b64085a0cfb94adadb634a jdk8-b81 +0631ebcc45f05c73b09a56c2586685af1f781c1d hs25-b23 +3db4ab0e12f437fe374817de346b2b0c6b4a5b31 jdk8-b82 +e3a41fc0234895eba4f272b984f7dacff495f8eb hs25-b24 diff --git a/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m b/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m index c14c6b7bc4b..d5c23a012df 100644 --- a/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m +++ b/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,12 +40,34 @@ #import #import #import +#include "libproc_impl.h" -jboolean debug = JNI_FALSE; +#define UNSUPPORTED_ARCH "Unsupported architecture!" + +#if defined(x86_64) && !defined(amd64) +#define amd64 1 +#endif + +#if amd64 +#include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h" +#else +#error UNSUPPORTED_ARCH +#endif static jfieldID symbolicatorID = 0; // set in _init0 static jfieldID taskID = 0; // set in _init0 +static jfieldID p_ps_prochandle_ID = 0; +static jfieldID loadObjectList_ID = 0; +static jmethodID listAdd_ID = 0; + +static jmethodID createClosestSymbol_ID = 0; +static jmethodID createLoadObject_ID = 0; +static jmethodID getJavaThreadsInfo_ID = 0; + +// indicator if thread id (lwpid_t) was set +static bool _threads_filled = false; + static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) { (*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator); } @@ -76,6 +98,11 @@ static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) { (*env)->ThrowNew(env, (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"), errMsg); } +static struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) { + jlong ptr = (*env)->GetLongField(env, this_obj, p_ps_prochandle_ID); + return (struct ps_prochandle*)(intptr_t)ptr; +} + #if defined(__i386__) #define hsdb_thread_state_t x86_thread_state32_t #define hsdb_float_state_t x86_float_state32_t @@ -91,7 +118,7 @@ static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) { #define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT #define HSDB_FLOAT_STATE_COUNT x86_FLOAT_STATE64_COUNT #else - #error "Unsupported architecture" + #error UNSUPPORTED_ARCH #endif /* @@ -104,6 +131,66 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J"); taskID = (*env)->GetFieldID(env, cls, "task", "J"); CHECK_EXCEPTION; + + // for core file + p_ps_prochandle_ID = (*env)->GetFieldID(env, cls, "p_ps_prochandle", "J"); + CHECK_EXCEPTION; + loadObjectList_ID = (*env)->GetFieldID(env, cls, "loadObjectList", "Ljava/util/List;"); + CHECK_EXCEPTION; + + // methods we use + createClosestSymbol_ID = (*env)->GetMethodID(env, cls, "createClosestSymbol", + "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;"); + CHECK_EXCEPTION; + createLoadObject_ID = (*env)->GetMethodID(env, cls, "createLoadObject", + "(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;"); + CHECK_EXCEPTION; + + // java.util.List method we call + jclass listClass = (*env)->FindClass(env, "java/util/List"); + CHECK_EXCEPTION; + listAdd_ID = (*env)->GetMethodID(env, listClass, "add", "(Ljava/lang/Object;)Z"); + CHECK_EXCEPTION; + getJavaThreadsInfo_ID = (*env)->GetMethodID(env, cls, "getJavaThreadsInfo", + "()[J"); + CHECK_EXCEPTION; + + init_libproc(getenv("LIBSAPROC_DEBUG") != NULL); +} + +JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getAddressSize + (JNIEnv *env, jclass cls) +{ +#ifdef _LP64 + return 8; +#else + #error UNSUPPORTED_ARCH +#endif +} + +/** called by Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0 */ +jlong lookupByNameIncore( + JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jstring objectName, jstring symbolName) +{ + const char *objectName_cstr, *symbolName_cstr; + jlong addr; + jboolean isCopy; + objectName_cstr = NULL; + if (objectName != NULL) { + objectName_cstr = (*env)->GetStringUTFChars(env, objectName, &isCopy); + CHECK_EXCEPTION_(0); + } + symbolName_cstr = (*env)->GetStringUTFChars(env, symbolName, &isCopy); + CHECK_EXCEPTION_(0); + + print_debug("look for %s \n", symbolName_cstr); + addr = (jlong) lookup_symbol(ph, objectName_cstr, symbolName_cstr); + + if (objectName_cstr != NULL) { + (*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr); + } + (*env)->ReleaseStringUTFChars(env, symbolName, symbolName_cstr); + return addr; } /* @@ -116,14 +203,17 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0( JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) { + struct ps_prochandle* ph = get_proc_handle(env, this_obj); + if (ph->core != NULL) { + return lookupByNameIncore(env, ph, this_obj, objectName, symbolName); + } + jlong address = 0; JNF_COCOA_ENTER(env); NSString *symbolNameString = JNFJavaToNSString(env, symbolName); - if (debug) { - printf("lookupInProcess called for %s\n", [symbolNameString UTF8String]); - } + print_debug("lookupInProcess called for %s\n", [symbolNameString UTF8String]); id symbolicator = getSymbolicator(env, this_obj); if (symbolicator != nil) { @@ -131,14 +221,48 @@ JNF_COCOA_ENTER(env); address = (jlong) dynamicCall(symbolicator, @selector(addressForSymbol:), symbolNameString); } - if (debug) { - printf("address of symbol %s = %llx\n", [symbolNameString UTF8String], address); - } + print_debug("address of symbol %s = %llx\n", [symbolNameString UTF8String], address); JNF_COCOA_EXIT(env); return address; } +/* + * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal + * Method: lookupByAddress0 + * Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol; + */ +JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0 + (JNIEnv *env, jobject this_obj, jlong addr) { + uintptr_t offset; + const char* sym = NULL; + + struct ps_prochandle* ph = get_proc_handle(env, this_obj); + sym = symbol_for_pc(ph, (uintptr_t) addr, &offset); + if (sym == NULL) return 0; + return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID, + (*env)->NewStringUTF(env, sym), (jlong)offset); +} + +/** called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0 */ +jbyteArray readBytesFromCore( + JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jlong addr, jlong numBytes) +{ + jboolean isCopy; + jbyteArray array; + jbyte *bufPtr; + ps_err_e err; + + array = (*env)->NewByteArray(env, numBytes); + CHECK_EXCEPTION_(0); + bufPtr = (*env)->GetByteArrayElements(env, array, &isCopy); + CHECK_EXCEPTION_(0); + + err = ps_pread(ph, (psaddr_t) (uintptr_t)addr, bufPtr, numBytes); + (*env)->ReleaseByteArrayElements(env, array, bufPtr, 0); + return (err == PS_OK)? array : 0; +} + /* * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal * Method: readBytesFromProcess0 @@ -149,12 +273,15 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0( JNIEnv *env, jobject this_obj, jlong addr, jlong numBytes) { - if (debug) printf("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes); + print_debug("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes); // must allocate storage instead of using former parameter buf - jboolean isCopy; jbyteArray array; - jbyte *bufPtr; + + struct ps_prochandle* ph = get_proc_handle(env, this_obj); + if (ph->core != NULL) { + return readBytesFromCore(env, ph, this_obj, addr, numBytes); + } array = (*env)->NewByteArray(env, numBytes); CHECK_EXCEPTION_(0); @@ -189,7 +316,7 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0( // assume all failures are unmapped pages } - if (debug) fprintf(stderr, "%ld pages\n", pageCount); + print_debug("%ld pages\n", pageCount); remaining = numBytes; @@ -207,7 +334,7 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0( } if (mapped[i]) { - if (debug) fprintf(stderr, "page %d mapped (len %ld start %ld)\n", i, len, start); + print_debug("page %d mapped (len %ld start %ld)\n", i, len, start); (*env)->SetByteArrayRegion(env, array, 0, len, ((jbyte *) pages[i] + start)); vm_deallocate(mach_task_self(), pages[i], vm_page_size); } @@ -220,6 +347,115 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0( return array; } +/** Only used for core file reading, set thread_id for threads which is got after core file parsed. + * Thread context is available in Mach-O core file but thread id is not. We can get thread id + * from Threads which store all java threads information when they are created. Here we can identify + * them as java threads by checking if a thread's rsp or rbp within a java thread's stack. + * Note Macosx uses unique_thread_id which is different from other platforms though printed ids + * are still pthread id. Function BsdDebuggerLocal.getJavaThreadsInfo returns an array of long + * integers to host all java threads' id, stack_start, stack_end as: + * [uid0, stack_start0, stack_end0, uid1, stack_start1, stack_end1, ...] + * + * The work cannot be done at init0 since Threads is not available yet(VM not initialized yet). + * This function should be called only once if succeeded + */ +bool fill_java_threads(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) { + int n = 0, i = 0, j; + struct reg regs; + + jlongArray thrinfos = (*env)->CallObjectMethod(env, this_obj, getJavaThreadsInfo_ID); + CHECK_EXCEPTION_(false); + int len = (int)(*env)->GetArrayLength(env, thrinfos); + uint64_t* cinfos = (uint64_t *)(*env)->GetLongArrayElements(env, thrinfos, NULL); + CHECK_EXCEPTION_(false); + n = get_num_threads(ph); + print_debug("fill_java_threads called, num_of_thread = %d\n", n); + for (i = 0; i < n; i++) { + if (!get_nth_lwp_regs(ph, i, ®s)) { + print_debug("Could not get regs of thread %d, already set!\n", i); + return false; + } + for (j = 0; j < len; j += 3) { + lwpid_t uid = cinfos[j]; + uint64_t beg = cinfos[j + 1]; + uint64_t end = cinfos[j + 2]; + if ((regs.r_rsp < end && regs.r_rsp >= beg) || + (regs.r_rbp < end && regs.r_rbp >= beg)) { + set_lwp_id(ph, i, uid); + break; + } + } + } + (*env)->ReleaseLongArrayElements(env, thrinfos, (jlong*)cinfos, 0); + CHECK_EXCEPTION_(false); + return true; +} + +/* For core file only, called from + * Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0 + */ +jlongArray getThreadIntegerRegisterSetFromCore(JNIEnv *env, jobject this_obj, long lwp_id) { + if (!_threads_filled) { + if (!fill_java_threads(env, this_obj, get_proc_handle(env, this_obj))) { + throw_new_debugger_exception(env, "Failed to fill in threads"); + return 0; + } else { + _threads_filled = true; + } + } + + struct reg gregs; + jboolean isCopy; + jlongArray array; + jlong *regs; + + struct ps_prochandle* ph = get_proc_handle(env, this_obj); + if (get_lwp_regs(ph, lwp_id, &gregs) != true) { + THROW_NEW_DEBUGGER_EXCEPTION_("get_thread_regs failed for a lwp", 0); + } + +#undef NPRGREG +#undef REG_INDEX +#if amd64 +#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG +#define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg + + array = (*env)->NewLongArray(env, NPRGREG); + CHECK_EXCEPTION_(0); + regs = (*env)->GetLongArrayElements(env, array, &isCopy); + + regs[REG_INDEX(R15)] = gregs.r_r15; + regs[REG_INDEX(R14)] = gregs.r_r14; + regs[REG_INDEX(R13)] = gregs.r_r13; + regs[REG_INDEX(R12)] = gregs.r_r12; + regs[REG_INDEX(RBP)] = gregs.r_rbp; + regs[REG_INDEX(RBX)] = gregs.r_rbx; + regs[REG_INDEX(R11)] = gregs.r_r11; + regs[REG_INDEX(R10)] = gregs.r_r10; + regs[REG_INDEX(R9)] = gregs.r_r9; + regs[REG_INDEX(R8)] = gregs.r_r8; + regs[REG_INDEX(RAX)] = gregs.r_rax; + regs[REG_INDEX(RCX)] = gregs.r_rcx; + regs[REG_INDEX(RDX)] = gregs.r_rdx; + regs[REG_INDEX(RSI)] = gregs.r_rsi; + regs[REG_INDEX(RDI)] = gregs.r_rdi; + regs[REG_INDEX(RIP)] = gregs.r_rip; + regs[REG_INDEX(CS)] = gregs.r_cs; + regs[REG_INDEX(RSP)] = gregs.r_rsp; + regs[REG_INDEX(SS)] = gregs.r_ss; + regs[REG_INDEX(FSBASE)] = 0; + regs[REG_INDEX(GSBASE)] = 0; + regs[REG_INDEX(DS)] = gregs.r_ds; + regs[REG_INDEX(ES)] = gregs.r_es; + regs[REG_INDEX(FS)] = gregs.r_fs; + regs[REG_INDEX(GS)] = gregs.r_gs; + regs[REG_INDEX(TRAPNO)] = gregs.r_trapno; + regs[REG_INDEX(RFL)] = gregs.r_rflags; + +#endif /* amd64 */ + (*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT); + return array; +} /* * Lookup the thread_t that corresponds to the given thread_id. @@ -232,9 +468,7 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0( */ thread_t lookupThreadFromThreadId(task_t task, jlong thread_id) { - if (debug) { - printf("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id); - } + print_debug("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id); thread_array_t thread_list = NULL; mach_msg_type_number_t thread_list_count = 0; @@ -244,9 +478,7 @@ lookupThreadFromThreadId(task_t task, jlong thread_id) { // get the list of all the send rights kern_return_t result = task_threads(task, &thread_list, &thread_list_count); if (result != KERN_SUCCESS) { - if (debug) { - printf("task_threads returned 0x%x\n", result); - } + print_debug("task_threads returned 0x%x\n", result); return 0; } @@ -257,9 +489,7 @@ lookupThreadFromThreadId(task_t task, jlong thread_id) { // get the THREAD_IDENTIFIER_INFO for the send right result = thread_info(thread_list[i], THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count); if (result != KERN_SUCCESS) { - if (debug) { - printf("thread_info returned 0x%x\n", result); - } + print_debug("thread_info returned 0x%x\n", result); break; } @@ -288,15 +518,17 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0( JNIEnv *env, jobject this_obj, jlong thread_id) { - if (debug) - printf("getThreadRegisterSet0 called\n"); + print_debug("getThreadRegisterSet0 called\n"); + + struct ps_prochandle* ph = get_proc_handle(env, this_obj); + if (ph->core != NULL) { + return getThreadIntegerRegisterSetFromCore(env, this_obj, thread_id); + } kern_return_t result; thread_t tid; mach_msg_type_number_t count = HSDB_THREAD_STATE_COUNT; hsdb_thread_state_t state; - unsigned int *r; - int i; jlongArray registerArray; jlong *primitiveArray; task_t gTask = getTask(env, this_obj); @@ -306,97 +538,56 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0( result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count); if (result != KERN_SUCCESS) { - if (debug) - printf("getregs: thread_get_state(%d) failed (%d)\n", tid, result); + print_error("getregs: thread_get_state(%d) failed (%d)\n", tid, result); return NULL; } - // 40 32-bit registers on ppc, 16 on x86. - // Output order is the same as the order in the ppc_thread_state/i386_thread_state struct. -#if defined(__i386__) - r = (unsigned int *)&state; - registerArray = (*env)->NewLongArray(env, 8); - primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL); - primitiveArray[0] = r[0]; // eax - primitiveArray[1] = r[2]; // ecx - primitiveArray[2] = r[3]; // edx - primitiveArray[3] = r[1]; // ebx - primitiveArray[4] = r[7]; // esp - primitiveArray[5] = r[6]; // ebp - primitiveArray[6] = r[5]; // esi - primitiveArray[7] = r[4]; // edi - (*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0); -#elif defined(__x86_64__) - /* From AMD64ThreadContext.java - public static final int R15 = 0; - public static final int R14 = 1; - public static final int R13 = 2; - public static final int R12 = 3; - public static final int R11 = 4; - public static final int R10 = 5; - public static final int R9 = 6; - public static final int R8 = 7; - public static final int RDI = 8; - public static final int RSI = 9; - public static final int RBP = 10; - public static final int RBX = 11; - public static final int RDX = 12; - public static final int RCX = 13; - public static final int RAX = 14; - public static final int TRAPNO = 15; - public static final int ERR = 16; - public static final int RIP = 17; - public static final int CS = 18; - public static final int RFL = 19; - public static final int RSP = 20; - public static final int SS = 21; - public static final int FS = 22; - public static final int GS = 23; - public static final int ES = 24; - public static final int DS = 25; - public static final int FSBASE = 26; - public static final int GSBASE = 27; - */ - // 64 bit - if (debug) printf("Getting threads for a 64-bit process\n"); - registerArray = (*env)->NewLongArray(env, 28); - primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL); +#if amd64 +#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG +#undef REG_INDEX +#define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg - primitiveArray[0] = state.__r15; - primitiveArray[1] = state.__r14; - primitiveArray[2] = state.__r13; - primitiveArray[3] = state.__r12; - primitiveArray[4] = state.__r11; - primitiveArray[5] = state.__r10; - primitiveArray[6] = state.__r9; - primitiveArray[7] = state.__r8; - primitiveArray[8] = state.__rdi; - primitiveArray[9] = state.__rsi; - primitiveArray[10] = state.__rbp; - primitiveArray[11] = state.__rbx; - primitiveArray[12] = state.__rdx; - primitiveArray[13] = state.__rcx; - primitiveArray[14] = state.__rax; - primitiveArray[15] = 0; // trapno ? - primitiveArray[16] = 0; // err ? - primitiveArray[17] = state.__rip; - primitiveArray[18] = state.__cs; - primitiveArray[19] = state.__rflags; - primitiveArray[20] = state.__rsp; - primitiveArray[21] = 0; // We don't have SS - primitiveArray[22] = state.__fs; - primitiveArray[23] = state.__gs; - primitiveArray[24] = 0; - primitiveArray[25] = 0; - primitiveArray[26] = 0; - primitiveArray[27] = 0; + // 64 bit + print_debug("Getting threads for a 64-bit process\n"); + registerArray = (*env)->NewLongArray(env, NPRGREG); + CHECK_EXCEPTION_(0); + primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL); - if (debug) printf("set registers\n"); + primitiveArray[REG_INDEX(R15)] = state.__r15; + primitiveArray[REG_INDEX(R14)] = state.__r14; + primitiveArray[REG_INDEX(R13)] = state.__r13; + primitiveArray[REG_INDEX(R12)] = state.__r12; + primitiveArray[REG_INDEX(R11)] = state.__r11; + primitiveArray[REG_INDEX(R10)] = state.__r10; + primitiveArray[REG_INDEX(R9)] = state.__r9; + primitiveArray[REG_INDEX(R8)] = state.__r8; + primitiveArray[REG_INDEX(RDI)] = state.__rdi; + primitiveArray[REG_INDEX(RSI)] = state.__rsi; + primitiveArray[REG_INDEX(RBP)] = state.__rbp; + primitiveArray[REG_INDEX(RBX)] = state.__rbx; + primitiveArray[REG_INDEX(RDX)] = state.__rdx; + primitiveArray[REG_INDEX(RCX)] = state.__rcx; + primitiveArray[REG_INDEX(RAX)] = state.__rax; + primitiveArray[REG_INDEX(TRAPNO)] = 0; // trapno, not used + primitiveArray[REG_INDEX(ERR)] = 0; // err, not used + primitiveArray[REG_INDEX(RIP)] = state.__rip; + primitiveArray[REG_INDEX(CS)] = state.__cs; + primitiveArray[REG_INDEX(RFL)] = state.__rflags; + primitiveArray[REG_INDEX(RSP)] = state.__rsp; + primitiveArray[REG_INDEX(SS)] = 0; // We don't have SS + primitiveArray[REG_INDEX(FS)] = state.__fs; + primitiveArray[REG_INDEX(GS)] = state.__gs; + primitiveArray[REG_INDEX(ES)] = 0; + primitiveArray[REG_INDEX(DS)] = 0; + primitiveArray[REG_INDEX(FSBASE)] = 0; + primitiveArray[REG_INDEX(GSBASE)] = 0; + print_debug("set registers\n"); + + (*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0); - (*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0); #else -#error Unsupported architecture -#endif +#error UNSUPPORTED_ARCH +#endif /* amd64 */ return registerArray; } @@ -410,8 +601,7 @@ JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0( JNIEnv *env, jobject this_obj, jint tid) { - if (debug) - printf("translateTID0 called on tid = 0x%x\n", (int)tid); + print_debug("translateTID0 called on tid = 0x%x\n", (int)tid); kern_return_t result; thread_t foreign_tid, usable_tid; @@ -426,8 +616,7 @@ Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0( if (result != KERN_SUCCESS) return -1; - if (debug) - printf("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid); + print_debug("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid); return (jint) usable_tid; } @@ -437,7 +626,7 @@ static bool ptrace_continue(pid_t pid, int signal) { // pass the signal to the process so we don't swallow it int res; if ((res = ptrace(PT_CONTINUE, pid, (caddr_t)1, signal)) < 0) { - fprintf(stderr, "attach: ptrace(PT_CONTINUE, %d) failed with %d\n", pid, res); + print_error("attach: ptrace(PT_CONTINUE, %d) failed with %d\n", pid, res); return false; } return true; @@ -461,11 +650,11 @@ static bool ptrace_waitpid(pid_t pid) { return true; } if (!ptrace_continue(pid, WSTOPSIG(status))) { - fprintf(stderr, "attach: Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status)); + print_error("attach: Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status)); return false; } } else { - fprintf(stderr, "attach: waitpid(): Child process exited/terminated (status = 0x%x)\n", status); + print_error("attach: waitpid(): Child process exited/terminated (status = 0x%x)\n", status); return false; } } else { @@ -474,13 +663,13 @@ static bool ptrace_waitpid(pid_t pid) { continue; break; case ECHILD: - fprintf(stderr, "attach: waitpid() failed. Child process pid (%d) does not exist \n", pid); + print_error("attach: waitpid() failed. Child process pid (%d) does not exist \n", pid); break; case EINVAL: - fprintf(stderr, "attach: waitpid() failed. Invalid options argument.\n"); + print_error("attach: waitpid() failed. Invalid options argument.\n"); break; default: - fprintf(stderr, "attach: waitpid() failed. Unexpected error %d\n",errno); + print_error("attach: waitpid() failed. Unexpected error %d\n",errno); break; } return false; @@ -492,7 +681,7 @@ static bool ptrace_waitpid(pid_t pid) { static bool ptrace_attach(pid_t pid) { int res; if ((res = ptrace(PT_ATTACH, pid, 0, 0)) < 0) { - fprintf(stderr, "ptrace(PT_ATTACH, %d) failed with %d\n", pid, res); + print_error("ptrace(PT_ATTACH, %d) failed with %d\n", pid, res); return false; } else { return ptrace_waitpid(pid); @@ -504,23 +693,19 @@ static bool ptrace_attach(pid_t pid) { * Method: attach0 * Signature: (I)V */ -JNIEXPORT void JNICALL +JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I( - JNIEnv *env, jobject this_obj, jint jpid) + JNIEnv *env, jobject this_obj, jint jpid) { + print_debug("attach0 called for jpid=%d\n", (int)jpid); + JNF_COCOA_ENTER(env); - if (getenv("JAVA_SAPROC_DEBUG") != NULL) - debug = JNI_TRUE; - else - debug = JNI_FALSE; - if (debug) printf("attach0 called for jpid=%d\n", (int)jpid); - - // get the task from the pid + kern_return_t result; task_t gTask = 0; result = task_for_pid(mach_task_self(), jpid, &gTask); if (result != KERN_SUCCESS) { - fprintf(stderr, "attach: task_for_pid(%d) failed (%d)\n", (int)jpid, result); + print_error("attach: task_for_pid(%d) failed (%d)\n", (int)jpid, result); THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process"); } putTask(env, this_obj, gTask); @@ -550,18 +735,79 @@ JNF_COCOA_ENTER(env); JNF_COCOA_EXIT(env); } +/** For core file, + called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2 */ +static void fillLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) { + int n = 0, i = 0; + + // add load objects + n = get_num_libs(ph); + for (i = 0; i < n; i++) { + uintptr_t base; + const char* name; + jobject loadObject; + jobject loadObjectList; + + base = get_lib_base(ph, i); + name = get_lib_name(ph, i); + loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID, + (*env)->NewStringUTF(env, name), (jlong)0, (jlong)base); + CHECK_EXCEPTION; + loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID); + CHECK_EXCEPTION; + (*env)->CallBooleanMethod(env, loadObjectList, listAdd_ID, loadObject); + CHECK_EXCEPTION; + } +} + +/* + * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal + * Method: attach0 + * Signature: (Ljava/lang/String;Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL +Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2( + JNIEnv *env, jobject this_obj, jstring execName, jstring coreName) +{ + const char *execName_cstr; + const char *coreName_cstr; + jboolean isCopy; + struct ps_prochandle* ph; + + execName_cstr = (*env)->GetStringUTFChars(env, execName, &isCopy); + CHECK_EXCEPTION; + coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy); + CHECK_EXCEPTION; + + print_debug("attach: %s %s\n", execName_cstr, coreName_cstr); + + if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) { + (*env)->ReleaseStringUTFChars(env, execName, execName_cstr); + (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr); + THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file"); + } + (*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph); + (*env)->ReleaseStringUTFChars(env, execName, execName_cstr); + (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr); + fillLoadObjects(env, this_obj, ph); +} + /* * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal * Method: detach0 * Signature: ()V */ -JNIEXPORT void JNICALL +JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0( - JNIEnv *env, jobject this_obj) + JNIEnv *env, jobject this_obj) { + print_debug("detach0 called\n"); + struct ps_prochandle* ph = get_proc_handle(env, this_obj); + if (ph != NULL && ph->core != NULL) { + Prelease(ph); + return; + } JNF_COCOA_ENTER(env); - if (debug) printf("detach0 called\n"); - task_t gTask = getTask(env, this_obj); // detach from the ptraced process causing it to resume execution @@ -569,15 +815,15 @@ JNF_COCOA_ENTER(env); kern_return_t k_res; k_res = pid_for_task(gTask, &pid); if (k_res != KERN_SUCCESS) { - fprintf(stderr, "detach: pid_for_task(%d) failed (%d)\n", pid, k_res); + print_error("detach: pid_for_task(%d) failed (%d)\n", pid, k_res); } else { int res = ptrace(PT_DETACH, pid, 0, 0); if (res < 0) { - fprintf(stderr, "detach: ptrace(PT_DETACH, %d) failed (%d)\n", pid, res); + print_error("detach: ptrace(PT_DETACH, %d) failed (%d)\n", pid, res); } } - + mach_port_deallocate(mach_task_self(), gTask); id symbolicator = getSymbolicator(env, this_obj); if (symbolicator != nil) { @@ -585,170 +831,3 @@ JNF_COCOA_ENTER(env); } JNF_COCOA_EXIT(env); } - -/* - * Class: sun_jvm_hotspot_asm_Disassembler - * Method: load_library - * Signature: (Ljava/lang/String;)L - */ -JNIEXPORT jlong JNICALL -Java_sun_jvm_hotspot_asm_Disassembler_load_1library( - JNIEnv * env, - jclass disclass, - jstring jrepath_s, - jstring libname_s) -{ - uintptr_t func = 0; - const char* error_message = NULL; - const char* java_home; - jboolean isCopy; - uintptr_t *handle = NULL; - - const char * jrepath = (*env)->GetStringUTFChars(env, jrepath_s, &isCopy); // like $JAVA_HOME/jre/lib/sparc/ - const char * libname = (*env)->GetStringUTFChars(env, libname_s, &isCopy); - char buffer[128]; - - /* Load the hsdis library */ - void* hsdis_handle; - hsdis_handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL); - if (hsdis_handle == NULL) { - snprintf(buffer, sizeof(buffer), "%s%s", jrepath, libname); - hsdis_handle = dlopen(buffer, RTLD_LAZY | RTLD_GLOBAL); - } - if (hsdis_handle != NULL) { - func = (uintptr_t)dlsym(hsdis_handle, "decode_instructions_virtual"); - } - if (func == 0) { - error_message = dlerror(); - fprintf(stderr, "%s\n", error_message); - } - - (*env)->ReleaseStringUTFChars(env, libname_s, libname); - (*env)->ReleaseStringUTFChars(env, jrepath_s, jrepath); - - if (func == 0) { - /* Couldn't find entry point. error_message should contain some - * platform dependent error message. - */ - THROW_NEW_DEBUGGER_EXCEPTION_(error_message, (jlong)func); - } - return (jlong)func; -} - -/* signature of decode_instructions_virtual from hsdis.h */ -typedef void* (*decode_func)(uintptr_t start_va, uintptr_t end_va, - unsigned char* start, uintptr_t length, - void* (*event_callback)(void*, const char*, void*), - void* event_stream, - int (*printf_callback)(void*, const char*, ...), - void* printf_stream, - const char* options); - -/* container for call back state when decoding instructions */ -typedef struct { - JNIEnv* env; - jobject dis; - jobject visitor; - jmethodID handle_event; - jmethodID raw_print; - char buffer[4096]; -} decode_env; - - -/* event callback binding to Disassembler.handleEvent */ -static void* event_to_env(void* env_pv, const char* event, void* arg) { - decode_env* denv = (decode_env*)env_pv; - JNIEnv* env = denv->env; - jstring event_string = (*env)->NewStringUTF(env, event); - jlong result = (*env)->CallLongMethod(env, denv->dis, denv->handle_event, denv->visitor, - event_string, (jlong) (uintptr_t)arg); - /* ignore exceptions for now */ - CHECK_EXCEPTION_CLEAR_((void *)0); - return (void*)(uintptr_t)result; -} - -/* printing callback binding to Disassembler.rawPrint */ -static int printf_to_env(void* env_pv, const char* format, ...) { - jstring output; - va_list ap; - int cnt; - decode_env* denv = (decode_env*)env_pv; - JNIEnv* env = denv->env; - size_t flen = strlen(format); - const char* raw = NULL; - - if (flen == 0) return 0; - if (flen < 2 || - strchr(format, '%') == NULL) { - raw = format; - } else if (format[0] == '%' && format[1] == '%' && - strchr(format+2, '%') == NULL) { - // happens a lot on machines with names like %foo - flen--; - raw = format+1; - } - if (raw != NULL) { - jstring output = (*env)->NewStringUTF(env, raw); - (*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output); - CHECK_EXCEPTION_CLEAR; - return (int) flen; - } - va_start(ap, format); - cnt = vsnprintf(denv->buffer, sizeof(denv->buffer), format, ap); - va_end(ap); - - output = (*env)->NewStringUTF(env, denv->buffer); - (*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output); - CHECK_EXCEPTION_CLEAR; - return cnt; -} - -/* - * Class: sun_jvm_hotspot_asm_Disassembler - * Method: decode - * Signature: (Lsun/jvm/hotspot/asm/InstructionVisitor;J[BLjava/lang/String;J)V - */ -JNIEXPORT void JNICALL -Java_sun_jvm_hotspot_asm_Disassembler_decode( - JNIEnv * env, - jobject dis, - jobject visitor, - jlong startPc, - jbyteArray code, - jstring options_s, - jlong decode_instructions_virtual) -{ - jboolean isCopy; - jbyte* start = (*env)->GetByteArrayElements(env, code, &isCopy); - jbyte* end = start + (*env)->GetArrayLength(env, code); - const char * options = (*env)->GetStringUTFChars(env, options_s, &isCopy); - jclass disclass = (*env)->GetObjectClass(env, dis); - - decode_env denv; - denv.env = env; - denv.dis = dis; - denv.visitor = visitor; - - /* find Disassembler.handleEvent callback */ - denv.handle_event = (*env)->GetMethodID(env, disclass, "handleEvent", - "(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;J)J"); - CHECK_EXCEPTION_CLEAR_VOID - - /* find Disassembler.rawPrint callback */ - denv.raw_print = (*env)->GetMethodID(env, disclass, "rawPrint", - "(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;)V"); - CHECK_EXCEPTION_CLEAR_VOID - - /* decode the buffer */ - (*(decode_func)(uintptr_t)decode_instructions_virtual)(startPc, - startPc + end - start, - (unsigned char*)start, - end - start, - &event_to_env, (void*) &denv, - &printf_to_env, (void*) &denv, - options); - - /* cleanup */ - (*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT); - (*env)->ReleaseStringUTFChars(env, options_s, options); -} diff --git a/hotspot/agent/src/os/bsd/Makefile b/hotspot/agent/src/os/bsd/Makefile index 90085c6ee9e..ce3e2c4c32c 100644 --- a/hotspot/agent/src/os/bsd/Makefile +++ b/hotspot/agent/src/os/bsd/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -22,34 +22,60 @@ # # -ARCH := $(shell if ([ `uname -m` = "ia64" ]) ; then echo ia64 ; elif ([ `uname -m` = "amd64" ]) ; then echo amd64; elif ([ `uname -m` = "sparc64" ]) ; then echo sparc; else echo i386 ; fi ) +ARCH := $(shell if ([ `uname -m` = "ia64" ]) ; then echo ia64 ; elif ([ `uname -m` = "amd64" ]) ; then echo amd64; elif ([ `uname -m` = "x86_64" ]) ; then echo amd64; elif ([ `uname -m` = "sparc64" ]) ; then echo sparc; else echo i386 ; fi ) + +OS := $(shell uname -s) + GCC = gcc JAVAH = ${JAVA_HOME}/bin/javah +ifneq ($(OS), Darwin) SOURCES = salibelf.c \ symtab.c \ libproc_impl.c \ ps_proc.c \ ps_core.c \ BsdDebuggerLocal.c - -INCLUDES = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(shell uname -s | tr "[:upper:]" "[:lower:]") - -OBJS = $(SOURCES:.c=.o) +OBJS = $(SOURCES:.c=.o) +OBJSPLUS = $(OBJS) sadis.o +LIBSA = $(ARCH)/libsaproc.so LIBS = -lutil -lthread_db -CFLAGS = -c -fPIC -g -Wall -D_ALLBSD_SOURCE -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) +else + +SOURCES = symtab.c \ + libproc_impl.c \ + ps_core.c +OBJS = $(SOURCES:.c=.o) +OBJSPLUS = MacosxDebuggerLocal.o sadis.o $(OBJS) +EXTINCLUDE = -I/System/Library/Frameworks/JavaVM.framework/Headers -I. +EXTCFLAGS = -m64 -D__APPLE__ -framework JavaNativeFoundation +FOUNDATIONFLAGS = -framework Foundation -F/System/Library/Frameworks/JavaVM.framework/Frameworks -framework JavaNativeFoundation -framework Security -framework CoreFoundation +LIBSA = $(ARCH)/libsaproc.dylib +endif # Darwin + +INCLUDES = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(shell uname -s | tr "[:upper:]" "[:lower:]") $(EXTINCLUDE) + + + +CFLAGS = -c -fPIC -g -Wall -D_ALLBSD_SOURCE -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) $(EXTCFLAGS) + -LIBSA = $(ARCH)/libsaproc.so all: $(LIBSA) -BsdDebuggerLocal.o: BsdDebuggerLocal.c - $(JAVAH) -jni -classpath ../../../../../build/bsd-i586/hotspot/outputdir/bsd_i486_compiler2/generated/saclasses \ +MacosxDebuggerLocal.o: MacosxDebuggerLocal.m + echo "OS="$(OS) + $(JAVAH) -jni -classpath ../../../build/classes \ sun.jvm.hotspot.debugger.x86.X86ThreadContext \ sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext + $(GCC) $(CFLAGS) $(FOUNDATIONFLAGS) $< + +sadis.o: ../../share/native/sadis.c + $(JAVAH) -jni -classpath ../../../build/classes \ + sun.jvm.hotspot.asm.Disassembler $(GCC) $(CFLAGS) $< .c.obj: @@ -59,9 +85,9 @@ ifndef LDNOMAP LFLAGS_LIBSA = -Xlinker --version-script=mapfile endif -$(LIBSA): $(OBJS) mapfile +$(LIBSA): $(OBJSPLUS) mapfile if [ ! -d $(ARCH) ] ; then mkdir $(ARCH) ; fi - $(GCC) -shared $(LFLAGS_LIBSA) -o $(LIBSA) $(OBJS) $(LIBS) + $(GCC) -shared $(LFLAGS_LIBSA) -o $(LIBSA) $(FOUNDATIONFLAGS) $(OBJSPLUS) $(LIBS) $(SALIBS) test.o: $(LIBSA) test.c $(GCC) -c -o test.o -g -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) test.c @@ -71,7 +97,6 @@ test: test.o clean: rm -f $(LIBSA) - rm -f $(OBJS) + rm -f *.o rm -f test.o -rmdir $(ARCH) - diff --git a/hotspot/agent/src/os/bsd/libproc.h b/hotspot/agent/src/os/bsd/libproc.h index 74bb84c1760..11e00dcb828 100644 --- a/hotspot/agent/src/os/bsd/libproc.h +++ b/hotspot/agent/src/os/bsd/libproc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,9 +27,38 @@ #include #include +#include +#include +#include +#include +#include + +#ifdef __APPLE__ +typedef enum ps_err_e { + PS_OK, PS_ERR, PS_BADPID, PS_BADLID, + PS_BADADDR, PS_NOSYM, PS_NOFREGS +} ps_err_e; + +#ifndef psaddr_t +#define psaddr_t uintptr_t +#endif + +#ifndef bool +typedef int bool; +#define true 1 +#define false 0 +#endif // bool + +#ifndef lwpid_t +#define lwpid_t uintptr_t +#endif + +#include +#else // __APPLE__ +#include +#include #include #include - #if defined(sparc) || defined(sparcv9) /* If _LP64 is defined ptrace.h should be taken from /usr/include/asm-sparc64 @@ -44,6 +73,14 @@ #endif //sparc or sparcv9 +// This C bool type must be int for compatibility with BSD calls and +// it would be a mistake to equivalence it to C++ bool on many platforms +typedef int bool; +#define true 1 +#define false 0 + +#endif // __APPLE__ + /************************************************************************************ 0. This is very minimal subset of Solaris libproc just enough for current application. @@ -72,13 +109,7 @@ combination of ptrace and /proc calls. *************************************************************************************/ -// This C bool type must be int for compatibility with BSD calls and -// it would be a mistake to equivalence it to C++ bool on many platforms - -typedef int bool; -#define true 1 -#define false 0 - +struct reg; struct ps_prochandle; // attach to a process diff --git a/hotspot/agent/src/os/bsd/libproc_impl.c b/hotspot/agent/src/os/bsd/libproc_impl.c index e9fa1b82a34..78da80617fa 100644 --- a/hotspot/agent/src/os/bsd/libproc_impl.c +++ b/hotspot/agent/src/os/bsd/libproc_impl.c @@ -21,12 +21,6 @@ * questions. * */ -#include -#include -#include -#include -#include -#include #include "libproc_impl.h" static const char* alt_root = NULL; @@ -34,61 +28,65 @@ static int alt_root_len = -1; #define SA_ALTROOT "SA_ALTROOT" +off_t ltell(int fd) { + return lseek(fd, 0, SEEK_CUR); +} + static void init_alt_root() { - if (alt_root_len == -1) { - alt_root = getenv(SA_ALTROOT); - if (alt_root) { - alt_root_len = strlen(alt_root); - } else { - alt_root_len = 0; - } - } + if (alt_root_len == -1) { + alt_root = getenv(SA_ALTROOT); + if (alt_root) { + alt_root_len = strlen(alt_root); + } else { + alt_root_len = 0; + } + } } int pathmap_open(const char* name) { - int fd; - char alt_path[PATH_MAX + 1]; + int fd; + char alt_path[PATH_MAX + 1]; - init_alt_root(); - fd = open(name, O_RDONLY); - if (fd >= 0) { + init_alt_root(); + + if (alt_root_len > 0) { + strcpy(alt_path, alt_root); + strcat(alt_path, name); + fd = open(alt_path, O_RDONLY); + if (fd >= 0) { + print_debug("path %s substituted for %s\n", alt_path, name); return fd; - } + } - if (alt_root_len > 0) { + if (strrchr(name, '/')) { strcpy(alt_path, alt_root); - strcat(alt_path, name); + strcat(alt_path, strrchr(name, '/')); fd = open(alt_path, O_RDONLY); if (fd >= 0) { - print_debug("path %s substituted for %s\n", alt_path, name); - return fd; + print_debug("path %s substituted for %s\n", alt_path, name); + return fd; } - - if (strrchr(name, '/')) { - strcpy(alt_path, alt_root); - strcat(alt_path, strrchr(name, '/')); - fd = open(alt_path, O_RDONLY); - if (fd >= 0) { - print_debug("path %s substituted for %s\n", alt_path, name); - return fd; - } - } - } - - return -1; + } + } else { + fd = open(name, O_RDONLY); + if (fd >= 0) { + return fd; + } + } + return -1; } static bool _libsaproc_debug; void print_debug(const char* format,...) { - if (_libsaproc_debug) { - va_list alist; + if (_libsaproc_debug) { + va_list alist; - va_start(alist, format); - fputs("libsaproc DEBUG: ", stderr); - vfprintf(stderr, format, alist); - va_end(alist); - } + va_start(alist, format); + fputs("libsaproc DEBUG: ", stderr); + vfprintf(stderr, format, alist); + va_end(alist); + } } void print_error(const char* format,...) { @@ -100,172 +98,235 @@ void print_error(const char* format,...) { } bool is_debug() { - return _libsaproc_debug; + return _libsaproc_debug; } +#ifdef __APPLE__ +// get arch offset in file +bool get_arch_off(int fd, cpu_type_t cputype, off_t *offset) { + struct fat_header fatheader; + struct fat_arch fatarch; + off_t img_start = 0; + + off_t pos = ltell(fd); + if (read(fd, (void *)&fatheader, sizeof(struct fat_header)) != sizeof(struct fat_header)) { + return false; + } + if (fatheader.magic == FAT_CIGAM) { + int i; + for (i = 0; i < ntohl(fatheader.nfat_arch); i++) { + if (read(fd, (void *)&fatarch, sizeof(struct fat_arch)) != sizeof(struct fat_arch)) { + return false; + } + if (ntohl(fatarch.cputype) == cputype) { + print_debug("fat offset=%x\n", ntohl(fatarch.offset)); + img_start = ntohl(fatarch.offset); + break; + } + } + if (img_start == 0) { + return false; + } + } + lseek(fd, pos, SEEK_SET); + *offset = img_start; + return true; +} + +bool is_macho_file(int fd) { + mach_header_64 fhdr; + off_t x86_64_off; + + if (fd < 0) { + print_debug("Invalid file handle passed to is_macho_file\n"); + return false; + } + + off_t pos = ltell(fd); + // check fat header + if (!get_arch_off(fd, CPU_TYPE_X86_64, &x86_64_off)) { + print_debug("failed to get fat header\n"); + return false; + } + lseek(fd, x86_64_off, SEEK_SET); + if (read(fd, (void *)&fhdr, sizeof(mach_header_64)) != sizeof(mach_header_64)) { + return false; + } + lseek(fd, pos, SEEK_SET); // restore + print_debug("fhdr.magic %x\n", fhdr.magic); + return (fhdr.magic == MH_MAGIC_64 || fhdr.magic == MH_CIGAM_64); +} + +#endif //__APPLE__ + // initialize libproc bool init_libproc(bool debug) { - // init debug mode _libsaproc_debug = debug; - +#ifndef __APPLE__ // initialize the thread_db library if (td_init() != TD_OK) { print_debug("libthread_db's td_init failed\n"); return false; } - +#endif // __APPLE__ return true; } -static void destroy_lib_info(struct ps_prochandle* ph) { - lib_info* lib = ph->libs; - while (lib) { - lib_info *next = lib->next; - if (lib->symtab) { - destroy_symtab(lib->symtab); - } - free(lib); - lib = next; - } +void destroy_lib_info(struct ps_prochandle* ph) { + lib_info* lib = ph->libs; + while (lib) { + lib_info* next = lib->next; + if (lib->symtab) { + destroy_symtab(lib->symtab); + } + free(lib); + lib = next; + } } -static void destroy_thread_info(struct ps_prochandle* ph) { - thread_info* thr = ph->threads; - while (thr) { - thread_info *next = thr->next; - free(thr); - thr = next; - } +void destroy_thread_info(struct ps_prochandle* ph) { + sa_thread_info* thr = ph->threads; + while (thr) { + sa_thread_info* n = thr->next; + free(thr); + thr = n; + } } -// ps_prochandle cleanup - // ps_prochandle cleanup void Prelease(struct ps_prochandle* ph) { - // do the "derived class" clean-up first - ph->ops->release(ph); - destroy_lib_info(ph); - destroy_thread_info(ph); - free(ph); + // do the "derived class" clean-up first + ph->ops->release(ph); + destroy_lib_info(ph); + destroy_thread_info(ph); + free(ph); } lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) { - return add_lib_info_fd(ph, libname, -1, base); + return add_lib_info_fd(ph, libname, -1, base); } lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) { lib_info* newlib; + print_debug("add_lib_info_fd %s\n", libname); - if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) { - print_debug("can't allocate memory for lib_info\n"); - return NULL; - } + if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) { + print_debug("can't allocate memory for lib_info\n"); + return NULL; + } - strncpy(newlib->name, libname, sizeof(newlib->name)); - newlib->base = base; + strncpy(newlib->name, libname, sizeof(newlib->name)); + newlib->base = base; - if (fd == -1) { - if ( (newlib->fd = pathmap_open(newlib->name)) < 0) { - print_debug("can't open shared object %s\n", newlib->name); - free(newlib); - return NULL; - } - } else { - newlib->fd = fd; - } - - // check whether we have got an ELF file. /proc//map - // gives out all file mappings and not just shared objects - if (is_elf_file(newlib->fd) == false) { - close(newlib->fd); + if (fd == -1) { + if ( (newlib->fd = pathmap_open(newlib->name)) < 0) { + print_debug("can't open shared object %s\n", newlib->name); free(newlib); return NULL; - } + } + } else { + newlib->fd = fd; + } - newlib->symtab = build_symtab(newlib->fd); - if (newlib->symtab == NULL) { - print_debug("symbol table build failed for %s\n", newlib->name); - } - else { - print_debug("built symbol table for %s\n", newlib->name); - } +#ifdef __APPLE__ + // check whether we have got an Macho file. + if (is_macho_file(newlib->fd) == false) { + close(newlib->fd); + free(newlib); + print_debug("not a mach-o file\n"); + return NULL; + } +#else + // check whether we have got an ELF file. /proc//map + // gives out all file mappings and not just shared objects + if (is_elf_file(newlib->fd) == false) { + close(newlib->fd); + free(newlib); + return NULL; + } +#endif // __APPLE__ - // even if symbol table building fails, we add the lib_info. - // This is because we may need to read from the ELF file for core file - // address read functionality. lookup_symbol checks for NULL symtab. - if (ph->libs) { - ph->lib_tail->next = newlib; - ph->lib_tail = newlib; - } else { - ph->libs = ph->lib_tail = newlib; - } - ph->num_libs++; + newlib->symtab = build_symtab(newlib->fd); + if (newlib->symtab == NULL) { + print_debug("symbol table build failed for %s\n", newlib->name); + } else { + print_debug("built symbol table for %s\n", newlib->name); + } - return newlib; + // even if symbol table building fails, we add the lib_info. + // This is because we may need to read from the ELF file or MachO file for core file + // address read functionality. lookup_symbol checks for NULL symtab. + if (ph->libs) { + ph->lib_tail->next = newlib; + ph->lib_tail = newlib; + } else { + ph->libs = ph->lib_tail = newlib; + } + ph->num_libs++; + return newlib; } // lookup for a specific symbol uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name, const char* sym_name) { - // ignore object_name. search in all libraries - // FIXME: what should we do with object_name?? The library names are obtained - // by parsing /proc//maps, which may not be the same as object_name. - // What we need is a utility to map object_name to real file name, something - // dlopen() does by looking at LD_LIBRARY_PATH and /etc/ld.so.cache. For - // now, we just ignore object_name and do a global search for the symbol. + // ignore object_name. search in all libraries + // FIXME: what should we do with object_name?? The library names are obtained + // by parsing /proc//maps, which may not be the same as object_name. + // What we need is a utility to map object_name to real file name, something + // dlopen() does by looking at LD_LIBRARY_PATH and /etc/ld.so.cache. For + // now, we just ignore object_name and do a global search for the symbol. - lib_info* lib = ph->libs; - while (lib) { - if (lib->symtab) { - uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL); - if (res) return res; - } - lib = lib->next; - } + lib_info* lib = ph->libs; + while (lib) { + if (lib->symtab) { + uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL); + if (res) return res; + } + lib = lib->next; + } - print_debug("lookup failed for symbol '%s' in obj '%s'\n", + print_debug("lookup failed for symbol '%s' in obj '%s'\n", sym_name, object_name); - return (uintptr_t) NULL; + return (uintptr_t) NULL; } - const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset) { - const char* res = NULL; - lib_info* lib = ph->libs; - while (lib) { - if (lib->symtab && addr >= lib->base) { - res = nearest_symbol(lib->symtab, addr - lib->base, poffset); - if (res) return res; - } - lib = lib->next; - } - return NULL; + const char* res = NULL; + lib_info* lib = ph->libs; + while (lib) { + if (lib->symtab && addr >= lib->base) { + res = nearest_symbol(lib->symtab, addr - lib->base, poffset); + if (res) return res; + } + lib = lib->next; + } + return NULL; } // add a thread to ps_prochandle -thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) { - thread_info* newthr; - if ( (newthr = (thread_info*) calloc(1, sizeof(thread_info))) == NULL) { - print_debug("can't allocate memory for thread_info\n"); - return NULL; - } +sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) { + sa_thread_info* newthr; + if ( (newthr = (sa_thread_info*) calloc(1, sizeof(sa_thread_info))) == NULL) { + print_debug("can't allocate memory for thread_info\n"); + return NULL; + } - // initialize thread info - newthr->pthread_id = pthread_id; - newthr->lwp_id = lwp_id; + // initialize thread info + newthr->pthread_id = pthread_id; + newthr->lwp_id = lwp_id; - // add new thread to the list - newthr->next = ph->threads; - ph->threads = newthr; - ph->num_threads++; - return newthr; + // add new thread to the list + newthr->next = ph->threads; + ph->threads = newthr; + ph->num_threads++; + return newthr; } - +#ifndef __APPLE__ // struct used for client data from thread_db callback struct thread_db_client_data { - struct ps_prochandle* ph; - thread_info_callback callback; + struct ps_prochandle* ph; + thread_info_callback callback; }; // callback function for libthread_db @@ -314,6 +375,7 @@ bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb) { return true; } +#endif // __APPLE__ // get number of threads int get_num_threads(struct ps_prochandle* ph) { @@ -322,18 +384,54 @@ int get_num_threads(struct ps_prochandle* ph) { // get lwp_id of n'th thread lwpid_t get_lwp_id(struct ps_prochandle* ph, int index) { - int count = 0; - thread_info* thr = ph->threads; - while (thr) { - if (count == index) { - return thr->lwp_id; - } - count++; - thr = thr->next; - } - return -1; + int count = 0; + sa_thread_info* thr = ph->threads; + while (thr) { + if (count == index) { + return thr->lwp_id; + } + count++; + thr = thr->next; + } + return 0; } +#ifdef __APPLE__ +// set lwp_id of n'th thread +bool set_lwp_id(struct ps_prochandle* ph, int index, lwpid_t lwpid) { + int count = 0; + sa_thread_info* thr = ph->threads; + while (thr) { + if (count == index) { + thr->lwp_id = lwpid; + return true; + } + count++; + thr = thr->next; + } + return false; +} + +// get regs of n-th thread, only used in fillThreads the first time called +bool get_nth_lwp_regs(struct ps_prochandle* ph, int index, struct reg* regs) { + int count = 0; + sa_thread_info* thr = ph->threads; + while (thr) { + if (count == index) { + break; + } + count++; + thr = thr->next; + } + if (thr != NULL) { + memcpy(regs, &thr->regs, sizeof(struct reg)); + return true; + } + return false; +} + +#endif // __APPLE__ + // get regs for a given lwp bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) { return ph->ops->get_lwp_regs(ph, lwp_id, regs); @@ -341,35 +439,35 @@ bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) { // get number of shared objects int get_num_libs(struct ps_prochandle* ph) { - return ph->num_libs; + return ph->num_libs; } // get name of n'th solib const char* get_lib_name(struct ps_prochandle* ph, int index) { - int count = 0; - lib_info* lib = ph->libs; - while (lib) { - if (count == index) { - return lib->name; - } - count++; - lib = lib->next; - } - return NULL; + int count = 0; + lib_info* lib = ph->libs; + while (lib) { + if (count == index) { + return lib->name; + } + count++; + lib = lib->next; + } + return NULL; } // get base address of a lib uintptr_t get_lib_base(struct ps_prochandle* ph, int index) { - int count = 0; - lib_info* lib = ph->libs; - while (lib) { - if (count == index) { - return lib->base; - } - count++; - lib = lib->next; - } - return (uintptr_t)NULL; + int count = 0; + lib_info* lib = ph->libs; + while (lib) { + if (count == index) { + return lib->base; + } + count++; + lib = lib->next; + } + return (uintptr_t)NULL; } bool find_lib(struct ps_prochandle* ph, const char *lib_name) { @@ -425,6 +523,7 @@ ps_plog (const char *format, ...) va_end(alist); } +#ifndef __APPLE__ // ------------------------------------------------------------------------ // Functions below this point are not yet implemented. They are here only // to make the linker happy. @@ -458,3 +557,4 @@ ps_err_e ps_pcontinue(struct ps_prochandle *ph) { print_debug("ps_pcontinue not implemented\n"); return PS_OK; } +#endif // __APPLE__ diff --git a/hotspot/agent/src/os/bsd/libproc_impl.h b/hotspot/agent/src/os/bsd/libproc_impl.h index 12326c17fd4..b5cec4d39cf 100644 --- a/hotspot/agent/src/os/bsd/libproc_impl.h +++ b/hotspot/agent/src/os/bsd/libproc_impl.h @@ -30,6 +30,60 @@ #include "libproc.h" #include "symtab.h" +#ifdef __APPLE__ +#include // for PRIx64, 32, ... +#include +#include +#include +#include + +#ifndef register_t +#define register_t uint64_t +#endif + +/*** registers copied from bsd/amd64 */ +typedef struct reg { + register_t r_r15; + register_t r_r14; + register_t r_r13; + register_t r_r12; + register_t r_r11; + register_t r_r10; + register_t r_r9; + register_t r_r8; + register_t r_rdi; + register_t r_rsi; + register_t r_rbp; + register_t r_rbx; + register_t r_rdx; + register_t r_rcx; + register_t r_rax; + uint32_t r_trapno; // not used + uint16_t r_fs; + uint16_t r_gs; + uint32_t r_err; // not used + uint16_t r_es; // not used + uint16_t r_ds; // not used + register_t r_rip; + register_t r_cs; + register_t r_rflags; + register_t r_rsp; + register_t r_ss; // not used +} reg; + +// convenient defs +typedef struct mach_header_64 mach_header_64; +typedef struct load_command load_command; +typedef struct segment_command_64 segment_command_64; +typedef struct thread_command thread_command; +typedef struct dylib_command dylib_command; +typedef struct symtab_command symtab_command; +typedef struct nlist_64 nlist_64; +#else +#include +#include "salibelf.h" +#endif // __APPLE__ + // data structures in this file mimic those of Solaris 8.0 - libproc's Pcontrol.h #define BUF_SIZE (PATH_MAX + NAME_MAX + 1) @@ -44,12 +98,12 @@ typedef struct lib_info { } lib_info; // list of threads -typedef struct thread_info { - lwpid_t lwp_id; - pthread_t pthread_id; // not used cores, always -1 +typedef struct sa_thread_info { + lwpid_t lwp_id; // same as pthread_t + pthread_t pthread_id; // struct reg regs; // not for process, core uses for caching regset - struct thread_info* next; -} thread_info; + struct sa_thread_info* next; +} sa_thread_info; // list of virtual memory maps typedef struct map_info { @@ -91,6 +145,7 @@ struct core_data { // part of the class sharing workaround map_info* class_share_maps;// class share maps in a linked list map_info** map_array; // sorted (by vaddr) array of map_info pointers + char exec_path[4096]; // file name java }; struct ps_prochandle { @@ -100,12 +155,11 @@ struct ps_prochandle { lib_info* libs; // head of lib list lib_info* lib_tail; // tail of lib list - to append at the end int num_threads; - thread_info* threads; // head of thread list + sa_thread_info* threads; // head of thread list struct core_data* core; // data only used for core dumps, NULL for process }; int pathmap_open(const char* name); - void print_debug(const char* format,...); void print_error(const char* format,...); bool is_debug(); @@ -122,10 +176,45 @@ lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base); -// adds a new thread to threads list, returns NULL on failure -thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id); - +sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id); // a test for ELF signature without using libelf -bool is_elf_file(int fd); +#ifdef __APPLE__ +// a test for Mach-O signature +bool is_macho_file(int fd); +// skip fat head to get image start offset of cpu_type_t +// return false if any error happens, else value in offset. +bool get_arch_off(int fd, cpu_type_t cputype, off_t *offset); +#else +bool is_elf_file(int fd); +#endif // __APPLE__ + +lwpid_t get_lwp_id(struct ps_prochandle* ph, int index); +bool set_lwp_id(struct ps_prochandle* ph, int index, lwpid_t lwpid); +bool get_nth_lwp_regs(struct ps_prochandle* ph, int index, struct reg* regs); + +// ps_pglobal_lookup() looks up the symbol sym_name in the symbol table +// of the load object object_name in the target process identified by ph. +// It returns the symbol's value as an address in the target process in +// *sym_addr. + +ps_err_e ps_pglobal_lookup(struct ps_prochandle *ph, const char *object_name, + const char *sym_name, psaddr_t *sym_addr); + +// read "size" bytes info "buf" from address "addr" +ps_err_e ps_pread(struct ps_prochandle *ph, psaddr_t addr, + void *buf, size_t size); + +// write "size" bytes of data to debuggee at address "addr" +ps_err_e ps_pwrite(struct ps_prochandle *ph, psaddr_t addr, + const void *buf, size_t size); + +// fill in ptrace_lwpinfo for lid +ps_err_e ps_linfo(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo); + +// needed for when libthread_db is compiled with TD_DEBUG defined +void ps_plog (const char *format, ...); + +// untility, tells the position in file +off_t ltell(int fd); #endif //_LIBPROC_IMPL_H_ diff --git a/hotspot/agent/src/os/bsd/ps_core.c b/hotspot/agent/src/os/bsd/ps_core.c index b00a03c5704..974e01a6ab4 100644 --- a/hotspot/agent/src/os/bsd/ps_core.c +++ b/hotspot/agent/src/os/bsd/ps_core.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,10 +28,11 @@ #include #include #include -#include -#include #include "libproc_impl.h" -#include "salibelf.h" + +#ifdef __APPLE__ +#include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h" +#endif // This file has the libproc implementation to read core files. // For live processes, refer to ps_proc.c. Portions of this is adapted @@ -41,156 +42,158 @@ // ps_prochandle cleanup helper functions // close all file descriptors -static void close_elf_files(struct ps_prochandle* ph) { - lib_info* lib = NULL; +static void close_files(struct ps_prochandle* ph) { + lib_info* lib = NULL; + // close core file descriptor + if (ph->core->core_fd >= 0) + close(ph->core->core_fd); - // close core file descriptor - if (ph->core->core_fd >= 0) - close(ph->core->core_fd); + // close exec file descriptor + if (ph->core->exec_fd >= 0) + close(ph->core->exec_fd); - // close exec file descriptor - if (ph->core->exec_fd >= 0) - close(ph->core->exec_fd); + // close interp file descriptor + if (ph->core->interp_fd >= 0) + close(ph->core->interp_fd); - // close interp file descriptor - if (ph->core->interp_fd >= 0) - close(ph->core->interp_fd); + // close class share archive file + if (ph->core->classes_jsa_fd >= 0) + close(ph->core->classes_jsa_fd); - // close class share archive file - if (ph->core->classes_jsa_fd >= 0) - close(ph->core->classes_jsa_fd); - - // close all library file descriptors - lib = ph->libs; - while (lib) { - int fd = lib->fd; - if (fd >= 0 && fd != ph->core->exec_fd) close(fd); - lib = lib->next; - } + // close all library file descriptors + lib = ph->libs; + while (lib) { + int fd = lib->fd; + if (fd >= 0 && fd != ph->core->exec_fd) { + close(fd); + } + lib = lib->next; + } } // clean all map_info stuff static void destroy_map_info(struct ps_prochandle* ph) { map_info* map = ph->core->maps; while (map) { - map_info* next = map->next; - free(map); - map = next; + map_info* next = map->next; + free(map); + map = next; } if (ph->core->map_array) { - free(ph->core->map_array); + free(ph->core->map_array); } // Part of the class sharing workaround map = ph->core->class_share_maps; while (map) { - map_info* next = map->next; - free(map); - map = next; + map_info* next = map->next; + free(map); + map = next; } } // ps_prochandle operations static void core_release(struct ps_prochandle* ph) { - if (ph->core) { - close_elf_files(ph); - destroy_map_info(ph); - free(ph->core); - } + if (ph->core) { + close_files(ph); + destroy_map_info(ph); + free(ph->core); + } } static map_info* allocate_init_map(int fd, off_t offset, uintptr_t vaddr, size_t memsz) { - map_info* map; - if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL) { - print_debug("can't allocate memory for map_info\n"); - return NULL; - } + map_info* map; + if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL) { + print_debug("can't allocate memory for map_info\n"); + return NULL; + } - // initialize map - map->fd = fd; - map->offset = offset; - map->vaddr = vaddr; - map->memsz = memsz; - return map; + // initialize map + map->fd = fd; + map->offset = offset; + map->vaddr = vaddr; + map->memsz = memsz; + return map; } // add map info with given fd, offset, vaddr and memsz static map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset, uintptr_t vaddr, size_t memsz) { - map_info* map; - if ((map = allocate_init_map(fd, offset, vaddr, memsz)) == NULL) { - return NULL; - } + map_info* map; + if ((map = allocate_init_map(fd, offset, vaddr, memsz)) == NULL) { + return NULL; + } - // add this to map list - map->next = ph->core->maps; - ph->core->maps = map; - ph->core->num_maps++; + // add this to map list + map->next = ph->core->maps; + ph->core->maps = map; + ph->core->num_maps++; - return map; + return map; } // Part of the class sharing workaround static map_info* add_class_share_map_info(struct ps_prochandle* ph, off_t offset, uintptr_t vaddr, size_t memsz) { - map_info* map; - if ((map = allocate_init_map(ph->core->classes_jsa_fd, - offset, vaddr, memsz)) == NULL) { - return NULL; - } + map_info* map; + if ((map = allocate_init_map(ph->core->classes_jsa_fd, + offset, vaddr, memsz)) == NULL) { + return NULL; + } - map->next = ph->core->class_share_maps; - ph->core->class_share_maps = map; - return map; + map->next = ph->core->class_share_maps; + ph->core->class_share_maps = map; + return map; } // Return the map_info for the given virtual address. We keep a sorted // array of pointers in ph->map_array, so we can binary search. static map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr) { - int mid, lo = 0, hi = ph->core->num_maps - 1; - map_info *mp; + int mid, lo = 0, hi = ph->core->num_maps - 1; + map_info *mp; - while (hi - lo > 1) { - mid = (lo + hi) / 2; - if (addr >= ph->core->map_array[mid]->vaddr) - lo = mid; - else - hi = mid; - } + while (hi - lo > 1) { + mid = (lo + hi) / 2; + if (addr >= ph->core->map_array[mid]->vaddr) { + lo = mid; + } else { + hi = mid; + } + } - if (addr < ph->core->map_array[hi]->vaddr) - mp = ph->core->map_array[lo]; - else - mp = ph->core->map_array[hi]; + if (addr < ph->core->map_array[hi]->vaddr) { + mp = ph->core->map_array[lo]; + } else { + mp = ph->core->map_array[hi]; + } - if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) + if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) { + return (mp); + } + + + // Part of the class sharing workaround + // Unfortunately, we have no way of detecting -Xshare state. + // Check out the share maps atlast, if we don't find anywhere. + // This is done this way so to avoid reading share pages + // ahead of other normal maps. For eg. with -Xshare:off we don't + // want to prefer class sharing data to data from core. + mp = ph->core->class_share_maps; + if (mp) { + print_debug("can't locate map_info at 0x%lx, trying class share maps\n", addr); + } + while (mp) { + if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) { + print_debug("located map_info at 0x%lx from class share maps\n", addr); return (mp); + } + mp = mp->next; + } - - // Part of the class sharing workaround - // Unfortunately, we have no way of detecting -Xshare state. - // Check out the share maps atlast, if we don't find anywhere. - // This is done this way so to avoid reading share pages - // ahead of other normal maps. For eg. with -Xshare:off we don't - // want to prefer class sharing data to data from core. - mp = ph->core->class_share_maps; - if (mp) { - print_debug("can't locate map_info at 0x%lx, trying class share maps\n", - addr); - } - while (mp) { - if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) { - print_debug("located map_info at 0x%lx from class share maps\n", - addr); - return (mp); - } - mp = mp->next; - } - - print_debug("can't locate map_info at 0x%lx\n", addr); - return (NULL); + print_debug("can't locate map_info at 0x%lx\n", addr); + return (NULL); } //--------------------------------------------------------------- @@ -239,156 +242,170 @@ struct FileMapHeader { }; static bool read_jboolean(struct ps_prochandle* ph, uintptr_t addr, jboolean* pvalue) { - jboolean i; - if (ps_pread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) { - *pvalue = i; - return true; - } else { - return false; - } + jboolean i; + if (ps_pread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) { + *pvalue = i; + return true; + } else { + return false; + } } static bool read_pointer(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* pvalue) { - uintptr_t uip; - if (ps_pread(ph, (psaddr_t) addr, &uip, sizeof(uip)) == PS_OK) { - *pvalue = uip; - return true; - } else { - return false; - } + uintptr_t uip; + if (ps_pread(ph, (psaddr_t) addr, (char *)&uip, sizeof(uip)) == PS_OK) { + *pvalue = uip; + return true; + } else { + return false; + } } // used to read strings from debuggee static bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t size) { - size_t i = 0; - char c = ' '; + size_t i = 0; + char c = ' '; - while (c != '\0') { - if (ps_pread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK) - return false; - if (i < size - 1) - buf[i] = c; - else // smaller buffer - return false; - i++; addr++; - } - - buf[i] = '\0'; - return true; + while (c != '\0') { + if (ps_pread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK) { + return false; + } + if (i < size - 1) { + buf[i] = c; + } else { + // smaller buffer + return false; + } + i++; addr++; + } + buf[i] = '\0'; + return true; } -#define USE_SHARED_SPACES_SYM "UseSharedSpaces" +#ifdef __APPLE__ +#define USE_SHARED_SPACES_SYM "_UseSharedSpaces" // mangled name of Arguments::SharedArchivePath #define SHARED_ARCHIVE_PATH_SYM "_ZN9Arguments17SharedArchivePathE" +#else +#define USE_SHARED_SPACES_SYM "UseSharedSpaces" +// mangled name of Arguments::SharedArchivePath +#define SHARED_ARCHIVE_PATH_SYM "__ZN9Arguments17SharedArchivePathE" +#endif // __APPLE_ static bool init_classsharing_workaround(struct ps_prochandle* ph) { - lib_info* lib = ph->libs; - while (lib != NULL) { - // we are iterating over shared objects from the core dump. look for - // libjvm[_g].so. - const char *jvm_name = 0; - if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0 || - (jvm_name = strstr(lib->name, "/libjvm_g.so")) != 0) { - char classes_jsa[PATH_MAX]; - struct FileMapHeader header; - size_t n = 0; - int fd = -1, m = 0; - uintptr_t base = 0, useSharedSpacesAddr = 0; - uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0; - jboolean useSharedSpaces = 0; + int m; + size_t n; + lib_info* lib = ph->libs; + while (lib != NULL) { + // we are iterating over shared objects from the core dump. look for + // libjvm[_g].so. + const char *jvm_name = 0; +#ifdef __APPLE__ + if ((jvm_name = strstr(lib->name, "/libjvm.dylib")) != 0 || + (jvm_name = strstr(lib->name, "/libjvm_g.dylib")) != 0) +#else + if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0 || + (jvm_name = strstr(lib->name, "/libjvm_g.so")) != 0) +#endif // __APPLE__ + { + char classes_jsa[PATH_MAX]; + struct FileMapHeader header; + int fd = -1; + uintptr_t base = 0, useSharedSpacesAddr = 0; + uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0; + jboolean useSharedSpaces = 0; - memset(classes_jsa, 0, sizeof(classes_jsa)); - jvm_name = lib->name; - useSharedSpacesAddr = lookup_symbol(ph, jvm_name, USE_SHARED_SPACES_SYM); - if (useSharedSpacesAddr == 0) { - print_debug("can't lookup 'UseSharedSpaces' flag\n"); - return false; - } - - // Hotspot vm types are not exported to build this library. So - // using equivalent type jboolean to read the value of - // UseSharedSpaces which is same as hotspot type "bool". - if (read_jboolean(ph, useSharedSpacesAddr, &useSharedSpaces) != true) { - print_debug("can't read the value of 'UseSharedSpaces' flag\n"); - return false; - } - - if ((int)useSharedSpaces == 0) { - print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n"); - return true; - } - - sharedArchivePathAddrAddr = lookup_symbol(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM); - if (sharedArchivePathAddrAddr == 0) { - print_debug("can't lookup shared archive path symbol\n"); - return false; - } - - if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) { - print_debug("can't read shared archive path pointer\n"); - return false; - } - - if (read_string(ph, sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) { - print_debug("can't read shared archive path value\n"); - return false; - } - - print_debug("looking for %s\n", classes_jsa); - // open the class sharing archive file - fd = pathmap_open(classes_jsa); - if (fd < 0) { - print_debug("can't open %s!\n", classes_jsa); - ph->core->classes_jsa_fd = -1; - return false; - } else { - print_debug("opened %s\n", classes_jsa); - } - - // read FileMapHeader from the file - memset(&header, 0, sizeof(struct FileMapHeader)); - if ((n = read(fd, &header, sizeof(struct FileMapHeader))) - != sizeof(struct FileMapHeader)) { - print_debug("can't read shared archive file map header from %s\n", classes_jsa); - close(fd); - return false; - } - - // check file magic - if (header._magic != 0xf00baba2) { - print_debug("%s has bad shared archive file magic number 0x%x, expecing 0xf00baba2\n", - classes_jsa, header._magic); - close(fd); - return false; - } - - // check version - if (header._version != CURRENT_ARCHIVE_VERSION) { - print_debug("%s has wrong shared archive file version %d, expecting %d\n", - classes_jsa, header._version, CURRENT_ARCHIVE_VERSION); - close(fd); - return false; - } - - ph->core->classes_jsa_fd = fd; - // add read-only maps from classes[_g].jsa to the list of maps - for (m = 0; m < NUM_SHARED_MAPS; m++) { - if (header._space[m]._read_only) { - base = (uintptr_t) header._space[m]._base; - // no need to worry about the fractional pages at-the-end. - // possible fractional pages are handled by core_read_data. - add_class_share_map_info(ph, (off_t) header._space[m]._file_offset, - base, (size_t) header._space[m]._used); - print_debug("added a share archive map at 0x%lx\n", base); - } - } - return true; + memset(classes_jsa, 0, sizeof(classes_jsa)); + jvm_name = lib->name; + useSharedSpacesAddr = lookup_symbol(ph, jvm_name, USE_SHARED_SPACES_SYM); + if (useSharedSpacesAddr == 0) { + print_debug("can't lookup 'UseSharedSpaces' flag\n"); + return false; } - lib = lib->next; - } - return true; -} + // Hotspot vm types are not exported to build this library. So + // using equivalent type jboolean to read the value of + // UseSharedSpaces which is same as hotspot type "bool". + if (read_jboolean(ph, useSharedSpacesAddr, &useSharedSpaces) != true) { + print_debug("can't read the value of 'UseSharedSpaces' flag\n"); + return false; + } + + if ((int)useSharedSpaces == 0) { + print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n"); + return true; + } + + sharedArchivePathAddrAddr = lookup_symbol(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM); + if (sharedArchivePathAddrAddr == 0) { + print_debug("can't lookup shared archive path symbol\n"); + return false; + } + + if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) { + print_debug("can't read shared archive path pointer\n"); + return false; + } + + if (read_string(ph, sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) { + print_debug("can't read shared archive path value\n"); + return false; + } + + print_debug("looking for %s\n", classes_jsa); + // open the class sharing archive file + fd = pathmap_open(classes_jsa); + if (fd < 0) { + print_debug("can't open %s!\n", classes_jsa); + ph->core->classes_jsa_fd = -1; + return false; + } else { + print_debug("opened %s\n", classes_jsa); + } + + // read FileMapHeader from the file + memset(&header, 0, sizeof(struct FileMapHeader)); + if ((n = read(fd, &header, sizeof(struct FileMapHeader))) + != sizeof(struct FileMapHeader)) { + print_debug("can't read shared archive file map header from %s\n", classes_jsa); + close(fd); + return false; + } + + // check file magic + if (header._magic != 0xf00baba2) { + print_debug("%s has bad shared archive file magic number 0x%x, expecing 0xf00baba2\n", + classes_jsa, header._magic); + close(fd); + return false; + } + + // check version + if (header._version != CURRENT_ARCHIVE_VERSION) { + print_debug("%s has wrong shared archive file version %d, expecting %d\n", + classes_jsa, header._version, CURRENT_ARCHIVE_VERSION); + close(fd); + return false; + } + + ph->core->classes_jsa_fd = fd; + // add read-only maps from classes[_g].jsa to the list of maps + for (m = 0; m < NUM_SHARED_MAPS; m++) { + if (header._space[m]._read_only) { + base = (uintptr_t) header._space[m]._base; + // no need to worry about the fractional pages at-the-end. + // possible fractional pages are handled by core_read_data. + add_class_share_map_info(ph, (off_t) header._space[m]._file_offset, + base, (size_t) header._space[m]._used); + print_debug("added a share archive map at 0x%lx\n", base); + } + } + return true; + } + lib = lib->next; + } + return true; +} //--------------------------------------------------------------------------- // functions to handle map_info @@ -397,54 +414,57 @@ static bool init_classsharing_workaround(struct ps_prochandle* ph) { // callback for sorting the array of map_info pointers. static int core_cmp_mapping(const void *lhsp, const void *rhsp) { - const map_info *lhs = *((const map_info **)lhsp); - const map_info *rhs = *((const map_info **)rhsp); + const map_info *lhs = *((const map_info **)lhsp); + const map_info *rhs = *((const map_info **)rhsp); - if (lhs->vaddr == rhs->vaddr) - return (0); + if (lhs->vaddr == rhs->vaddr) { + return (0); + } - return (lhs->vaddr < rhs->vaddr ? -1 : 1); + return (lhs->vaddr < rhs->vaddr ? -1 : 1); } // we sort map_info by starting virtual address so that we can do // binary search to read from an address. static bool sort_map_array(struct ps_prochandle* ph) { - size_t num_maps = ph->core->num_maps; - map_info* map = ph->core->maps; - int i = 0; + size_t num_maps = ph->core->num_maps; + map_info* map = ph->core->maps; + int i = 0; - // allocate map_array - map_info** array; - if ( (array = (map_info**) malloc(sizeof(map_info*) * num_maps)) == NULL) { - print_debug("can't allocate memory for map array\n"); - return false; - } + // allocate map_array + map_info** array; + if ( (array = (map_info**) malloc(sizeof(map_info*) * num_maps)) == NULL) { + print_debug("can't allocate memory for map array\n"); + return false; + } - // add maps to array - while (map) { - array[i] = map; - i++; - map = map->next; - } + // add maps to array + while (map) { + array[i] = map; + i++; + map = map->next; + } - // sort is called twice. If this is second time, clear map array - if (ph->core->map_array) free(ph->core->map_array); - ph->core->map_array = array; - // sort the map_info array by base virtual address. - qsort(ph->core->map_array, ph->core->num_maps, sizeof (map_info*), - core_cmp_mapping); + // sort is called twice. If this is second time, clear map array + if (ph->core->map_array) { + free(ph->core->map_array); + } + ph->core->map_array = array; + // sort the map_info array by base virtual address. + qsort(ph->core->map_array, ph->core->num_maps, sizeof (map_info*), + core_cmp_mapping); - // print map - if (is_debug()) { - int j = 0; - print_debug("---- sorted virtual address map ----\n"); - for (j = 0; j < ph->core->num_maps; j++) { - print_debug("base = 0x%lx\tsize = %d\n", ph->core->map_array[j]->vaddr, - ph->core->map_array[j]->memsz); - } - } + // print map + if (is_debug()) { + int j = 0; + print_debug("---- sorted virtual address map ----\n"); + for (j = 0; j < ph->core->num_maps; j++) { + print_debug("base = 0x%lx\tsize = %d\n", ph->core->map_array[j]->vaddr, + ph->core->map_array[j]->memsz); + } + } - return true; + return true; } #ifndef MIN @@ -461,16 +481,18 @@ static bool core_read_data(struct ps_prochandle* ph, uintptr_t addr, char *buf, off_t off; int fd; - if (mp == NULL) + if (mp == NULL) { break; /* No mapping for this address */ + } fd = mp->fd; mapoff = addr - mp->vaddr; len = MIN(resid, mp->memsz - mapoff); off = mp->offset + mapoff; - if ((len = pread(fd, buf, len, off)) <= 0) + if ((len = pread(fd, buf, len, off)) <= 0) { break; + } resid -= len; addr += len; @@ -507,8 +529,8 @@ static bool core_write_data(struct ps_prochandle* ph, static bool core_get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) { - // for core we have cached the lwp regs from NOTE section - thread_info* thr = ph->threads; + // for core we have cached the lwp regs after segment parsed + sa_thread_info* thr = ph->threads; while (thr) { if (thr->lwp_id == lwp_id) { memcpy(regs, &thr->regs, sizeof(struct reg)); @@ -519,7 +541,7 @@ static bool core_get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, return false; } -static bool core_get_lwp_info(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo) { +static bool core_get_lwp_info(struct ps_prochandle *ph, lwpid_t id, void *info) { print_debug("core_get_lwp_info not implemented\n"); return false; } @@ -532,12 +554,451 @@ static ps_prochandle_ops core_ops = { .get_lwp_info= core_get_lwp_info }; -// read regs and create thread from NT_PRSTATUS entries from core file +// from this point, mainly two blocks divided by def __APPLE__ +// one for Macosx, the other for regular Bsd + +#ifdef __APPLE__ + +void print_thread(sa_thread_info *threadinfo) { + print_debug("thread added: %d\n", threadinfo->lwp_id); + print_debug("registers:\n"); + print_debug(" r_r15: 0x%" PRIx64 "\n", threadinfo->regs.r_r15); + print_debug(" r_r14: 0x%" PRIx64 "\n", threadinfo->regs.r_r14); + print_debug(" r_r13: 0x%" PRIx64 "\n", threadinfo->regs.r_r13); + print_debug(" r_r12: 0x%" PRIx64 "\n", threadinfo->regs.r_r12); + print_debug(" r_r11: 0x%" PRIx64 "\n", threadinfo->regs.r_r11); + print_debug(" r_r10: 0x%" PRIx64 "\n", threadinfo->regs.r_r10); + print_debug(" r_r9: 0x%" PRIx64 "\n", threadinfo->regs.r_r9); + print_debug(" r_r8: 0x%" PRIx64 "\n", threadinfo->regs.r_r8); + print_debug(" r_rdi: 0x%" PRIx64 "\n", threadinfo->regs.r_rdi); + print_debug(" r_rsi: 0x%" PRIx64 "\n", threadinfo->regs.r_rsi); + print_debug(" r_rbp: 0x%" PRIx64 "\n", threadinfo->regs.r_rbp); + print_debug(" r_rbx: 0x%" PRIx64 "\n", threadinfo->regs.r_rbx); + print_debug(" r_rdx: 0x%" PRIx64 "\n", threadinfo->regs.r_rdx); + print_debug(" r_rcx: 0x%" PRIx64 "\n", threadinfo->regs.r_rcx); + print_debug(" r_rax: 0x%" PRIx64 "\n", threadinfo->regs.r_rax); + print_debug(" r_fs: 0x%" PRIx32 "\n", threadinfo->regs.r_fs); + print_debug(" r_gs: 0x%" PRIx32 "\n", threadinfo->regs.r_gs); + print_debug(" r_rip 0x%" PRIx64 "\n", threadinfo->regs.r_rip); + print_debug(" r_cs: 0x%" PRIx64 "\n", threadinfo->regs.r_cs); + print_debug(" r_rsp: 0x%" PRIx64 "\n", threadinfo->regs.r_rsp); + print_debug(" r_rflags: 0x%" PRIx64 "\n", threadinfo->regs.r_rflags); +} + +// read all segments64 commands from core file +// read all thread commands from core file +static bool read_core_segments(struct ps_prochandle* ph) { + int i = 0; + int num_threads = 0; + int fd = ph->core->core_fd; + off_t offset = 0; + mach_header_64 fhead; + load_command lcmd; + segment_command_64 segcmd; + // thread_command thrcmd; + + lseek(fd, offset, SEEK_SET); + if(read(fd, (void *)&fhead, sizeof(mach_header_64)) != sizeof(mach_header_64)) { + goto err; + } + print_debug("total commands: %d\n", fhead.ncmds); + offset += sizeof(mach_header_64); + for (i = 0; i < fhead.ncmds; i++) { + lseek(fd, offset, SEEK_SET); + if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) { + goto err; + } + offset += lcmd.cmdsize; // next command position + if (lcmd.cmd == LC_SEGMENT_64) { + lseek(fd, -sizeof(load_command), SEEK_CUR); + if (read(fd, (void *)&segcmd, sizeof(segment_command_64)) != sizeof(segment_command_64)) { + print_debug("failed to read LC_SEGMENT_64 i = %d!\n", i); + goto err; + } + if (add_map_info(ph, fd, segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize) == NULL) { + print_debug("Failed to add map_info at i = %d\n", i); + goto err; + } + print_debug("segment added: %" PRIu64 " 0x%" PRIx64 " %d\n", + segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize); + } else if (lcmd.cmd == LC_THREAD || lcmd.cmd == LC_UNIXTHREAD) { + typedef struct thread_fc { + uint32_t flavor; + uint32_t count; + } thread_fc; + thread_fc fc; + uint32_t size = sizeof(load_command); + while (size < lcmd.cmdsize) { + if (read(fd, (void *)&fc, sizeof(thread_fc)) != sizeof(thread_fc)) { + printf("Reading flavor, count failed.\n"); + goto err; + } + size += sizeof(thread_fc); + if (fc.flavor == x86_THREAD_STATE) { + x86_thread_state_t thrstate; + if (read(fd, (void *)&thrstate, sizeof(x86_thread_state_t)) != sizeof(x86_thread_state_t)) { + printf("Reading flavor, count failed.\n"); + goto err; + } + size += sizeof(x86_thread_state_t); + // create thread info list, update lwp_id later + sa_thread_info* newthr = add_thread_info(ph, (pthread_t) -1, (lwpid_t) num_threads++); + if (newthr == NULL) { + printf("create thread_info failed\n"); + goto err; + } + + // note __DARWIN_UNIX03 depengs on other definitions +#if __DARWIN_UNIX03 +#define get_register_v(regst, regname) \ + regst.uts.ts64.__##regname +#else +#define get_register_v(regst, regname) \ + regst.uts.ts64.##regname +#endif // __DARWIN_UNIX03 + newthr->regs.r_rax = get_register_v(thrstate, rax); + newthr->regs.r_rbx = get_register_v(thrstate, rbx); + newthr->regs.r_rcx = get_register_v(thrstate, rcx); + newthr->regs.r_rdx = get_register_v(thrstate, rdx); + newthr->regs.r_rdi = get_register_v(thrstate, rdi); + newthr->regs.r_rsi = get_register_v(thrstate, rsi); + newthr->regs.r_rbp = get_register_v(thrstate, rbp); + newthr->regs.r_rsp = get_register_v(thrstate, rsp); + newthr->regs.r_r8 = get_register_v(thrstate, r8); + newthr->regs.r_r9 = get_register_v(thrstate, r9); + newthr->regs.r_r10 = get_register_v(thrstate, r10); + newthr->regs.r_r11 = get_register_v(thrstate, r11); + newthr->regs.r_r12 = get_register_v(thrstate, r12); + newthr->regs.r_r13 = get_register_v(thrstate, r13); + newthr->regs.r_r14 = get_register_v(thrstate, r14); + newthr->regs.r_r15 = get_register_v(thrstate, r15); + newthr->regs.r_rip = get_register_v(thrstate, rip); + newthr->regs.r_rflags = get_register_v(thrstate, rflags); + newthr->regs.r_cs = get_register_v(thrstate, cs); + newthr->regs.r_fs = get_register_v(thrstate, fs); + newthr->regs.r_gs = get_register_v(thrstate, gs); + print_thread(newthr); + } else if (fc.flavor == x86_FLOAT_STATE) { + x86_float_state_t flstate; + if (read(fd, (void *)&flstate, sizeof(x86_float_state_t)) != sizeof(x86_float_state_t)) { + print_debug("Reading flavor, count failed.\n"); + goto err; + } + size += sizeof(x86_float_state_t); + } else if (fc.flavor == x86_EXCEPTION_STATE) { + x86_exception_state_t excpstate; + if (read(fd, (void *)&excpstate, sizeof(x86_exception_state_t)) != sizeof(x86_exception_state_t)) { + printf("Reading flavor, count failed.\n"); + goto err; + } + size += sizeof(x86_exception_state_t); + } + } + } + } + return true; +err: + return false; +} + +/**local function **/ +bool exists(const char *fname) +{ + int fd; + if ((fd = open(fname, O_RDONLY)) > 0) { + close(fd); + return true; + } + return false; +} + +// we check: 1. lib +// 2. lib/server +// 3. jre/lib +// 4. jre/lib/server +// from: 1. exe path +// 2. JAVA_HOME +// 3. DYLD_LIBRARY_PATH +static bool get_real_path(struct ps_prochandle* ph, char *rpath) { + /** check if they exist in JAVA ***/ + char* execname = ph->core->exec_path; + char filepath[4096]; + char* filename = strrchr(rpath, '/'); // like /libjvm.dylib + if (filename == NULL) { + return false; + } + + char* posbin = strstr(execname, "/bin/java"); + if (posbin != NULL) { + memcpy(filepath, execname, posbin - execname); // not include trailing '/' + filepath[posbin - execname] = '\0'; + } else { + char* java_home = getenv("JAVA_HOME"); + if (java_home != NULL) { + strcpy(filepath, java_home); + } else { + char* dyldpath = getenv("DYLD_LIBRARY_PATH"); + char* dypath = strtok(dyldpath, ":"); + while (dypath != NULL) { + strcpy(filepath, dypath); + strcat(filepath, filename); + if (exists(filepath)) { + strcpy(rpath, filepath); + return true; + } + dypath = strtok(dyldpath, ":"); + } + // not found + return false; + } + } + // for exec and java_home, jdkpath now is filepath + size_t filepath_base_size = strlen(filepath); + + // first try /lib/ and /lib/server + strcat(filepath, "/lib"); + strcat(filepath, filename); + if (exists(filepath)) { + strcpy(rpath, filepath); + return true; + } + char* pos = strstr(filepath, filename); // like /libjvm.dylib + *pos = '\0'; + strcat(filepath, "/server"); + strcat(filepath, filename); + if (exists(filepath)) { + strcpy(rpath, filepath); + return true; + } + + // then try /jre/lib/ and /jre/lib/server + filepath[filepath_base_size] = '\0'; + strcat(filepath, "/jre/lib"); + strcat(filepath, filename); + if (exists(filepath)) { + strcpy(rpath, filepath); + return true; + } + pos = strstr(filepath, filename); + *pos = '\0'; + strcat(filepath, "/server"); + strcat(filepath, filename); + if (exists(filepath)) { + strcpy(rpath, filepath); + return true; + } + + return false; +} + +static bool read_shared_lib_info(struct ps_prochandle* ph) { + static int pagesize = 0; + int fd = ph->core->core_fd; + int i = 0, j; + uint32_t v; + mach_header_64 header; // used to check if a file header in segment + load_command lcmd; + dylib_command dylibcmd; + + char name[BUF_SIZE]; // use to store name + + if (pagesize == 0) { + pagesize = getpagesize(); + print_debug("page size is %d\n", pagesize); + } + for (j = 0; j < ph->core->num_maps; j++) { + map_info *iter = ph->core->map_array[j]; // head + off_t fpos = iter->offset; + if (iter->fd != fd) { + // only search core file! + continue; + } + print_debug("map_info %d: vmaddr = 0x%016" PRIx64 " fileoff = %" PRIu64 " vmsize = %" PRIu64 "\n", + j, iter->vaddr, iter->offset, iter->memsz); + lseek(fd, fpos, SEEK_SET); + // we assume .dylib loaded at segment address --- which is true for JVM libraries + // multiple files may be loaded in one segment. + // if first word is not a magic word, means this segment does not contain lib file. + if (read(fd, (void *)&v, sizeof(uint32_t)) == sizeof(uint32_t)) { + if (v != MH_MAGIC_64) { + continue; + } + } else { + // may be encountered last map, which is not readable + continue; + } + while (ltell(fd) - iter->offset < iter->memsz) { + lseek(fd, fpos, SEEK_SET); + if (read(fd, (void *)&v, sizeof(uint32_t)) != sizeof(uint32_t)) { + break; + } + if (v != MH_MAGIC_64) { + fpos = (ltell(fd) + pagesize -1)/pagesize * pagesize; + continue; + } + lseek(fd, -sizeof(uint32_t), SEEK_CUR); + // this is the file begining to core file. + if (read(fd, (void *)&header, sizeof(mach_header_64)) != sizeof(mach_header_64)) { + goto err; + } + fpos = ltell(fd); + + // found a mach-o file in this segment + for (i = 0; i < header.ncmds; i++) { + // read commands in this "file" + // LC_ID_DYLIB is the file itself for a .dylib + lseek(fd, fpos, SEEK_SET); + if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) { + return false; // error + } + fpos += lcmd.cmdsize; // next command position + // make sure still within seg size. + if (fpos - lcmd.cmdsize - iter->offset > iter->memsz) { + print_debug("Warning: out of segement limit: %ld \n", fpos - lcmd.cmdsize - iter->offset); + break; // no need to iterate all commands + } + if (lcmd.cmd == LC_ID_DYLIB) { + lseek(fd, -sizeof(load_command), SEEK_CUR); + if (read(fd, (void *)&dylibcmd, sizeof(dylib_command)) != sizeof(dylib_command)) { + return false; + } + /**** name stored at dylib_command.dylib.name.offset, is a C string */ + lseek(fd, dylibcmd.dylib.name.offset - sizeof(dylib_command), SEEK_CUR); + int j = 0; + while (j < BUF_SIZE) { + read(fd, (void *)(name + j), sizeof(char)); + if (name[j] == '\0') break; + j++; + } + print_debug("%s\n", name); + // changed name from @rpath/xxxx.dylib to real path + if (strrchr(name, '@')) { + get_real_path(ph, name); + print_debug("get_real_path returned: %s\n", name); + } + add_lib_info(ph, name, iter->vaddr); + break; + } + } + // done with the file, advanced to next page to search more files + fpos = (ltell(fd) + pagesize - 1) / pagesize * pagesize; + } + } + return true; +err: + return false; +} + +bool read_macho64_header(int fd, mach_header_64* core_header) { + bool is_macho = false; + if (fd < 0) return false; + off_t pos = ltell(fd); + lseek(fd, 0, SEEK_SET); + if (read(fd, (void *)core_header, sizeof(mach_header_64)) != sizeof(mach_header_64)) { + is_macho = false; + } else { + is_macho = (core_header->magic == MH_MAGIC_64 || core_header->magic == MH_CIGAM_64); + } + lseek(fd, pos, SEEK_SET); + return is_macho; +} + +// the one and only one exposed stuff from this file +struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) { + mach_header_64 core_header; + mach_header_64 exec_header; + + struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); + if (ph == NULL) { + print_debug("cant allocate ps_prochandle\n"); + return NULL; + } + + if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) { + free(ph); + print_debug("can't allocate ps_prochandle\n"); + return NULL; + } + + // initialize ph + ph->ops = &core_ops; + ph->core->core_fd = -1; + ph->core->exec_fd = -1; + ph->core->interp_fd = -1; + + print_debug("exec: %s core: %s", exec_file, core_file); + + strncpy(ph->core->exec_path, exec_file, sizeof(ph->core->exec_path)); + + // open the core file + if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) { + print_error("can't open core file\n"); + goto err; + } + + // read core file header + if (read_macho64_header(ph->core->core_fd, &core_header) != true || core_header.filetype != MH_CORE) { + print_debug("core file is not a valid Mach-O file\n"); + goto err; + } + + if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) { + print_error("can't open executable file\n"); + goto err; + } + + if (read_macho64_header(ph->core->exec_fd, &exec_header) != true || + exec_header.filetype != MH_EXECUTE) { + print_error("executable file is not a valid Mach-O file\n"); + goto err; + } + + // process core file segments + if (read_core_segments(ph) != true) { + print_error("failed to read core segments\n"); + goto err; + } + + // allocate and sort maps into map_array, we need to do this + // here because read_shared_lib_info needs to read from debuggee + // address space + if (sort_map_array(ph) != true) { + print_error("failed to sort segment map array\n"); + goto err; + } + + if (read_shared_lib_info(ph) != true) { + print_error("failed to read libraries\n"); + goto err; + } + + // sort again because we have added more mappings from shared objects + if (sort_map_array(ph) != true) { + print_error("failed to sort segment map array\n"); + goto err; + } + + if (init_classsharing_workaround(ph) != true) { + print_error("failed to workaround classshareing\n"); + goto err; + } + + print_debug("Leave Pgrab_core\n"); + return ph; + +err: + Prelease(ph); + return NULL; +} + +#else // __APPLE__ (none macosx) + +// read regs and create thread from core file static bool core_handle_prstatus(struct ps_prochandle* ph, const char* buf, size_t nbytes) { // we have to read prstatus_t from buf // assert(nbytes == sizeof(prstaus_t), "size mismatch on prstatus_t"); prstatus_t* prstat = (prstatus_t*) buf; - thread_info* newthr; + sa_thread_info* newthr; print_debug("got integer regset for lwp %d\n", prstat->pr_pid); // we set pthread_t to -1 for core dump if((newthr = add_thread_info(ph, (pthread_t) -1, prstat->pr_pid)) == NULL) @@ -632,8 +1093,9 @@ static bool core_handle_note(struct ps_prochandle* ph, ELF_PHDR* note_phdr) { notep->n_type, notep->n_descsz); if (notep->n_type == NT_PRSTATUS) { - if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) + if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) { return false; + } } p = descdata + ROUNDUP(notep->n_descsz, 4); } @@ -681,7 +1143,9 @@ static bool read_core_segments(struct ps_prochandle* ph, ELF_EHDR* core_ehdr) { for (core_php = phbuf, i = 0; i < core_ehdr->e_phnum; i++) { switch (core_php->p_type) { case PT_NOTE: - if (core_handle_note(ph, core_php) != true) goto err; + if (core_handle_note(ph, core_php) != true) { + goto err; + } break; case PT_LOAD: { @@ -800,7 +1264,6 @@ err: return false; } - #define FIRST_LINK_MAP_OFFSET offsetof(struct r_debug, r_map) #define LD_BASE_OFFSET offsetof(struct r_debug, r_ldbase) #define LINK_MAP_ADDR_OFFSET offsetof(struct link_map, l_addr) @@ -810,213 +1273,218 @@ err: // read shared library info from runtime linker's data structures. // This work is done by librtlb_db in Solaris static bool read_shared_lib_info(struct ps_prochandle* ph) { - uintptr_t addr = ph->core->dynamic_addr; - uintptr_t debug_base; - uintptr_t first_link_map_addr; - uintptr_t ld_base_addr; - uintptr_t link_map_addr; - uintptr_t lib_base_diff; - uintptr_t lib_base; - uintptr_t lib_name_addr; - char lib_name[BUF_SIZE]; - ELF_DYN dyn; - ELF_EHDR elf_ehdr; - int lib_fd; + uintptr_t addr = ph->core->dynamic_addr; + uintptr_t debug_base; + uintptr_t first_link_map_addr; + uintptr_t ld_base_addr; + uintptr_t link_map_addr; + uintptr_t lib_base_diff; + uintptr_t lib_base; + uintptr_t lib_name_addr; + char lib_name[BUF_SIZE]; + ELF_DYN dyn; + ELF_EHDR elf_ehdr; + int lib_fd; - // _DYNAMIC has information of the form - // [tag] [data] [tag] [data] ..... - // Both tag and data are pointer sized. - // We look for dynamic info with DT_DEBUG. This has shared object info. - // refer to struct r_debug in link.h + // _DYNAMIC has information of the form + // [tag] [data] [tag] [data] ..... + // Both tag and data are pointer sized. + // We look for dynamic info with DT_DEBUG. This has shared object info. + // refer to struct r_debug in link.h - dyn.d_tag = DT_NULL; - while (dyn.d_tag != DT_DEBUG) { - if (ps_pread(ph, (psaddr_t) addr, &dyn, sizeof(ELF_DYN)) != PS_OK) { - print_debug("can't read debug info from _DYNAMIC\n"); - return false; - } - addr += sizeof(ELF_DYN); - } - - // we have got Dyn entry with DT_DEBUG - debug_base = dyn.d_un.d_ptr; - // at debug_base we have struct r_debug. This has first link map in r_map field - if (ps_pread(ph, (psaddr_t) debug_base + FIRST_LINK_MAP_OFFSET, - &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read first link map address\n"); + dyn.d_tag = DT_NULL; + while (dyn.d_tag != DT_DEBUG) { + if (ps_pread(ph, (psaddr_t) addr, &dyn, sizeof(ELF_DYN)) != PS_OK) { + print_debug("can't read debug info from _DYNAMIC\n"); return false; - } + } + addr += sizeof(ELF_DYN); + } - // read ld_base address from struct r_debug - // XXX: There is no r_ldbase member on BSD -/* - if (ps_pread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr, - sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read ld base address\n"); + // we have got Dyn entry with DT_DEBUG + debug_base = dyn.d_un.d_ptr; + // at debug_base we have struct r_debug. This has first link map in r_map field + if (ps_pread(ph, (psaddr_t) debug_base + FIRST_LINK_MAP_OFFSET, + &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) { + print_debug("can't read first link map address\n"); + return false; + } + + // read ld_base address from struct r_debug + // XXX: There is no r_ldbase member on BSD + /* + if (ps_pread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr, + sizeof(uintptr_t)) != PS_OK) { + print_debug("can't read ld base address\n"); + return false; + } + ph->core->ld_base_addr = ld_base_addr; + */ + ph->core->ld_base_addr = 0; + + print_debug("interpreter base address is 0x%lx\n", ld_base_addr); + + // now read segments from interp (i.e ld-elf.so.1) + if (read_interp_segments(ph) != true) + return false; + + // after adding interpreter (ld.so) mappings sort again + if (sort_map_array(ph) != true) + return false; + + print_debug("first link map is at 0x%lx\n", first_link_map_addr); + + link_map_addr = first_link_map_addr; + while (link_map_addr != 0) { + // read library base address of the .so. Note that even though calls + // link_map->l_addr as "base address", this is * not * really base virtual + // address of the shared object. This is actually the difference b/w the virtual + // address mentioned in shared object and the actual virtual base where runtime + // linker loaded it. We use "base diff" in read_lib_segments call below. + + if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_ADDR_OFFSET, + &lib_base_diff, sizeof(uintptr_t)) != PS_OK) { + print_debug("can't read shared object base address diff\n"); return false; - } - ph->core->ld_base_addr = ld_base_addr; -*/ - ph->core->ld_base_addr = 0; + } - print_debug("interpreter base address is 0x%lx\n", ld_base_addr); - - // now read segments from interp (i.e ld-elf.so.1) - if (read_interp_segments(ph) != true) + // read address of the name + if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NAME_OFFSET, + &lib_name_addr, sizeof(uintptr_t)) != PS_OK) { + print_debug("can't read address of shared object name\n"); return false; + } - // after adding interpreter (ld.so) mappings sort again - if (sort_map_array(ph) != true) + // read name of the shared object + if (read_string(ph, (uintptr_t) lib_name_addr, lib_name, sizeof(lib_name)) != true) { + print_debug("can't read shared object name\n"); return false; + } - print_debug("first link map is at 0x%lx\n", first_link_map_addr); + if (lib_name[0] != '\0') { + // ignore empty lib names + lib_fd = pathmap_open(lib_name); - link_map_addr = first_link_map_addr; - while (link_map_addr != 0) { - // read library base address of the .so. Note that even though calls - // link_map->l_addr as "base address", this is * not * really base virtual - // address of the shared object. This is actually the difference b/w the virtual - // address mentioned in shared object and the actual virtual base where runtime - // linker loaded it. We use "base diff" in read_lib_segments call below. - - if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_ADDR_OFFSET, - &lib_base_diff, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read shared object base address diff\n"); - return false; + if (lib_fd < 0) { + print_debug("can't open shared object %s\n", lib_name); + // continue with other libraries... + } else { + if (read_elf_header(lib_fd, &elf_ehdr)) { + lib_base = lib_base_diff + find_base_address(lib_fd, &elf_ehdr); + print_debug("reading library %s @ 0x%lx [ 0x%lx ]\n", + lib_name, lib_base, lib_base_diff); + // while adding library mappings we need to use "base difference". + if (! read_lib_segments(ph, lib_fd, &elf_ehdr, lib_base_diff)) { + print_debug("can't read shared object's segments\n"); + close(lib_fd); + return false; + } + add_lib_info_fd(ph, lib_name, lib_fd, lib_base); + // Map info is added for the library (lib_name) so + // we need to re-sort it before calling the p_pdread. + if (sort_map_array(ph) != true) + return false; + } else { + print_debug("can't read ELF header for shared object %s\n", lib_name); + close(lib_fd); + // continue with other libraries... + } } + } - // read address of the name - if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NAME_OFFSET, - &lib_name_addr, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read address of shared object name\n"); - return false; - } + // read next link_map address + if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NEXT_OFFSET, + &link_map_addr, sizeof(uintptr_t)) != PS_OK) { + print_debug("can't read next link in link_map\n"); + return false; + } + } - // read name of the shared object - if (read_string(ph, (uintptr_t) lib_name_addr, lib_name, sizeof(lib_name)) != true) { - print_debug("can't read shared object name\n"); - return false; - } - - if (lib_name[0] != '\0') { - // ignore empty lib names - lib_fd = pathmap_open(lib_name); - - if (lib_fd < 0) { - print_debug("can't open shared object %s\n", lib_name); - // continue with other libraries... - } else { - if (read_elf_header(lib_fd, &elf_ehdr)) { - lib_base = lib_base_diff + find_base_address(lib_fd, &elf_ehdr); - print_debug("reading library %s @ 0x%lx [ 0x%lx ]\n", - lib_name, lib_base, lib_base_diff); - // while adding library mappings we need to use "base difference". - if (! read_lib_segments(ph, lib_fd, &elf_ehdr, lib_base_diff)) { - print_debug("can't read shared object's segments\n"); - close(lib_fd); - return false; - } - add_lib_info_fd(ph, lib_name, lib_fd, lib_base); - // Map info is added for the library (lib_name) so - // we need to re-sort it before calling the p_pdread. - if (sort_map_array(ph) != true) - return false; - } else { - print_debug("can't read ELF header for shared object %s\n", lib_name); - close(lib_fd); - // continue with other libraries... - } - } - } - - // read next link_map address - if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NEXT_OFFSET, - &link_map_addr, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read next link in link_map\n"); - return false; - } - } - - return true; + return true; } // the one and only one exposed stuff from this file struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) { - ELF_EHDR core_ehdr; - ELF_EHDR exec_ehdr; + ELF_EHDR core_ehdr; + ELF_EHDR exec_ehdr; - struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); - if (ph == NULL) { - print_debug("can't allocate ps_prochandle\n"); - return NULL; - } + struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); + if (ph == NULL) { + print_debug("cant allocate ps_prochandle\n"); + return NULL; + } - if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) { - free(ph); - print_debug("can't allocate ps_prochandle\n"); - return NULL; - } + if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) { + free(ph); + print_debug("can't allocate ps_prochandle\n"); + return NULL; + } - // initialize ph - ph->ops = &core_ops; - ph->core->core_fd = -1; - ph->core->exec_fd = -1; - ph->core->interp_fd = -1; + // initialize ph + ph->ops = &core_ops; + ph->core->core_fd = -1; + ph->core->exec_fd = -1; + ph->core->interp_fd = -1; - // open the core file - if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) { - print_debug("can't open core file\n"); - goto err; - } + print_debug("exec: %s core: %s", exec_file, core_file); - // read core file ELF header - if (read_elf_header(ph->core->core_fd, &core_ehdr) != true || core_ehdr.e_type != ET_CORE) { - print_debug("core file is not a valid ELF ET_CORE file\n"); - goto err; - } + // open the core file + if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) { + print_debug("can't open core file\n"); + goto err; + } - if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) { - print_debug("can't open executable file\n"); - goto err; - } + // read core file ELF header + if (read_elf_header(ph->core->core_fd, &core_ehdr) != true || core_ehdr.e_type != ET_CORE) { + print_debug("core file is not a valid ELF ET_CORE file\n"); + goto err; + } - if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || exec_ehdr.e_type != ET_EXEC) { - print_debug("executable file is not a valid ELF ET_EXEC file\n"); - goto err; - } + if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) { + print_debug("can't open executable file\n"); + goto err; + } - // process core file segments - if (read_core_segments(ph, &core_ehdr) != true) - goto err; + if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || exec_ehdr.e_type != ET_EXEC) { + print_debug("executable file is not a valid ELF ET_EXEC file\n"); + goto err; + } - // process exec file segments - if (read_exec_segments(ph, &exec_ehdr) != true) - goto err; + // process core file segments + if (read_core_segments(ph, &core_ehdr) != true) + goto err; - // exec file is also treated like a shared object for symbol search - if (add_lib_info_fd(ph, exec_file, ph->core->exec_fd, - (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL) - goto err; + // process exec file segments + if (read_exec_segments(ph, &exec_ehdr) != true) + goto err; - // allocate and sort maps into map_array, we need to do this - // here because read_shared_lib_info needs to read from debuggee - // address space - if (sort_map_array(ph) != true) - goto err; + // exec file is also treated like a shared object for symbol search + if (add_lib_info_fd(ph, exec_file, ph->core->exec_fd, + (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL) + goto err; - if (read_shared_lib_info(ph) != true) - goto err; + // allocate and sort maps into map_array, we need to do this + // here because read_shared_lib_info needs to read from debuggee + // address space + if (sort_map_array(ph) != true) + goto err; - // sort again because we have added more mappings from shared objects - if (sort_map_array(ph) != true) - goto err; + if (read_shared_lib_info(ph) != true) + goto err; - if (init_classsharing_workaround(ph) != true) - goto err; + // sort again because we have added more mappings from shared objects + if (sort_map_array(ph) != true) + goto err; - return ph; + if (init_classsharing_workaround(ph) != true) + goto err; + + print_debug("Leave Pgrab_core\n"); + return ph; err: - Prelease(ph); - return NULL; + Prelease(ph); + return NULL; } + +#endif // __APPLE__ diff --git a/hotspot/agent/src/os/bsd/symtab.c b/hotspot/agent/src/os/bsd/symtab.c index 9a9fbd23491..0299cb2b7a8 100644 --- a/hotspot/agent/src/os/bsd/symtab.c +++ b/hotspot/agent/src/os/bsd/symtab.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,32 +28,182 @@ #include #include #include + +#include "libproc_impl.h" #include "symtab.h" +#ifndef __APPLE__ #include "salibelf.h" +#endif // __APPLE__ // ---------------------------------------------------- // functions for symbol lookups // ---------------------------------------------------- +typedef struct symtab_symbol { + char *name; // name like __ZThread_... + uintptr_t offset; // to loaded address + uintptr_t size; // size strlen +} symtab_symbol; + +typedef struct symtab { + char *strs; // all symbols "__symbol1__'\0'__symbol2__...." + size_t num_symbols; + DB* hash_table; + symtab_symbol* symbols; +} symtab_t; + +#ifdef __APPLE__ + +void build_search_table(symtab_t *symtab) { + int i; + for (i = 0; i < symtab->num_symbols; i++) { + DBT key, value; + key.data = symtab->symbols[i].name; + key.size = strlen(key.data) + 1; + value.data = &(symtab->symbols[i]); + value.size = sizeof(symtab_symbol); + (*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0); + + // check result + if (is_debug()) { + DBT rkey, rvalue; + char* tmp = (char *)malloc(strlen(symtab->symbols[i].name) + 1); + strcpy(tmp, symtab->symbols[i].name); + rkey.data = tmp; + rkey.size = strlen(tmp) + 1; + (*symtab->hash_table->get)(symtab->hash_table, &rkey, &rvalue, 0); + // we may get a copy back so compare contents + symtab_symbol *res = (symtab_symbol *)rvalue.data; + if (strcmp(res->name, symtab->symbols[i].name) || + res->offset != symtab->symbols[i].offset || + res->size != symtab->symbols[i].size) { + print_debug("error to get hash_table value!\n"); + } + free(tmp); + } + } +} + +// read symbol table from given fd. +struct symtab* build_symtab(int fd) { + symtab_t* symtab = NULL; + int i; + mach_header_64 header; + off_t image_start; + + if (!get_arch_off(fd, CPU_TYPE_X86_64, &image_start)) { + print_debug("failed in get fat header\n"); + return NULL; + } + lseek(fd, image_start, SEEK_SET); + if (read(fd, (void *)&header, sizeof(mach_header_64)) != sizeof(mach_header_64)) { + print_debug("reading header failed!\n"); + return NULL; + } + // header + if (header.magic != MH_MAGIC_64) { + print_debug("not a valid .dylib file\n"); + return NULL; + } + + load_command lcmd; + symtab_command symtabcmd; + nlist_64 lentry; + + bool lcsymtab_exist = false; + + long filepos = ltell(fd); + for (i = 0; i < header.ncmds; i++) { + lseek(fd, filepos, SEEK_SET); + if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) { + print_debug("read load_command failed for file\n"); + return NULL; + } + filepos += lcmd.cmdsize; // next command position + if (lcmd.cmd == LC_SYMTAB) { + lseek(fd, -sizeof(load_command), SEEK_CUR); + lcsymtab_exist = true; + break; + } + } + if (!lcsymtab_exist) { + print_debug("No symtab command found!\n"); + return NULL; + } + if (read(fd, (void *)&symtabcmd, sizeof(symtab_command)) != sizeof(symtab_command)) { + print_debug("read symtab_command failed for file"); + return NULL; + } + symtab = (symtab_t *)malloc(sizeof(symtab_t)); + if (symtab == NULL) { + print_debug("out of memory: allocating symtab\n"); + return NULL; + } + + // create hash table, we use berkeley db to + // manipulate the hash table. + symtab->hash_table = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL); + if (symtab->hash_table == NULL) + goto quit; + + symtab->num_symbols = symtabcmd.nsyms; + symtab->symbols = (symtab_symbol *)malloc(sizeof(symtab_symbol) * symtab->num_symbols); + symtab->strs = (char *)malloc(sizeof(char) * symtabcmd.strsize); + if (symtab->symbols == NULL || symtab->strs == NULL) { + print_debug("out of memory: allocating symtab.symbol or symtab.strs\n"); + goto quit; + } + lseek(fd, image_start + symtabcmd.symoff, SEEK_SET); + for (i = 0; i < symtab->num_symbols; i++) { + if (read(fd, (void *)&lentry, sizeof(nlist_64)) != sizeof(nlist_64)) { + print_debug("read nlist_64 failed at %i\n", i); + goto quit; + } + symtab->symbols[i].offset = lentry.n_value; + symtab->symbols[i].size = lentry.n_un.n_strx; // index + } + + // string table + lseek(fd, image_start + symtabcmd.stroff, SEEK_SET); + int size = read(fd, (void *)(symtab->strs), symtabcmd.strsize * sizeof(char)); + if (size != symtabcmd.strsize * sizeof(char)) { + print_debug("reading string table failed\n"); + goto quit; + } + + for (i = 0; i < symtab->num_symbols; i++) { + symtab->symbols[i].name = symtab->strs + symtab->symbols[i].size; + if (i > 0) { + // fix size + symtab->symbols[i - 1].size = symtab->symbols[i].size - symtab->symbols[i - 1].size; + print_debug("%s size = %d\n", symtab->symbols[i - 1].name, symtab->symbols[i - 1].size); + + } + + if (i == symtab->num_symbols - 1) { + // last index + symtab->symbols[i].size = + symtabcmd.strsize - symtab->symbols[i].size; + print_debug("%s size = %d\n", symtab->symbols[i].name, symtab->symbols[i].size); + } + } + + // build a hashtable for fast query + build_search_table(symtab); + return symtab; +quit: + if (symtab) destroy_symtab(symtab); + return NULL; +} + +#else // __APPLE__ + struct elf_section { ELF_SHDR *c_shdr; void *c_data; }; -struct elf_symbol { - char *name; - uintptr_t offset; - uintptr_t size; -}; - -typedef struct symtab { - char *strs; - size_t num_symbols; - struct elf_symbol *symbols; - DB* hash_table; -} symtab_t; - // read symbol table from given fd. struct symtab* build_symtab(int fd) { ELF_EHDR ehdr; @@ -176,7 +326,7 @@ struct symtab* build_symtab(int fd) { key.data = sym_name; key.size = strlen(sym_name) + 1; value.data = &(symtab->symbols[j]); - value.size = sizeof(void *); + value.size = sizeof(symtab_symbol); (*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0); } } @@ -201,30 +351,29 @@ quit: return symtab; } -void destroy_symtab(struct symtab* symtab) { +#endif // __APPLE__ + +void destroy_symtab(symtab_t* symtab) { if (!symtab) return; - if (symtab->strs) free(symtab->strs); - if (symtab->symbols) free(symtab->symbols); - if (symtab->hash_table) { - (*symtab->hash_table->close)(symtab->hash_table); - } + free(symtab->strs); + free(symtab->symbols); free(symtab); } -uintptr_t search_symbol(struct symtab* symtab, uintptr_t base, - const char *sym_name, int *sym_size) { +uintptr_t search_symbol(struct symtab* symtab, uintptr_t base, const char *sym_name, int *sym_size) { DBT key, value; int ret; // library does not have symbol table - if (!symtab || !symtab->hash_table) + if (!symtab || !symtab->hash_table) { return 0; + } key.data = (char*)(uintptr_t)sym_name; key.size = strlen(sym_name) + 1; ret = (*symtab->hash_table->get)(symtab->hash_table, &key, &value, 0); if (ret == 0) { - struct elf_symbol *sym = value.data; + symtab_symbol *sym = value.data; uintptr_t rslt = (uintptr_t) ((char*)base + sym->offset); if (sym_size) *sym_size = sym->size; return rslt; @@ -238,7 +387,7 @@ const char* nearest_symbol(struct symtab* symtab, uintptr_t offset, int n = 0; if (!symtab) return NULL; for (; n < symtab->num_symbols; n++) { - struct elf_symbol* sym = &(symtab->symbols[n]); + symtab_symbol* sym = &(symtab->symbols[n]); if (sym->name != NULL && offset >= sym->offset && offset < sym->offset + sym->size) { if (poffset) *poffset = (offset - sym->offset); diff --git a/hotspot/agent/src/os/bsd/symtab.h b/hotspot/agent/src/os/bsd/symtab.h index 9b7eef77d69..f5f8645dabc 100644 --- a/hotspot/agent/src/os/bsd/symtab.h +++ b/hotspot/agent/src/os/bsd/symtab.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,11 +27,11 @@ #include -// interface to manage ELF symbol tables +// interface to manage ELF or MachO symbol tables struct symtab; -// build symbol table for a given ELF file descriptor +// build symbol table for a given ELF or MachO file escriptor struct symtab* build_symtab(int fd); // destroy the symbol table diff --git a/hotspot/agent/src/os/linux/ps_core.c b/hotspot/agent/src/os/linux/ps_core.c index 30023f2397b..c211ff3b34a 100644 --- a/hotspot/agent/src/os/linux/ps_core.c +++ b/hotspot/agent/src/os/linux/ps_core.c @@ -132,12 +132,12 @@ static map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset, } // Part of the class sharing workaround -static map_info* add_class_share_map_info(struct ps_prochandle* ph, off_t offset, +static void add_class_share_map_info(struct ps_prochandle* ph, off_t offset, uintptr_t vaddr, size_t memsz) { map_info* map; if ((map = allocate_init_map(ph->core->classes_jsa_fd, offset, vaddr, memsz)) == NULL) { - return NULL; + return; } map->next = ph->core->class_share_maps; diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java index ed688758d41..6d422f62acc 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,11 +34,18 @@ public class BsdVtblAccess extends BasicVtblAccess { public BsdVtblAccess(SymbolLookup symbolLookup, String[] dllNames) { super(symbolLookup, dllNames); - - if (symbolLookup.lookup("libjvm.so", "__vt_10JavaThread") != null || - symbolLookup.lookup("libjvm_g.so", "__vt_10JavaThread") != null) { + boolean oldVT = false; + boolean isDarwin = dllNames[0].lastIndexOf(".dylib") != -1; + String vtJavaThread = isDarwin ? "_vt_10JavaThread" : "__vt_10JavaThread"; + for (String dllName : dllNames) { + if (symbolLookup.lookup(dllName, vtJavaThread) != null) { + oldVT = true; + break; + } + } + if (oldVT) { // old C++ ABI - vt = "__vt_"; + vt = isDarwin ? "_vt_" : "__vt_"; } else { // new C++ ABI vt = "_ZTV"; diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java index 23058f42858..2233844267c 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java @@ -24,36 +24,81 @@ package sun.jvm.hotspot; -import java.io.*; -import java.math.*; -import java.util.*; -import java.util.regex.*; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; -import sun.jvm.hotspot.types.Type; -import sun.jvm.hotspot.types.Field; -import sun.jvm.hotspot.HotSpotTypeDataBase; -import sun.jvm.hotspot.types.basic.BasicType; -import sun.jvm.hotspot.types.basic.BasicTypeDataBase; -import sun.jvm.hotspot.types.CIntegerType; -import sun.jvm.hotspot.code.*; -import sun.jvm.hotspot.compiler.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.interpreter.*; -import sun.jvm.hotspot.memory.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.opto.*; -import sun.jvm.hotspot.ci.*; -import sun.jvm.hotspot.asm.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.utilities.*; -import sun.jvm.hotspot.utilities.soql.*; -import sun.jvm.hotspot.ui.classbrowser.*; -import sun.jvm.hotspot.ui.tree.*; -import sun.jvm.hotspot.tools.*; +import sun.jvm.hotspot.ci.ciEnv; +import sun.jvm.hotspot.code.CodeBlob; +import sun.jvm.hotspot.code.CodeCacheVisitor; +import sun.jvm.hotspot.code.NMethod; +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.debugger.OopHandle; +import sun.jvm.hotspot.memory.SymbolTable; +import sun.jvm.hotspot.memory.SystemDictionary; +import sun.jvm.hotspot.memory.Universe; +import sun.jvm.hotspot.oops.DefaultHeapVisitor; +import sun.jvm.hotspot.oops.HeapVisitor; +import sun.jvm.hotspot.oops.InstanceKlass; +import sun.jvm.hotspot.oops.Klass; +import sun.jvm.hotspot.oops.Metadata; +import sun.jvm.hotspot.oops.Method; +import sun.jvm.hotspot.oops.MethodData; +import sun.jvm.hotspot.oops.Oop; +import sun.jvm.hotspot.oops.RawHeapVisitor; +import sun.jvm.hotspot.oops.Symbol; +import sun.jvm.hotspot.oops.UnknownOopException; +import sun.jvm.hotspot.opto.Compile; +import sun.jvm.hotspot.opto.InlineTree; +import sun.jvm.hotspot.runtime.CompiledVFrame; +import sun.jvm.hotspot.runtime.CompilerThread; +import sun.jvm.hotspot.runtime.JavaThread; +import sun.jvm.hotspot.runtime.JavaVFrame; +import sun.jvm.hotspot.runtime.Threads; +import sun.jvm.hotspot.runtime.VM; import sun.jvm.hotspot.tools.ObjectHistogram; +import sun.jvm.hotspot.tools.PMap; +import sun.jvm.hotspot.tools.PStack; import sun.jvm.hotspot.tools.StackTrace; import sun.jvm.hotspot.tools.jcore.ClassDump; import sun.jvm.hotspot.tools.jcore.ClassFilter; +import sun.jvm.hotspot.types.CIntegerType; +import sun.jvm.hotspot.types.Field; +import sun.jvm.hotspot.types.Type; +import sun.jvm.hotspot.types.basic.BasicType; +import sun.jvm.hotspot.ui.classbrowser.HTMLGenerator; +import sun.jvm.hotspot.ui.tree.CTypeTreeNodeAdapter; +import sun.jvm.hotspot.ui.tree.OopTreeNodeAdapter; +import sun.jvm.hotspot.ui.tree.SimpleTreeNode; +import sun.jvm.hotspot.utilities.AddressOps; +import sun.jvm.hotspot.utilities.Assert; +import sun.jvm.hotspot.utilities.HeapProgressThunk; +import sun.jvm.hotspot.utilities.LivenessPathElement; +import sun.jvm.hotspot.utilities.MethodArray; +import sun.jvm.hotspot.utilities.ObjectReader; +import sun.jvm.hotspot.utilities.PointerFinder; +import sun.jvm.hotspot.utilities.PointerLocation; +import sun.jvm.hotspot.utilities.ReversePtrs; +import sun.jvm.hotspot.utilities.ReversePtrsAnalysis; +import sun.jvm.hotspot.utilities.RobustOopDeterminator; +import sun.jvm.hotspot.utilities.SystemDictionaryHelper; +import sun.jvm.hotspot.utilities.soql.JSJavaFactory; +import sun.jvm.hotspot.utilities.soql.JSJavaFactoryImpl; +import sun.jvm.hotspot.utilities.soql.JSJavaScriptEngine; public class CommandProcessor { public abstract static class DebuggerInterface { @@ -1132,6 +1177,10 @@ public class CommandProcessor { Klass klass = null; if (t.countTokens() == 1) { klass = SystemDictionaryHelper.findInstanceKlass(t.nextToken()); + if (klass == null) { + out.println("No such type."); + return; + } } while (base != null && base.lessThan(end)) { long step = stride; @@ -1517,7 +1566,7 @@ public class CommandProcessor { ByteArrayOutputStream bos = new ByteArrayOutputStream(); thread.printThreadIDOn(new PrintStream(bos)); if (all || bos.toString().equals(name)) { - out.println(bos.toString() + " = " + thread.getAddress()); + out.println("Thread " + bos.toString() + " Address: " + thread.getAddress()); HTMLGenerator gen = new HTMLGenerator(false); try { out.println(gen.genHTMLForJavaStackTrace(thread)); @@ -1546,7 +1595,7 @@ public class CommandProcessor { ByteArrayOutputStream bos = new ByteArrayOutputStream(); thread.printThreadIDOn(new PrintStream(bos)); if (all || bos.toString().equals(name)) { - out.println(bos.toString() + " = " + thread.getAddress()); + out.println("Thread " + bos.toString() + " Address " + thread.getAddress()); if (!all) return; } } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java index bb718d9f78b..8abd084c8b3 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -311,6 +311,8 @@ public class HotSpotAgent { setupDebuggerLinux(); } else if (os.equals("bsd")) { setupDebuggerBsd(); + } else if (os.equals("darwin")) { + setupDebuggerDarwin(); } else { // Add support for more operating systems here throw new DebuggerException("Operating system " + os + " not yet supported"); @@ -370,6 +372,10 @@ public class HotSpotAgent { db = new HotSpotTypeDataBase(machDesc, new BsdVtblAccess(debugger, jvmLibNames), debugger, jvmLibNames); + } else if (os.equals("darwin")) { + db = new HotSpotTypeDataBase(machDesc, + new BsdVtblAccess(debugger, jvmLibNames), + debugger, jvmLibNames); } else { throw new DebuggerException("OS \"" + os + "\" not yet supported (no VtblAccess yet)"); } @@ -459,6 +465,8 @@ public class HotSpotAgent { setupJVMLibNamesLinux(); } else if (os.equals("bsd")) { setupJVMLibNamesBsd(); + } else if (os.equals("darwin")) { + setupJVMLibNamesDarwin(); } else { throw new RuntimeException("Unknown OS type"); } @@ -567,6 +575,29 @@ public class HotSpotAgent { jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" }; } + // + // Darwin + // + + private void setupDebuggerDarwin() { + setupJVMLibNamesDarwin(); + + if (cpu.equals("amd64") || cpu.equals("x86_64")) { + machDesc = new MachineDescriptionAMD64(); + } else { + throw new DebuggerException("Darwin only supported on x86_64. Current arch: " + cpu); + } + + BsdDebuggerLocal dbg = new BsdDebuggerLocal(machDesc, !isServer); + debugger = dbg; + + attachDebugger(); + } + + private void setupJVMLibNamesDarwin() { + jvmLibNames = new String[] { "libjvm.dylib", "libjvm_g.dylib" }; + } + /** Convenience routine which should be called by per-platform debugger setup. Should not be called when startupMode is REMOTE_MODE. */ diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java index c6fbb7dab34..9a26584e324 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,9 @@ import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.x86.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.utilities.*; +import sun.jvm.hotspot.runtime.VM; +import sun.jvm.hotspot.runtime.Threads; +import sun.jvm.hotspot.runtime.JavaThread; import java.lang.reflect.*; /**

An implementation of the JVMDebugger interface. The basic debug @@ -51,10 +54,11 @@ import java.lang.reflect.*; public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { private boolean useGCC32ABI; private boolean attached; - private long p_ps_prochandle; // native debugger handle - private long symbolicator; // macosx symbolicator handle - private long task; // macosx task handle + private long p_ps_prochandle; // native debugger handle + private long symbolicator; // macosx symbolicator handle + private long task; // macosx task handle private boolean isCore; + private boolean isDarwin; // variant for bsd // CDebugger support private BsdCDebugger cdbg; @@ -208,6 +212,7 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { } } + isDarwin = getOS().equals("darwin"); workerThread = new BsdDebuggerLocalWorkerThread(this); workerThread.start(); } @@ -240,8 +245,11 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { /* called from attach methods */ private void findABIVersion() throws DebuggerException { - if (lookupByName0("libjvm.so", "__vt_10JavaThread") != 0 || - lookupByName0("libjvm_g.so", "__vt_10JavaThread") != 0) { + String libjvmName = isDarwin ? "libjvm.dylib" : "libjvm.so"; + String libjvm_gName = isDarwin? "libjvm_g.dylib" : "libjvm_g.so"; + String javaThreadVt = isDarwin ? "_vt_10JavaThread" : "__vt_10JavaThread"; + if (lookupByName0(libjvmName, javaThreadVt) != 0 || + lookupByName0(libjvm_gName, javaThreadVt) != 0) { // old C++ ABI useGCC32ABI = false; } else { @@ -360,7 +368,8 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { } if (isCore) { - long addr = lookupByName0(objectName, symbol); + // MacOSX symbol with "_" as leading + long addr = lookupByName0(objectName, isDarwin ? "_" + symbol : symbol); return (addr == 0)? null : new BsdAddress(this, handleGCC32ABI(addr, symbol)); } else { class LookupByNameTask implements WorkerThreadTask { @@ -403,12 +412,12 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { public ThreadProxy getThreadForIdentifierAddress(Address threadIdAddr, Address uniqueThreadIdAddr) { return new BsdThread(this, threadIdAddr, uniqueThreadIdAddr); } + @Override public ThreadProxy getThreadForIdentifierAddress(Address addr) { throw new RuntimeException("unimplemented"); } - /** From the ThreadAccess interface via Debugger and JVMDebugger */ public ThreadProxy getThreadForThreadId(long id) { return new BsdThread(this, id); @@ -601,6 +610,33 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { throw new DebuggerException("Unimplemented"); } + /** this functions used for core file reading and called from native attach0, + it returns an array of long integers as + [thread_id, stack_start, stack_end, thread_id, stack_start, stack_end, ....] for + all java threads recorded in Threads. Also adds the ThreadProxy to threadList */ + public long[] getJavaThreadsInfo() { + requireAttach(); + Threads threads = VM.getVM().getThreads(); + int len = threads.getNumberOfThreads(); + long[] result = new long[len * 3]; // triple + JavaThread t = threads.first(); + long beg, end; + int i = 0; + while (t != null) { + end = t.getStackBaseValue(); + beg = end - t.getStackSize(); + BsdThread bsdt = (BsdThread)t.getThreadProxy(); + long uid = bsdt.getUniqueThreadId(); + if (threadList != null) threadList.add(bsdt); + result[i] = uid; + result[i + 1] = beg; + result[i + 2] = end; + t = t.next(); + i += 3; + } + return result; + } + static { System.loadLibrary("saproc"); init0(); diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java index f3351fb9ce1..0d637f30f14 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,8 @@ class BsdThread implements ThreadProxy { BsdThread(BsdDebugger debugger, long id) { this.debugger = debugger; - this.thread_id = (int) id; + // use unique_thread_id to identify thread + this.unique_thread_id = id; } public boolean equals(Object obj) { @@ -52,7 +53,7 @@ class BsdThread implements ThreadProxy { return false; } - return (((BsdThread) obj).thread_id == thread_id); + return (((BsdThread) obj).unique_thread_id == unique_thread_id); } public int hashCode() { @@ -80,4 +81,9 @@ class BsdThread implements ThreadProxy { throws IllegalThreadStateException, DebuggerException { throw new DebuggerException("Unimplemented"); } + + /** this is not interface function, used in core file to get unique thread id on Macosx*/ + public long getUniqueThreadId() { + return unique_thread_id; + } } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java index ab81252d4e7..241e5be3756 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -148,7 +148,7 @@ public class Oop { if (doVMFields) { visitor.doCInt(mark, true); if (VM.getVM().isCompressedKlassPointersEnabled()) { - throw new InternalError("unimplemented"); + visitor.doMetadata(compressedKlass, true); } else { visitor.doMetadata(klass, true); } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java index 153d51bb090..926c11c4bad 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -320,6 +320,10 @@ public class JavaThread extends Thread { return stackBaseField.getValue(addr); } + public long getStackBaseValue() { + return VM.getVM().getAddressValue(getStackBase()); + } + public long getStackSize() { return stackSizeField.getValue(addr); } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java index 8e259e3a145..b4b5903d139 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,7 @@ import sun.jvm.hotspot.utilities.*; public class Threads { private static JavaThreadFactory threadFactory; private static AddressField threadListField; + private static CIntegerField numOfThreadsField; private static VirtualConstructor virtualConstructor; private static JavaThreadPDAccess access; @@ -57,6 +58,7 @@ public class Threads { Type type = db.lookupType("Threads"); threadListField = type.getAddressField("_thread_list"); + numOfThreadsField = type.getCIntegerField("_number_of_threads"); // Instantiate appropriate platform-specific JavaThreadFactory String os = VM.getVM().getOS(); @@ -102,6 +104,10 @@ public class Threads { } else if (cpu.equals("amd64") || cpu.equals("x86_64")) { access = new BsdAMD64JavaThreadPDAccess(); } + } else if (os.equals("darwin")) { + if (cpu.equals("amd64") || cpu.equals("x86_64")) { + access = new BsdAMD64JavaThreadPDAccess(); + } } if (access == null) { @@ -144,6 +150,10 @@ public class Threads { return createJavaThreadWrapper(threadAddr); } + public int getNumberOfThreads() { + return (int) numOfThreadsField.getValue(); + } + /** Routine for instantiating appropriately-typed wrapper for a JavaThread. Currently needs to be public for OopUtilities to access it. */ diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java index 54aa0e0de5c..0b3720ff594 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.utilities.PlatformInfo; public class PStack extends Tool { // in non-verbose mode, Method*s are not printed in java frames @@ -54,6 +55,11 @@ public class PStack extends Tool { } public void run(PrintStream out, Debugger dbg) { + if (PlatformInfo.getOS().equals("darwin")) { + out.println("Not available on Darwin"); + return; + } + CDebugger cdbg = dbg.getCDebugger(); if (cdbg != null) { ConcurrentLocksPrinter concLocksPrinter = null; diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java index f88335c1bff..12325863163 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java @@ -24,10 +24,15 @@ package sun.jvm.hotspot.types.basic; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.types.*; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.debugger.MachineDescription; import sun.jvm.hotspot.runtime.VM; +import sun.jvm.hotspot.types.Type; +import sun.jvm.hotspot.types.TypeDataBase; /**

This is a basic implementation of the TypeDataBase interface. It allows an external type database builder to add types to be @@ -150,7 +155,7 @@ public class BasicTypeDataBase implements TypeDataBase { return VM.getVM().getOopSize(); } - static HashMap typeToVtbl = new HashMap(); + HashMap typeToVtbl = new HashMap(); private Address vtblForType(Type type) { Address vtblAddr = (Address)typeToVtbl.get(type); diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java index 9a5dc144a9c..afe81ef578d 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,8 +43,8 @@ public class PlatformInfo { return "bsd"; } else if (os.equals("OpenBSD")) { return "bsd"; - } else if (os.equals("Darwin") || os.contains("OS X")) { - return "bsd"; + } else if (os.contains("Darwin") || os.contains("OS X")) { + return "darwin"; } else if (os.startsWith("Windows")) { return "win32"; } else { diff --git a/hotspot/agent/src/share/native/sadis.c b/hotspot/agent/src/share/native/sadis.c index f8bd9adbd64..926b4e5fd55 100644 --- a/hotspot/agent/src/share/native/sadis.c +++ b/hotspot/agent/src/share/native/sadis.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,10 @@ #include #include + +#ifndef __APPLE__ #include +#endif #endif @@ -109,9 +112,7 @@ JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_asm_Disassembler_load_1library(JNIE jstring libname_s) { uintptr_t func = 0; const char* error_message = NULL; - const char* java_home; jboolean isCopy; - uintptr_t *handle = NULL; const char * jrepath = (*env)->GetStringUTFChars(env, jrepath_s, &isCopy); // like $JAVA_HOME/jre/lib/sparc/ const char * libname = (*env)->GetStringUTFChars(env, libname_s, &isCopy); @@ -167,7 +168,8 @@ typedef void* (*decode_func)(uintptr_t start_va, uintptr_t end_va, void* event_stream, int (*printf_callback)(void*, const char*, ...), void* printf_stream, - const char* options); + const char* options, + int newline); /* container for call back state when decoding instructions */ typedef struct { @@ -281,7 +283,7 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_asm_Disassembler_decode(JNIEnv * env end - start, &event_to_env, (void*) &denv, &printf_to_env, (void*) &denv, - options); + options, 0 /* newline */); /* cleanup */ (*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT); diff --git a/hotspot/make/Makefile b/hotspot/make/Makefile index c55574d8247..8dad67f074e 100644 --- a/hotspot/make/Makefile +++ b/hotspot/make/Makefile @@ -532,6 +532,39 @@ $(JDK_IMAGE_DIR)/jre/lib/rt.jar: $(TAR) -cf - *) | \ ($(CD) $(JDK_IMAGE_DIR) && $(TAR) -xf -) + +# Testing the built JVM +RUN_JVM=JAVA_HOME=$(JDK_IMPORT_PATH) $(JDK_IMPORT_PATH)/bin/java -d$(ARCH_DATA_MODEL) -Dsun.java.launcher=gamma +generic_test: + @$(ECHO) "Running with: $(ALTJVM_DIR)" + @$(RUN_JVM) -XXaltjvm=$(ALTJVM_DIR) -Xinternalversion + @$(RUN_JVM) -XXaltjvm=$(ALTJVM_DIR) -showversion -help + +# C2 test targets +test_product test_optimized test_fastdebug test_jvmg: + @$(MAKE) generic_test ALTJVM_DIR="$(C2_DIR)/$(@:test_%=%)" + +# C1 test targets +test_product1 test_optimized1 test_fastdebug1 test_jvmg1: + ifeq ($(ARCH_DATA_MODEL), 32) + @$(MAKE) generic_test ALTJVM_DIR="$(C1_DIR)/$(@:test_%1=%)" + else + @$(ECHO) "No compiler1 ($(@:test_%=%)) for ARCH_DATA_MODEL=$(ARCH_DATA_MODEL)" + endif + +# Zero test targets +test_productzero test_optimizedzero test_fastdebugzero test_jvmgzero: + @$(MAKE) generic_test ALTJVM_DIR="$(ZERO_DIR)/$(@:test_%zero=%)" + +# Shark test targets +test_productshark test_optimizedshark test_fastdebugshark test_jvmgshark: + @$(MAKE) generic_test ALTJVM_DIR="$(SHARK_DIR)/$(@:test_%shark=%)" + +# Minimal1 test targets +test_productminimal1 test_optimizedminimal1 test_fastdebugminimal1 test_jvmgminimal1: + @$(MAKE) generic_test ALTJVM_DIR="$(MINIMAL1_DIR)/$(@:test_%minimal1=%)" + + test_jdk: ifeq ($(JVM_VARIANT_CLIENT), true) $(JDK_IMAGE_DIR)/bin/java -d$(ARCH_DATA_MODEL) -client -Xinternalversion diff --git a/hotspot/make/bsd/Makefile b/hotspot/make/bsd/Makefile index e95bb05502d..024aef9cba6 100644 --- a/hotspot/make/bsd/Makefile +++ b/hotspot/make/bsd/Makefile @@ -299,63 +299,42 @@ platform_zero: $(GAMMADIR)/make/$(OSNAME)/platform_zero.in $(TARGETS_C2): $(SUBDIRS_C2) cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS) install endif $(TARGETS_TIERED): $(SUBDIRS_TIERED) cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_C1): $(SUBDIRS_C1) cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_CORE): $(SUBDIRS_CORE) cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_ZERO): $(SUBDIRS_ZERO) cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_SHARK): $(SUBDIRS_SHARK) cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_MINIMAL1): $(SUBDIRS_MINIMAL1) cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && $(MAKE) $(MFLAGS) install endif diff --git a/hotspot/make/bsd/makefiles/buildtree.make b/hotspot/make/bsd/makefiles/buildtree.make index b8d92f6a4fc..71bb04b9811 100644 --- a/hotspot/make/bsd/makefiles/buildtree.make +++ b/hotspot/make/bsd/makefiles/buildtree.make @@ -50,7 +50,6 @@ # jvmti.make - generate JVMTI bindings from the spec (JSR-163) # sa.make - generate SA jar file and natives # env.[ck]sh - environment settings -# test_gamma - script to run the Queens program # # The makefiles are split this way so that "make foo" will run faster by not # having to read the dependency files for the vm. @@ -67,9 +66,6 @@ include $(GAMMADIR)/make/altsrc.make # 'gmake MAKE_VERBOSE=y' or 'gmake QUIETLY=' gives all the gory details. QUIETLY$(MAKE_VERBOSE) = @ -# For now, until the compiler is less wobbly: -TESTFLAGS = -Xbatch -showversion - ifeq ($(findstring true, $(JVM_VARIANT_ZERO) $(JVM_VARIANT_ZEROSHARK)), true) PLATFORM_FILE = $(shell dirname $(shell dirname $(shell pwd)))/platform_zero else @@ -135,7 +131,7 @@ BUILDTREE_MAKE = $(GAMMADIR)/make/$(OS_FAMILY)/makefiles/buildtree.make # dtrace.make is used on BSD versions that implement Dtrace (like MacOS X) BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make \ jvmti.make sa.make dtrace.make \ - env.sh env.csh jdkpath.sh .dbxrc test_gamma + env.sh env.csh jdkpath.sh BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \ SRCARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT) @@ -352,7 +348,7 @@ env.sh: $(BUILDTREE_MAKE) @echo Creating $@ ... $(QUIETLY) ( \ $(BUILDTREE_COMMENT); \ - [ -n "$$JAVA_HOME" ] && { echo ": \$${JAVA_HOME:=$${JAVA_HOME}}"; }; \ + { echo "JAVA_HOME=$(JDK_IMPORT_PATH)"; }; \ { \ echo "CLASSPATH=$${CLASSPATH:+$$CLASSPATH:}.:\$${JAVA_HOME}/jre/lib/rt.jar:\$${JAVA_HOME}/jre/lib/i18n.jar"; \ } | sed s:$${JAVA_HOME:--------}:\$${JAVA_HOME}:g; \ @@ -364,8 +360,7 @@ env.csh: env.sh @echo Creating $@ ... $(QUIETLY) ( \ $(BUILDTREE_COMMENT); \ - [ -n "$$JAVA_HOME" ] && \ - { echo "if (! \$$?JAVA_HOME) setenv JAVA_HOME \"$$JAVA_HOME\""; }; \ + { echo "setenv JAVA_HOME \"$(JDK_IMPORT_PATH)\""; }; \ sed -n 's/^\([A-Za-z_][A-Za-z0-9_]*\)=/setenv \1 /p' $?; \ ) > $@ @@ -376,119 +371,6 @@ jdkpath.sh: $(BUILDTREE_MAKE) echo "JDK=${JAVA_HOME}"; \ ) > $@ -.dbxrc: $(BUILDTREE_MAKE) - @echo Creating $@ ... - $(QUIETLY) ( \ - echo "echo '# Loading $(PLATFORM_DIR)/$(TARGET)/.dbxrc'"; \ - echo "if [ -f \"\$${HOTSPOT_DBXWARE}\" ]"; \ - echo "then"; \ - echo " source \"\$${HOTSPOT_DBXWARE}\""; \ - echo "elif [ -f \"\$$HOME/.dbxrc\" ]"; \ - echo "then"; \ - echo " source \"\$$HOME/.dbxrc\""; \ - echo "fi"; \ - ) > $@ - -# Skip the test for product builds (which only work when installed in a JDK), to -# avoid exiting with an error and causing make to halt. -NO_TEST_MSG = \ - echo "$@: skipping the test--this build must be tested in a JDK." - -NO_JAVA_HOME_MSG = \ - echo "JAVA_HOME must be set to run this test." - -DATA_MODE = $(DATA_MODE/$(BUILDARCH)) -JAVA_FLAG = $(JAVA_FLAG/$(DATA_MODE)) - -DATA_MODE/i486 = 32 -DATA_MODE/sparc = 32 -DATA_MODE/sparcv9 = 64 -DATA_MODE/amd64 = 64 -DATA_MODE/ia64 = 64 -DATA_MODE/zero = $(ARCH_DATA_MODEL) - -JAVA_FLAG/32 = -d32 -JAVA_FLAG/64 = -d64 - -WRONG_DATA_MODE_MSG = \ - echo "JAVA_HOME must point to a $(DATA_MODE)-bit OpenJDK." - -CROSS_COMPILING_MSG = \ - echo "Cross compiling for ARCH $(CROSS_COMPILE_ARCH), skipping gamma run." - -test_gamma: $(BUILDTREE_MAKE) $(GAMMADIR)/make/test/Queens.java - @echo Creating $@ ... - $(QUIETLY) ( \ - echo "#!/bin/sh"; \ - echo ""; \ - $(BUILDTREE_COMMENT); \ - echo ""; \ - echo "# Include environment settings for gamma run"; \ - echo ""; \ - echo ". ./env.sh"; \ - echo ""; \ - echo "# Do not run gamma test for cross compiles"; \ - echo ""; \ - echo "if [ -n \"$(CROSS_COMPILE_ARCH)\" ]; then "; \ - echo " $(CROSS_COMPILING_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "# Make sure JAVA_HOME is set as it is required for gamma"; \ - echo ""; \ - echo "if [ -z \"\$${JAVA_HOME}\" ]; then "; \ - echo " $(NO_JAVA_HOME_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "# Check JAVA_HOME version to be used for the test"; \ - echo ""; \ - echo "\$${JAVA_HOME}/bin/java $(JAVA_FLAG) -fullversion > /dev/null 2>&1"; \ - echo "if [ \$$? -ne 0 ]; then "; \ - echo " $(WRONG_DATA_MODE_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "GAMMA_PROG=gamma"; \ - echo ""; \ - echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \ - echo " # Ensure architecture for gamma and JAVA_HOME is the same."; \ - echo " # NOTE: gamma assumes the OpenJDK directory layout."; \ - echo ""; \ - echo " GAMMA_ARCH=\"\`file \$${GAMMA_PROG} | awk '{print \$$NF}'\`\""; \ - echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/libjava.$(LIBRARY_SUFFIX)\""; \ - echo " if [ ! -f \$${JVM_LIB} ]; then"; \ - echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/$${LIBARCH}/libjava.$(LIBRARY_SUFFIX)\""; \ - echo " fi"; \ - echo " if [ ! -f \$${JVM_LIB} ] || [ -z \"\`file \$${JVM_LIB} | grep \$${GAMMA_ARCH}\`\" ]; then "; \ - echo " $(WRONG_DATA_MODE_MSG)"; \ - echo " exit 0"; \ - echo " fi"; \ - echo "fi"; \ - echo ""; \ - echo "# Compile Queens program for test"; \ - echo ""; \ - echo "rm -f Queens.class"; \ - echo "\$${JAVA_HOME}/bin/javac -d . $(GAMMADIR)/make/test/Queens.java"; \ - echo ""; \ - echo "# Set library path solely for gamma launcher test run"; \ - echo ""; \ - echo "LD_LIBRARY_PATH=.:$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \ - echo "export LD_LIBRARY_PATH"; \ - echo "unset LD_LIBRARY_PATH_32"; \ - echo "unset LD_LIBRARY_PATH_64"; \ - echo ""; \ - echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \ - echo " DYLD_LIBRARY_PATH=.:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/native_threads:\$${JAVA_HOME}/jre/lib:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \ - echo " export DYLD_LIBRARY_PATH"; \ - echo "fi"; \ - echo ""; \ - echo "# Use the gamma launcher and JAVA_HOME to run the test"; \ - echo ""; \ - echo "./\$${GAMMA_PROG} $(TESTFLAGS) Queens < /dev/null"; \ - ) > $@ - $(QUIETLY) chmod +x $@ - FORCE: .PHONY: all FORCE diff --git a/hotspot/make/bsd/makefiles/gcc.make b/hotspot/make/bsd/makefiles/gcc.make index 6d25e307bab..858173bf203 100644 --- a/hotspot/make/bsd/makefiles/gcc.make +++ b/hotspot/make/bsd/makefiles/gcc.make @@ -168,12 +168,12 @@ endif # conversions which might affect the values. To avoid that, we need to turn # it off explicitly. ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" -ACCEPTABLE_WARNINGS = -Wpointer-arith -Wsign-compare +WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef else -ACCEPTABLE_WARNINGS = -Wpointer-arith -Wconversion -Wsign-compare +WARNING_FLAGS = -Wpointer-arith -Wconversion -Wsign-compare -Wundef endif -CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(ACCEPTABLE_WARNINGS) +CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(WARNING_FLAGS) # Special cases CFLAGS_WARN/BYFILE = $(CFLAGS_WARN/$@)$(CFLAGS_WARN/DEFAULT$(CFLAGS_WARN/$@)) # XXXDARWIN: for _dyld_bind_fully_image_containing_address diff --git a/hotspot/make/bsd/makefiles/saproc.make b/hotspot/make/bsd/makefiles/saproc.make index 4fb216b41f6..62e31a63dc0 100644 --- a/hotspot/make/bsd/makefiles/saproc.make +++ b/hotspot/make/bsd/makefiles/saproc.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ # Rules to build serviceability agent library, used by vm.make -# libsaproc.so: serviceability agent +# libsaproc.so(dylib): serviceability agent SAPROC = saproc ifeq ($(OS_VENDOR), Darwin) @@ -37,7 +37,7 @@ AGENT_DIR = $(GAMMADIR)/agent SASRCDIR = $(AGENT_DIR)/src/os/$(Platform_os_family) -NON_STUB_SASRCFILES = $(SASRCDIR)/salibelf.c \ +BSD_NON_STUB_SASRCFILES = $(SASRCDIR)/salibelf.c \ $(SASRCDIR)/symtab.c \ $(SASRCDIR)/libproc_impl.c \ $(SASRCDIR)/ps_proc.c \ @@ -45,13 +45,19 @@ NON_STUB_SASRCFILES = $(SASRCDIR)/salibelf.c \ $(SASRCDIR)/BsdDebuggerLocal.c \ $(AGENT_DIR)/src/share/native/sadis.c +DARWIN_NON_STUB_SASRCFILES = $(SASRCDIR)/symtab.c \ + $(SASRCDIR)/libproc_impl.c \ + $(SASRCDIR)/ps_core.c \ + $(SASRCDIR)/MacosxDebuggerLocal.m \ + $(AGENT_DIR)/src/share/native/sadis.c + ifeq ($(OS_VENDOR), FreeBSD) - SASRCFILES = $(NON_STUB_SASRCFILES) + SASRCFILES = $(BSD_NON_STUB_SASRCFILES) SALIBS = -lutil -lthread_db SAARCH = $(ARCHFLAG) else ifeq ($(OS_VENDOR), Darwin) - SASRCFILES = $(SASRCDIR)/MacosxDebuggerLocal.m + SASRCFILES = $(DARWIN_NON_STUB_SASRCFILES) SALIBS = -g -framework Foundation -F/System/Library/Frameworks/JavaVM.framework/Frameworks -framework JavaNativeFoundation -framework Security -framework CoreFoundation #objc compiler blows up on -march=i586, perhaps it should not be included in the macosx intel 32-bit C++ compiles? SAARCH = $(subst -march=i586,,$(ARCHFLAG)) @@ -102,7 +108,7 @@ $(LIBSAPROC): $(SASRCFILES) $(SAMAPFILE) fi @echo Making SA debugger back-end... $(QUIETLY) $(CC) -D$(BUILDARCH) -D_GNU_SOURCE \ - $(SYMFLAG) $(SAARCH) $(SHARED_FLAG) $(PICFLAG) \ + $(SYMFLAG) $(SAARCH) $(SHARED_FLAG) $(PICFLAG) \ -I$(SASRCDIR) \ -I$(GENERATED) \ $(BOOT_JAVA_INCLUDES) \ diff --git a/hotspot/make/defs.make b/hotspot/make/defs.make index 3d86ed70e6c..4e4c2cb0120 100644 --- a/hotspot/make/defs.make +++ b/hotspot/make/defs.make @@ -302,7 +302,7 @@ ifneq ($(OSNAME),windows) endif # Required make macro settings for all platforms -MAKE_ARGS += JAVA_HOME=$(ABS_BOOTDIR) +MAKE_ARGS += BOOTDIR=$(ABS_BOOTDIR) MAKE_ARGS += OUTPUTDIR=$(ABS_OUTPUTDIR) MAKE_ARGS += GAMMADIR=$(ABS_GAMMADIR) MAKE_ARGS += MAKE_VERBOSE=$(MAKE_VERBOSE) @@ -337,9 +337,6 @@ EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jni.h EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/$(JDK_INCLUDE_SUBDIR)/jni_md.h EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jmm.h -# By default, run Queens test after building -TEST_IN_BUILD ?= true - ifndef JAVASE_EMBEDDED EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jfr.h endif diff --git a/hotspot/make/excludeSrc.make b/hotspot/make/excludeSrc.make index b3c468f0455..1f044812352 100644 --- a/hotspot/make/excludeSrc.make +++ b/hotspot/make/excludeSrc.make @@ -69,7 +69,7 @@ ifeq ($(INCLUDE_CDS), false) CXXFLAGS += -DINCLUDE_CDS=0 CFLAGS += -DINCLUDE_CDS=0 - Src_Files_EXCLUDE += metaspaceShared.cpp + Src_Files_EXCLUDE += filemap.cpp metaspaceShared.cpp endif ifeq ($(INCLUDE_ALL_GCS), false) diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index b52c3c52dfb..69b8ad849df 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2013 HS_MAJOR_VER=25 HS_MINOR_VER=0 -HS_BUILD_NUMBER=22 +HS_BUILD_NUMBER=24 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 diff --git a/hotspot/make/jprt.properties b/hotspot/make/jprt.properties index fa65aa1bc7d..8bf107758c9 100644 --- a/hotspot/make/jprt.properties +++ b/hotspot/make/jprt.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -97,15 +97,18 @@ jprt.my.linux.ppcsflt.jdk7=linux_ppcsflt_2.6 jprt.my.linux.ppcsflt.jdk7u8=${jprt.my.linux.ppcsflt.jdk7} jprt.my.linux.ppcsflt=${jprt.my.linux.ppcsflt.${jprt.tools.default.release}} -jprt.my.linux.armvfp.jdk8=linux_armvfp_2.6 -jprt.my.linux.armvfp.jdk7=linux_armvfp_2.6 -jprt.my.linux.armvfp.jdk7u8=${jprt.my.linux.armvfp.jdk7} -jprt.my.linux.armvfp=${jprt.my.linux.armvfp.${jprt.tools.default.release}} +jprt.my.linux.armvfpsflt.jdk8=linux_armvfpsflt_2.6 +jprt.my.linux.armvfpsflt=${jprt.my.linux.armvfpsflt.${jprt.tools.default.release}} -jprt.my.linux.armv6.jdk8=linux_armv6_2.6 -jprt.my.linux.armv6.jdk7=linux_armv6_2.6 -jprt.my.linux.armv6.jdk7u8=${jprt.my.linux.armv6.jdk7} -jprt.my.linux.armv6=${jprt.my.linux.armv6.${jprt.tools.default.release}} +jprt.my.linux.armvfphflt.jdk8=linux_armvfphflt_2.6 +jprt.my.linux.armvfphflt=${jprt.my.linux.armvfphflt.${jprt.tools.default.release}} + +# The ARM GP vfp-sflt build is not currently supported +#jprt.my.linux.armvs.jdk8=linux_armvs_2.6 +#jprt.my.linux.armvs=${jprt.my.linux.armvs.${jprt.tools.default.release}} + +jprt.my.linux.armvh.jdk8=linux_armvh_2.6 +jprt.my.linux.armvh=${jprt.my.linux.armvh.${jprt.tools.default.release}} jprt.my.linux.armsflt.jdk8=linux_armsflt_2.6 jprt.my.linux.armsflt.jdk7=linux_armsflt_2.6 @@ -139,7 +142,7 @@ jprt.build.targets.standard= \ ${jprt.my.macosx.x64}-{product|fastdebug|debug}, \ ${jprt.my.windows.i586}-{product|fastdebug|debug}, \ ${jprt.my.windows.x64}-{product|fastdebug|debug}, \ - ${jprt.my.linux.armv6}-{product|fastdebug} + ${jprt.my.linux.armvh}-{product|fastdebug} jprt.build.targets.open= \ ${jprt.my.solaris.i586}-{productOpen}, \ @@ -151,7 +154,8 @@ jprt.build.targets.embedded= \ ${jprt.my.linux.ppc}-{productEmb|fastdebugEmb}, \ ${jprt.my.linux.ppcv2}-{productEmb|fastdebugEmb}, \ ${jprt.my.linux.ppcsflt}-{productEmb|fastdebugEmb}, \ - ${jprt.my.linux.armvfp}-{productEmb|fastdebugEmb}, \ + ${jprt.my.linux.armvfpsflt}-{productEmb|fastdebugEmb}, \ + ${jprt.my.linux.armvfphflt}-{productEmb|fastdebugEmb}, \ ${jprt.my.linux.armsflt}-{productEmb|fastdebugEmb} jprt.build.targets.all=${jprt.build.targets.standard}, \ diff --git a/hotspot/make/linux/Makefile b/hotspot/make/linux/Makefile index e8ef90718a4..04d0b8e5c64 100644 --- a/hotspot/make/linux/Makefile +++ b/hotspot/make/linux/Makefile @@ -300,63 +300,42 @@ platform_zero: $(GAMMADIR)/make/$(OSNAME)/platform_zero.in $(TARGETS_C2): $(SUBDIRS_C2) cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS) install endif $(TARGETS_TIERED): $(SUBDIRS_TIERED) cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_C1): $(SUBDIRS_C1) cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_CORE): $(SUBDIRS_CORE) cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_ZERO): $(SUBDIRS_ZERO) cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_SHARK): $(SUBDIRS_SHARK) cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_MINIMAL1): $(SUBDIRS_MINIMAL1) cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && $(MAKE) $(MFLAGS) install endif diff --git a/hotspot/make/linux/makefiles/buildtree.make b/hotspot/make/linux/makefiles/buildtree.make index 960b8f316fb..b75b4d57876 100644 --- a/hotspot/make/linux/makefiles/buildtree.make +++ b/hotspot/make/linux/makefiles/buildtree.make @@ -50,7 +50,6 @@ # jvmti.make - generate JVMTI bindings from the spec (JSR-163) # sa.make - generate SA jar file and natives # env.[ck]sh - environment settings -# test_gamma - script to run the Queens program # # The makefiles are split this way so that "make foo" will run faster by not # having to read the dependency files for the vm. @@ -64,9 +63,6 @@ include $(GAMMADIR)/make/altsrc.make # 'gmake MAKE_VERBOSE=y' or 'gmake QUIETLY=' gives all the gory details. QUIETLY$(MAKE_VERBOSE) = @ -# For now, until the compiler is less wobbly: -TESTFLAGS = -Xbatch -showversion - ifeq ($(findstring true, $(JVM_VARIANT_ZERO) $(JVM_VARIANT_ZEROSHARK)), true) PLATFORM_FILE = $(shell dirname $(shell dirname $(shell pwd)))/platform_zero else @@ -128,7 +124,7 @@ SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS)) BUILDTREE_MAKE = $(GAMMADIR)/make/$(OS_FAMILY)/makefiles/buildtree.make BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make sa.make \ - env.sh env.csh jdkpath.sh .dbxrc test_gamma + env.sh env.csh jdkpath.sh BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \ SRCARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT) @@ -345,7 +341,7 @@ env.sh: $(BUILDTREE_MAKE) @echo Creating $@ ... $(QUIETLY) ( \ $(BUILDTREE_COMMENT); \ - [ -n "$$JAVA_HOME" ] && { echo ": \$${JAVA_HOME:=$${JAVA_HOME}}"; }; \ + { echo "JAVA_HOME=$(JDK_IMPORT_PATH)"; }; \ { \ echo "CLASSPATH=$${CLASSPATH:+$$CLASSPATH:}.:\$${JAVA_HOME}/jre/lib/rt.jar:\$${JAVA_HOME}/jre/lib/i18n.jar"; \ } | sed s:$${JAVA_HOME:--------}:\$${JAVA_HOME}:g; \ @@ -357,8 +353,7 @@ env.csh: env.sh @echo Creating $@ ... $(QUIETLY) ( \ $(BUILDTREE_COMMENT); \ - [ -n "$$JAVA_HOME" ] && \ - { echo "if (! \$$?JAVA_HOME) setenv JAVA_HOME \"$$JAVA_HOME\""; }; \ + { echo "setenv JAVA_HOME \"$(JDK_IMPORT_PATH)\""; }; \ sed -n 's/^\([A-Za-z_][A-Za-z0-9_]*\)=/setenv \1 /p' $?; \ ) > $@ @@ -369,119 +364,6 @@ jdkpath.sh: $(BUILDTREE_MAKE) echo "JDK=${JAVA_HOME}"; \ ) > $@ -.dbxrc: $(BUILDTREE_MAKE) - @echo Creating $@ ... - $(QUIETLY) ( \ - echo "echo '# Loading $(PLATFORM_DIR)/$(TARGET)/.dbxrc'"; \ - echo "if [ -f \"\$${HOTSPOT_DBXWARE}\" ]"; \ - echo "then"; \ - echo " source \"\$${HOTSPOT_DBXWARE}\""; \ - echo "elif [ -f \"\$$HOME/.dbxrc\" ]"; \ - echo "then"; \ - echo " source \"\$$HOME/.dbxrc\""; \ - echo "fi"; \ - ) > $@ - -# Skip the test for product builds (which only work when installed in a JDK), to -# avoid exiting with an error and causing make to halt. -NO_TEST_MSG = \ - echo "$@: skipping the test--this build must be tested in a JDK." - -NO_JAVA_HOME_MSG = \ - echo "JAVA_HOME must be set to run this test." - -DATA_MODE = $(DATA_MODE/$(BUILDARCH)) -JAVA_FLAG = $(JAVA_FLAG/$(DATA_MODE)) - -DATA_MODE/i486 = 32 -DATA_MODE/sparc = 32 -DATA_MODE/sparcv9 = 64 -DATA_MODE/amd64 = 64 -DATA_MODE/ia64 = 64 -DATA_MODE/zero = $(ARCH_DATA_MODEL) - -JAVA_FLAG/32 = -d32 -JAVA_FLAG/64 = -d64 - -WRONG_DATA_MODE_MSG = \ - echo "JAVA_HOME must point to a $(DATA_MODE)-bit OpenJDK." - -CROSS_COMPILING_MSG = \ - echo "Cross compiling for ARCH $(CROSS_COMPILE_ARCH), skipping gamma run." - -test_gamma: $(BUILDTREE_MAKE) $(GAMMADIR)/make/test/Queens.java - @echo Creating $@ ... - $(QUIETLY) ( \ - echo "#!/bin/sh"; \ - echo ""; \ - $(BUILDTREE_COMMENT); \ - echo ""; \ - echo "# Include environment settings for gamma run"; \ - echo ""; \ - echo ". ./env.sh"; \ - echo ""; \ - echo "# Do not run gamma test for cross compiles"; \ - echo ""; \ - echo "if [ -n \"$(CROSS_COMPILE_ARCH)\" ]; then "; \ - echo " $(CROSS_COMPILING_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "# Make sure JAVA_HOME is set as it is required for gamma"; \ - echo ""; \ - echo "if [ -z \"\$${JAVA_HOME}\" ]; then "; \ - echo " $(NO_JAVA_HOME_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "# Check JAVA_HOME version to be used for the test"; \ - echo ""; \ - echo "\$${JAVA_HOME}/bin/java $(JAVA_FLAG) -fullversion > /dev/null 2>&1"; \ - echo "if [ \$$? -ne 0 ]; then "; \ - echo " $(WRONG_DATA_MODE_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "GAMMA_PROG=gamma"; \ - echo ""; \ - echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \ - echo " # Ensure architecture for gamma and JAVA_HOME is the same."; \ - echo " # NOTE: gamma assumes the OpenJDK directory layout."; \ - echo ""; \ - echo " GAMMA_ARCH=\"\`file \$${GAMMA_PROG} | awk '{print \$$NF}'\`\""; \ - echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/libjava.$(LIBRARY_SUFFIX)\""; \ - echo " if [ ! -f \$${JVM_LIB} ]; then"; \ - echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/$${LIBARCH}/libjava.$(LIBRARY_SUFFIX)\""; \ - echo " fi"; \ - echo " if [ ! -f \$${JVM_LIB} ] || [ -z \"\`file \$${JVM_LIB} | grep \$${GAMMA_ARCH}\`\" ]; then "; \ - echo " $(WRONG_DATA_MODE_MSG)"; \ - echo " exit 0"; \ - echo " fi"; \ - echo "fi"; \ - echo ""; \ - echo "# Compile Queens program for test"; \ - echo ""; \ - echo "rm -f Queens.class"; \ - echo "\$${JAVA_HOME}/bin/javac -d . $(GAMMADIR)/make/test/Queens.java"; \ - echo ""; \ - echo "# Set library path solely for gamma launcher test run"; \ - echo ""; \ - echo "LD_LIBRARY_PATH=.:$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \ - echo "export LD_LIBRARY_PATH"; \ - echo "unset LD_LIBRARY_PATH_32"; \ - echo "unset LD_LIBRARY_PATH_64"; \ - echo ""; \ - echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \ - echo " DYLD_LIBRARY_PATH=.:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/native_threads:\$${JAVA_HOME}/jre/lib:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \ - echo " export DYLD_LIBRARY_PATH"; \ - echo "fi"; \ - echo ""; \ - echo "# Use the gamma launcher and JAVA_HOME to run the test"; \ - echo ""; \ - echo "./\$${GAMMA_PROG} $(TESTFLAGS) Queens < /dev/null"; \ - ) > $@ - $(QUIETLY) chmod +x $@ - FORCE: .PHONY: all FORCE diff --git a/hotspot/make/linux/makefiles/gcc.make b/hotspot/make/linux/makefiles/gcc.make index 9ef83664535..b2c4bdfa491 100644 --- a/hotspot/make/linux/makefiles/gcc.make +++ b/hotspot/make/linux/makefiles/gcc.make @@ -131,12 +131,12 @@ WARNINGS_ARE_ERRORS = -Werror # conversions which might affect the values. To avoid that, we need to turn # it off explicitly. ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" -ACCEPTABLE_WARNINGS = -Wpointer-arith -Wsign-compare +WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef else -ACCEPTABLE_WARNINGS = -Wpointer-arith -Wconversion -Wsign-compare +WARNING_FLAGS = -Wpointer-arith -Wconversion -Wsign-compare -Wundef endif -CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(ACCEPTABLE_WARNINGS) +CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(WARNING_FLAGS) # Special cases CFLAGS_WARN/BYFILE = $(CFLAGS_WARN/$@)$(CFLAGS_WARN/DEFAULT$(CFLAGS_WARN/$@)) diff --git a/hotspot/make/solaris/Makefile b/hotspot/make/solaris/Makefile index 83e4df66579..7ae82d856f3 100644 --- a/hotspot/make/solaris/Makefile +++ b/hotspot/make/solaris/Makefile @@ -231,36 +231,24 @@ $(SUBDIRS_CORE): $(BUILDTREE_MAKE) $(TARGETS_C2): $(SUBDIRS_C2) cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS) install endif $(TARGETS_TIERED): $(SUBDIRS_TIERED) cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_C1): $(SUBDIRS_C1) cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_CORE): $(SUBDIRS_CORE) cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) install endif diff --git a/hotspot/make/solaris/makefiles/buildtree.make b/hotspot/make/solaris/makefiles/buildtree.make index a9e5a401c00..707d5f36a8d 100644 --- a/hotspot/make/solaris/makefiles/buildtree.make +++ b/hotspot/make/solaris/makefiles/buildtree.make @@ -50,21 +50,19 @@ # jvmti.make - generate JVMTI bindings from the spec (JSR-163) # sa.make - generate SA jar file and natives # env.[ck]sh - environment settings -# test_gamma - script to run the Queens program # # The makefiles are split this way so that "make foo" will run faster by not # having to read the dependency files for the vm. -include $(SPEC) include $(GAMMADIR)/make/scm.make +include $(GAMMADIR)/make/defs.make include $(GAMMADIR)/make/altsrc.make + # 'gmake MAKE_VERBOSE=y' or 'gmake QUIETLY=' gives all the gory details. QUIETLY$(MAKE_VERBOSE) = @ -# For now, until the compiler is less wobbly: -TESTFLAGS = -Xbatch -Xmx32m -showversion - ### maye ARCH_XXX instead? ifdef USE_GCC PLATFORM_FILE = $(GAMMADIR)/make/$(OS_FAMILY)/platform_$(BUILDARCH).gcc @@ -119,7 +117,7 @@ SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS)) BUILDTREE_MAKE = $(GAMMADIR)/make/$(OS_FAMILY)/makefiles/buildtree.make BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make sa.make \ - env.sh env.csh jdkpath.sh .dbxrc test_gamma + env.sh env.csh jdkpath.sh BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \ ARCH=$(ARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT) @@ -334,7 +332,7 @@ env.sh: $(BUILDTREE_MAKE) @echo Creating $@ ... $(QUIETLY) ( \ $(BUILDTREE_COMMENT); \ - [ -n "$$JAVA_HOME" ] && { echo ": \$${JAVA_HOME:=$${JAVA_HOME}}"; }; \ + { echo "JAVA_HOME=$(JDK_IMPORT_PATH)"; }; \ { \ echo "CLASSPATH=$${CLASSPATH:+$$CLASSPATH:}.:\$${JAVA_HOME}/jre/lib/rt.jar:\$${JAVA_HOME}/jre/lib/i18n.jar"; \ } | sed s:$${JAVA_HOME:--------}:\$${JAVA_HOME}:g; \ @@ -346,8 +344,7 @@ env.csh: env.sh @echo Creating $@ ... $(QUIETLY) ( \ $(BUILDTREE_COMMENT); \ - [ -n "$$JAVA_HOME" ] && \ - { echo "if (! \$$?JAVA_HOME) setenv JAVA_HOME \"$$JAVA_HOME\""; }; \ + { echo "setenv JAVA_HOME \"$(JDK_IMPORT_PATH)\""; }; \ sed -n 's/^\([A-Za-z_][A-Za-z0-9_]*\)=/setenv \1 /p' $?; \ ) > $@ @@ -358,124 +355,6 @@ jdkpath.sh: $(BUILDTREE_MAKE) echo "JDK=${JAVA_HOME}"; \ ) > $@ -.dbxrc: $(BUILDTREE_MAKE) - @echo Creating $@ ... - $(QUIETLY) ( \ - echo "echo '# Loading $(PLATFORM_DIR)/$(TARGET)/.dbxrc'"; \ - echo "if [ -f \"\$${HOTSPOT_DBXWARE}\" ]"; \ - echo "then"; \ - echo " source \"\$${HOTSPOT_DBXWARE}\""; \ - echo "elif [ -f \"\$$HOME/.dbxrc\" ]"; \ - echo "then"; \ - echo " source \"\$$HOME/.dbxrc\""; \ - echo "fi"; \ - ) > $@ - -# Skip the test for product builds (which only work when installed in a JDK), to -# avoid exiting with an error and causing make to halt. -NO_TEST_MSG = \ - echo "$@: skipping the test--this build must be tested in a JDK." - -NO_JAVA_HOME_MSG = \ - echo "JAVA_HOME must be set to run this test." - -DATA_MODE = $(DATA_MODE/$(BUILDARCH)) -JAVA_FLAG = $(JAVA_FLAG/$(DATA_MODE)) - -DATA_MODE/i486 = 32 -DATA_MODE/sparc = 32 -DATA_MODE/sparcv9 = 64 -DATA_MODE/amd64 = 64 -DATA_MODE/ia64 = 64 - -# This bit is needed to enable local rebuilds. -# Unless the makefile itself sets LP64, any environmental -# setting of LP64 will interfere with the build. -LP64_SETTING/32 = LP64 = \#empty -LP64_SETTING/64 = LP64 = 1 - -JAVA_FLAG/32 = -d32 -JAVA_FLAG/64 = -d64 - -WRONG_DATA_MODE_MSG = \ - echo "JAVA_HOME must point to a $(DATA_MODE)-bit OpenJDK." - -CROSS_COMPILING_MSG = \ - echo "Cross compiling for ARCH $(CROSS_COMPILE_ARCH), skipping gamma run." - -test_gamma: $(BUILDTREE_MAKE) $(GAMMADIR)/make/test/Queens.java - @echo Creating $@ ... - $(QUIETLY) ( \ - echo "#!/bin/sh"; \ - echo ""; \ - $(BUILDTREE_COMMENT); \ - echo ""; \ - echo "# Include environment settings for gamma run"; \ - echo ""; \ - echo ". ./env.sh"; \ - echo ""; \ - echo "# Do not run gamma test for cross compiles"; \ - echo ""; \ - echo "if [ -n \"$(CROSS_COMPILE_ARCH)\" ]; then "; \ - echo " $(CROSS_COMPILING_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "# Make sure JAVA_HOME is set as it is required for gamma"; \ - echo ""; \ - echo "if [ -z \"\$${JAVA_HOME}\" ]; then "; \ - echo " $(NO_JAVA_HOME_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "# Check JAVA_HOME version to be used for the test"; \ - echo ""; \ - echo "\$${JAVA_HOME}/bin/java $(JAVA_FLAG) -fullversion > /dev/null 2>&1"; \ - echo "if [ \$$? -ne 0 ]; then "; \ - echo " $(WRONG_DATA_MODE_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "GAMMA_PROG=gamma"; \ - echo ""; \ - echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \ - echo " # Ensure architecture for gamma and JAVA_HOME is the same."; \ - echo " # NOTE: gamma assumes the OpenJDK directory layout."; \ - echo ""; \ - echo " GAMMA_ARCH=\"\`file \$${GAMMA_PROG} | awk '{print \$$NF}'\`\""; \ - echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/libjava.$(LIBRARY_SUFFIX)\""; \ - echo " if [ ! -f \$${JVM_LIB} ]; then"; \ - echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/$${LIBARCH}/libjava.$(LIBRARY_SUFFIX)\""; \ - echo " fi"; \ - echo " if [ ! -f \$${JVM_LIB} ] || [ -z \"\`file \$${JVM_LIB} | grep \$${GAMMA_ARCH}\`\" ]; then "; \ - echo " $(WRONG_DATA_MODE_MSG)"; \ - echo " exit 0"; \ - echo " fi"; \ - echo "fi"; \ - echo ""; \ - echo "# Compile Queens program for test"; \ - echo ""; \ - echo "rm -f Queens.class"; \ - echo "\$${JAVA_HOME}/bin/javac -d . $(GAMMADIR)/make/test/Queens.java"; \ - echo ""; \ - echo "# Set library path solely for gamma launcher test run"; \ - echo ""; \ - echo "LD_LIBRARY_PATH=.:$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \ - echo "export LD_LIBRARY_PATH"; \ - echo "unset LD_LIBRARY_PATH_32"; \ - echo "unset LD_LIBRARY_PATH_64"; \ - echo ""; \ - echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \ - echo " DYLD_LIBRARY_PATH=.:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/native_threads:\$${JAVA_HOME}/jre/lib:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \ - echo " export DYLD_LIBRARY_PATH"; \ - echo "fi"; \ - echo ""; \ - echo "# Use the gamma launcher and JAVA_HOME to run the test"; \ - echo ""; \ - echo "./\$${GAMMA_PROG} $(TESTFLAGS) Queens < /dev/null"; \ - ) > $@ - $(QUIETLY) chmod +x $@ - FORCE: .PHONY: all FORCE diff --git a/hotspot/make/solaris/makefiles/gcc.make b/hotspot/make/solaris/makefiles/gcc.make index 66ab8c55d6a..e946d65d256 100644 --- a/hotspot/make/solaris/makefiles/gcc.make +++ b/hotspot/make/solaris/makefiles/gcc.make @@ -118,8 +118,8 @@ endif # Compiler warnings are treated as errors WARNINGS_ARE_ERRORS = -Werror # Enable these warnings. See 'info gcc' about details on these options -ADDITIONAL_WARNINGS = -Wpointer-arith -Wconversion -Wsign-compare -CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(ADDITIONAL_WARNINGS) +WARNING_FLAGS = -Wpointer-arith -Wconversion -Wsign-compare -Wundef +CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(WARNING_FLAGS) # Special cases CFLAGS_WARN/BYFILE = $(CFLAGS_WARN/$@)$(CFLAGS_WARN/DEFAULT$(CFLAGS_WARN/$@)) diff --git a/hotspot/make/test/Queens.java b/hotspot/make/test/Queens.java deleted file mode 100644 index ab7a9e2c135..00000000000 --- a/hotspot/make/test/Queens.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2006, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -import java.util.*; - -// Copyright 1996, Animorphic Systems -// gri 28 Aug 92 / 15 Jan 93 / 8 Dec 95 - -class Queens { - - static void try_i(boolean a[], boolean b[], boolean c[], int x[], int i) { - int adj = 7; - - for (int j = 1; j <= 8; j++) { - if (b[j] && a[i+j] && c[adj+i-j]) { - x[i] = j; - b[j] = false; - a[i+j] = false; - c[adj+i-j] = false; - if (i < 8) try_i(a, b, c, x, i+1); - else print(x); - b[j] = true; - a[i+j] = true; - c[adj+i-j] = true; - } - } - } - - public static void main(String s[]) { - boolean a[] = new boolean[16+1]; - boolean b[] = new boolean[ 8+1]; - boolean c[] = new boolean[14+1]; - int x[] = new int[8+1]; - int adj = 7; - - for (int i = -7; i <= 16; i++) { - if (i >= 1 && i <= 8) b[i] = true; - if (i >= 2) a[i] = true; - if (i <= 7) c[adj+i] = true; - } - - x[0] = 0; // solution counter - - try_i(a, b, c, x, 1); - } - - static void print(int x[]) { - // first correct solution: A1 B5 C8 D6 E3 F7 G2 H4 - - char LF = (char)0xA; - char CR = (char)0xD; - - x[0]++; - if (x[0] < 10) - System.out.print(" "); - System.out.print(x[0] + ". "); - for (int i = 1; i <= 8; i++) { - char p = (char)('A' + i - 1); - System.out.print(p); - System.out.print (x[i] + " "); - } - System.out.println(); - } - -}; diff --git a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp index 4918746db13..b1451fb0bae 100644 --- a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp @@ -2194,7 +2194,8 @@ int AbstractInterpreter::layout_activation(Method* method, int callee_locals_size, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { assert(popframe_extra_args == 0, "NEED TO FIX"); // NOTE this code must exactly mimic what InterpreterGenerator::generate_compute_interpreter_state() diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp index 251e42cd6af..578650a3419 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp @@ -1385,13 +1385,13 @@ void MacroAssembler::_verify_oop(Register reg, const char* msg, const char * fil } #endif - int len = strlen(file) + strlen(msg) + 1 + 4; - sprintf(buffer, "%d", line); - len += strlen(buffer); - sprintf(buffer, " at offset %d ", offset()); - len += strlen(buffer); - char * real_msg = new char[len]; - sprintf(real_msg, "%s%s(%s:%d)", msg, buffer, file, line); + const char* real_msg = NULL; + { + ResourceMark rm; + stringStream ss; + ss.print("%s at offset %d (%s:%d)", msg, offset(), file, line); + real_msg = code_string(ss.as_string()); + } // Call indirectly to solve generation ordering problem AddressLiteral a(StubRoutines::verify_oop_subroutine_entry_address()); @@ -1423,13 +1423,13 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* msg, const char // plausibility check for oops if (!VerifyOops) return; - char buffer[64]; - sprintf(buffer, "%d", line); - int len = strlen(file) + strlen(msg) + 1 + 4 + strlen(buffer); - sprintf(buffer, " at SP+%d ", addr.disp()); - len += strlen(buffer); - char * real_msg = new char[len]; - sprintf(real_msg, "%s at SP+%d (%s:%d)", msg, addr.disp(), file, line); + const char* real_msg = NULL; + { + ResourceMark rm; + stringStream ss; + ss.print("%s at SP+%d (%s:%d)", msg, addr.disp(), file, line); + real_msg = code_string(ss.as_string()); + } // Call indirectly to solve generation ordering problem AddressLiteral a(StubRoutines::verify_oop_subroutine_entry_address()); @@ -1622,9 +1622,13 @@ void MacroAssembler::untested(const char* what) { // in order to run automated test scripts on the VM // Use the flag ShowMessageBoxOnError - char* b = new char[1024]; - sprintf(b, "untested: %s", what); - + const char* b = NULL; + { + ResourceMark rm; + stringStream ss; + ss.print("untested: %s", what); + b = code_string(ss.as_string()); + } if (ShowMessageBoxOnError) { STOP(b); } else { warn(b); } } diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp index b5cfa00f975..4a6372ae0de 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp @@ -1581,7 +1581,8 @@ int AbstractInterpreter::layout_activation(Method* method, int callee_local_count, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { // Note: This calculation must exactly parallel the frame setup // in InterpreterGenerator::generate_fixed_frame. // If f!=NULL, set up the following variables: @@ -1664,6 +1665,15 @@ int AbstractInterpreter::layout_activation(Method* method, int delta = local_words - parm_words; int computed_sp_adjustment = (delta > 0) ? round_to(delta, WordsPerLong) : 0; *interpreter_frame->register_addr(I5_savedSP) = (intptr_t) (fp + computed_sp_adjustment) - STACK_BIAS; + if (!is_bottom_frame) { + // Llast_SP is set below for the current frame to SP (with the + // extra space for the callee's locals). Here we adjust + // Llast_SP for the caller's frame, removing the extra space + // for the current method's locals. + *caller->register_addr(Llast_SP) = *interpreter_frame->register_addr(I5_savedSP); + } else { + assert(*caller->register_addr(Llast_SP) >= *interpreter_frame->register_addr(I5_savedSP), "strange Llast_SP"); + } } else { assert(caller->is_compiled_frame() || caller->is_entry_frame(), "only possible cases"); // Don't have Lesp available; lay out locals block in the caller diff --git a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp index 55b29fb2f6c..c568c6f4d3a 100644 --- a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp +++ b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp @@ -2361,7 +2361,8 @@ int AbstractInterpreter::layout_activation(Method* method, int callee_locals, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { assert(popframe_extra_args == 0, "FIX ME"); // NOTE this code must exactly mimic what InterpreterGenerator::generate_compute_interpreter_state() diff --git a/hotspot/src/cpu/x86/vm/frame_x86.cpp b/hotspot/src/cpu/x86/vm/frame_x86.cpp index fa0855c458c..93180c8e37d 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.cpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp @@ -356,7 +356,7 @@ frame frame::sender_for_entry_frame(RegisterMap* map) const { // Verifies the calculated original PC of a deoptimization PC for the // given unextended SP. The unextended SP might also be the saved SP // for MethodHandle call sites. -#if ASSERT +#ifdef ASSERT void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return) { frame fr; diff --git a/hotspot/src/cpu/x86/vm/frame_x86.hpp b/hotspot/src/cpu/x86/vm/frame_x86.hpp index b3c3f416c46..0033077dde4 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.hpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.hpp @@ -170,7 +170,7 @@ return (intptr_t*) addr_at(offset); } -#if ASSERT +#ifdef ASSERT // Used in frame::sender_for_{interpreter,compiled}_frame static void verify_deopt_original_pc( nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false); static void verify_deopt_mh_original_pc(nmethod* nm, intptr_t* unextended_sp) { diff --git a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp index ea8111b9fd7..b15b00be586 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp @@ -295,14 +295,18 @@ inline bool frame::volatile_across_calls(Register reg) { return true; } +inline oop frame::saved_oop_result(RegisterMap* map) const { + oop* result_adr = (oop *)map->location(rax->as_VMReg()); + guarantee(result_adr != NULL, "bad register save location"); - -inline oop frame::saved_oop_result(RegisterMap* map) const { - return *((oop*) map->location(rax->as_VMReg())); + return (*result_adr); } inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) { - *((oop*) map->location(rax->as_VMReg())) = obj; + oop* result_adr = (oop *)map->location(rax->as_VMReg()); + guarantee(result_adr != NULL, "bad register save location"); + + *result_adr = obj; } #endif // CPU_X86_VM_FRAME_X86_INLINE_HPP diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index bda1550ac25..b64518a7bc1 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -4262,8 +4262,13 @@ void MacroAssembler::verify_oop(Register reg, const char* s) { if (!VerifyOops) return; // Pass register number to verify_oop_subroutine - char* b = new char[strlen(s) + 50]; - sprintf(b, "verify_oop: %s: %s", reg->name(), s); + const char* b = NULL; + { + ResourceMark rm; + stringStream ss; + ss.print("verify_oop: %s: %s", reg->name(), s); + b = code_string(ss.as_string()); + } BLOCK_COMMENT("verify_oop {"); #ifdef _LP64 push(rscratch1); // save r10, trashed by movptr() @@ -4297,9 +4302,14 @@ RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_ad { Label L; testptr(tmp, tmp); if (WizardMode) { + const char* buf = NULL; + { + ResourceMark rm; + stringStream ss; + ss.print("DelayedValue="INTPTR_FORMAT, delayed_value_addr[1]); + buf = code_string(ss.as_string()); + } jcc(Assembler::notZero, L); - char* buf = new char[40]; - sprintf(buf, "DelayedValue="INTPTR_FORMAT, delayed_value_addr[1]); STOP(buf); } else { jccb(Assembler::notZero, L); @@ -4343,9 +4353,13 @@ void MacroAssembler::verify_oop_addr(Address addr, const char* s) { // Address adjust(addr.base(), addr.index(), addr.scale(), addr.disp() + BytesPerWord); // Pass register number to verify_oop_subroutine - char* b = new char[strlen(s) + 50]; - sprintf(b, "verify_oop_addr: %s", s); - + const char* b = NULL; + { + ResourceMark rm; + stringStream ss; + ss.print("verify_oop_addr: %s", s); + b = code_string(ss.as_string()); + } #ifdef _LP64 push(rscratch1); // save r10, trashed by movptr() #endif diff --git a/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp b/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp index d4a929613ab..e16c6653960 100644 --- a/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp +++ b/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp @@ -145,12 +145,9 @@ address* Relocation::pd_address_in_code() { assert(which == Assembler::disp32_operand || which == Assembler::call32_operand || which == Assembler::imm_operand, "format unpacks ok"); - if (which != Assembler::imm_operand) { - // The "address" in the code is a displacement can't return it as - // and address* since it is really a jint* - ShouldNotReachHere(); - return NULL; - } + // The "address" in the code is a displacement can't return it as + // and address* since it is really a jint* + guarantee(which == Assembler::imm_operand, "must be immediate operand"); #else assert(which == Assembler::disp32_operand || which == Assembler::imm_operand, "format unpacks ok"); #endif // AMD64 diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp index a562bee3e53..5df98394cf5 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp @@ -1585,7 +1585,8 @@ int AbstractInterpreter::layout_activation(Method* method, int callee_locals, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { // Note: This calculation must exactly parallel the frame setup // in AbstractInterpreterGenerator::generate_method_entry. // If interpreter_frame!=NULL, set up the method, locals, and monitors. diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp index 26eadba79b2..c446cb3c9b1 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp @@ -1599,7 +1599,8 @@ int AbstractInterpreter::layout_activation(Method* method, int callee_locals, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { // Note: This calculation must exactly parallel the frame setup // in AbstractInterpreterGenerator::generate_method_entry. // If interpreter_frame!=NULL, set up the method, locals, and monitors. diff --git a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp index a199d037cbc..10501655dbb 100644 --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp @@ -919,7 +919,8 @@ int AbstractInterpreter::layout_activation(Method* method, int callee_locals, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { assert(popframe_extra_args == 0, "what to do?"); assert(!is_top_frame || (!callee_locals && !callee_param_count), "top frame should have no caller"); diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index b407b4251fd..a09db37288f 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -57,6 +57,7 @@ #include "runtime/threadCritical.hpp" #include "runtime/timer.hpp" #include "services/attachListener.hpp" +#include "services/memTracker.hpp" #include "services/runtimeService.hpp" #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" @@ -2275,13 +2276,25 @@ char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) { return NULL; } + // The memory is committed + address pc = CALLER_PC; + MemTracker::record_virtual_memory_reserve((address)addr, bytes, pc); + MemTracker::record_virtual_memory_commit((address)addr, bytes, pc); + return addr; } bool os::release_memory_special(char* base, size_t bytes) { // detaching the SHM segment will also delete it, see reserve_memory_special() int rslt = shmdt(base); - return rslt == 0; + if (rslt == 0) { + MemTracker::record_virtual_memory_uncommit((address)base, bytes); + MemTracker::record_virtual_memory_release((address)base, bytes); + return true; + } else { + return false; + } + } size_t os::large_page_size() { diff --git a/hotspot/src/os/linux/vm/globals_linux.hpp b/hotspot/src/os/linux/vm/globals_linux.hpp index 56bb45213ad..af4947b1b86 100644 --- a/hotspot/src/os/linux/vm/globals_linux.hpp +++ b/hotspot/src/os/linux/vm/globals_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,9 @@ product(bool, UseHugeTLBFS, false, \ "Use MAP_HUGETLB for large pages") \ \ + product(bool, LoadExecStackDllInVMThread, true, \ + "Load DLLs with executable-stack attribute in the VM Thread") \ + \ product(bool, UseSHM, false, \ "Use SYSV shared memory for large pages") diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index b14615e58e8..59cb59d6805 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -44,6 +44,7 @@ #include "runtime/extendedPC.hpp" #include "runtime/globals.hpp" #include "runtime/interfaceSupport.hpp" +#include "runtime/init.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" #include "runtime/mutexLocker.hpp" @@ -57,10 +58,12 @@ #include "runtime/threadCritical.hpp" #include "runtime/timer.hpp" #include "services/attachListener.hpp" +#include "services/memTracker.hpp" #include "services/runtimeService.hpp" #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" +#include "utilities/elfFile.hpp" #include "utilities/growableArray.hpp" #include "utilities/vmError.hpp" @@ -1796,9 +1799,93 @@ bool os::dll_address_to_library_name(address addr, char* buf, // in case of error it checks if .dll/.so was built for the // same architecture as Hotspot is running on + +// Remember the stack's state. The Linux dynamic linker will change +// the stack to 'executable' at most once, so we must safepoint only once. +bool os::Linux::_stack_is_executable = false; + +// VM operation that loads a library. This is necessary if stack protection +// of the Java stacks can be lost during loading the library. If we +// do not stop the Java threads, they can stack overflow before the stacks +// are protected again. +class VM_LinuxDllLoad: public VM_Operation { + private: + const char *_filename; + void *_lib; + public: + VM_LinuxDllLoad(const char *fn) : + _filename(fn), _lib(NULL) {} + VMOp_Type type() const { return VMOp_LinuxDllLoad; } + void doit() { + _lib = os::Linux::dll_load_inner(_filename); + os::Linux::_stack_is_executable = true; + } + void* loaded_library() { return _lib; } +}; + void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { - void * result= ::dlopen(filename, RTLD_LAZY); + void * result = NULL; + bool load_attempted = false; + + // Check whether the library to load might change execution rights + // of the stack. If they are changed, the protection of the stack + // guard pages will be lost. We need a safepoint to fix this. + // + // See Linux man page execstack(8) for more info. + if (os::uses_stack_guard_pages() && !os::Linux::_stack_is_executable) { + ElfFile ef(filename); + if (!ef.specifies_noexecstack()) { + if (!is_init_completed()) { + os::Linux::_stack_is_executable = true; + // This is OK - No Java threads have been created yet, and hence no + // stack guard pages to fix. + // + // This should happen only when you are building JDK7 using a very + // old version of JDK6 (e.g., with JPRT) and running test_gamma. + // + // Dynamic loader will make all stacks executable after + // this function returns, and will not do that again. + assert(Threads::first() == NULL, "no Java threads should exist yet."); + } else { + warning("You have loaded library %s which might have disabled stack guard. " + "The VM will try to fix the stack guard now.\n" + "It's highly recommended that you fix the library with " + "'execstack -c ', or link it with '-z noexecstack'.", + filename); + + assert(Thread::current()->is_Java_thread(), "must be Java thread"); + JavaThread *jt = JavaThread::current(); + if (jt->thread_state() != _thread_in_native) { + // This happens when a compiler thread tries to load a hsdis-.so file + // that requires ExecStack. Cannot enter safe point. Let's give up. + warning("Unable to fix stack guard. Giving up."); + } else { + if (!LoadExecStackDllInVMThread) { + // This is for the case where the DLL has an static + // constructor function that executes JNI code. We cannot + // load such DLLs in the VMThread. + result = ::dlopen(filename, RTLD_LAZY); + } + + ThreadInVMfromNative tiv(jt); + debug_only(VMNativeEntryWrapper vew;) + + VM_LinuxDllLoad op(filename); + VMThread::execute(&op); + if (LoadExecStackDllInVMThread) { + result = op.loaded_library(); + } + load_attempted = true; + } + } + } + } + + if (!load_attempted) { + result = ::dlopen(filename, RTLD_LAZY); + } + if (result != NULL) { // Successful loading return result; @@ -1952,6 +2039,38 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) return NULL; } +void * os::Linux::dll_load_inner(const char *filename) { + void * result = NULL; + if (LoadExecStackDllInVMThread) { + result = ::dlopen(filename, RTLD_LAZY); + } + + // Since 7019808, libjvm.so is linked with -noexecstack. If the VM loads a + // library that requires an executable stack, or which does not have this + // stack attribute set, dlopen changes the stack attribute to executable. The + // read protection of the guard pages gets lost. + // + // Need to check _stack_is_executable again as multiple VM_LinuxDllLoad + // may have been queued at the same time. + + if (!_stack_is_executable) { + JavaThread *jt = Threads::first(); + + while (jt) { + if (!jt->stack_guard_zone_unused() && // Stack not yet fully initialized + jt->stack_yellow_zone_enabled()) { // No pending stack overflow exceptions + if (!os::guard_memory((char *) jt->stack_red_zone_base() - jt->stack_red_zone_size(), + jt->stack_yellow_zone_size() + jt->stack_red_zone_size())) { + warning("Attempt to reguard stack yellow zone failed."); + } + } + jt = jt->next(); + } + } + + return result; +} + /* * glibc-2.0 libdl is not MT safe. If you are building with any glibc, * chances are you might want to run the generated bits against glibc-2.0 @@ -3094,13 +3213,24 @@ char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) { numa_make_global(addr, bytes); } + // The memory is committed + address pc = CALLER_PC; + MemTracker::record_virtual_memory_reserve((address)addr, bytes, pc); + MemTracker::record_virtual_memory_commit((address)addr, bytes, pc); + return addr; } bool os::release_memory_special(char* base, size_t bytes) { // detaching the SHM segment will also delete it, see reserve_memory_special() int rslt = shmdt(base); - return rslt == 0; + if (rslt == 0) { + MemTracker::record_virtual_memory_uncommit((address)base, bytes); + MemTracker::record_virtual_memory_release((address)base, bytes); + return true; + } else { + return false; + } } size_t os::large_page_size() { diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp index 414ccd976fc..356f7f67afa 100644 --- a/hotspot/src/os/linux/vm/os_linux.hpp +++ b/hotspot/src/os/linux/vm/os_linux.hpp @@ -94,6 +94,9 @@ class Linux { static void print_libversion_info(outputStream* st); public: + static bool _stack_is_executable; + static void *dll_load_inner(const char *name); + static void init_thread_fpu_state(); static int get_fpu_control_word(); static void set_fpu_control_word(int fpu_control); diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index a80a0ea4590..bdd78ad0218 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -2945,7 +2945,7 @@ char *os::scan_pages(char *start, char* end, page_info* page_expected, page_info while (p < (uint64_t)end) { addrs[0] = p; size_t addrs_count = 1; - while (addrs_count < MAX_MEMINFO_CNT && addrs[addrs_count - 1] < (uint64_t)end) { + while (addrs_count < MAX_MEMINFO_CNT && addrs[addrs_count - 1] + page_size < (uint64_t)end) { addrs[addrs_count] = addrs[addrs_count - 1] + page_size; addrs_count++; } @@ -3420,13 +3420,25 @@ char* os::reserve_memory_special(size_t size, char* addr, bool exec) { if ((retAddr != NULL) && UseNUMAInterleaving) { numa_make_global(retAddr, size); } + + // The memory is committed + address pc = CALLER_PC; + MemTracker::record_virtual_memory_reserve((address)retAddr, size, pc); + MemTracker::record_virtual_memory_commit((address)retAddr, size, pc); + return retAddr; } bool os::release_memory_special(char* base, size_t bytes) { // detaching the SHM segment will also delete it, see reserve_memory_special() int rslt = shmdt(base); - return rslt == 0; + if (rslt == 0) { + MemTracker::record_virtual_memory_uncommit((address)base, bytes); + MemTracker::record_virtual_memory_release((address)base, bytes); + return true; + } else { + return false; + } } size_t os::large_page_size() { diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index b1556bf6491..4a99a1b3975 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -60,6 +60,7 @@ #include "runtime/threadCritical.hpp" #include "runtime/timer.hpp" #include "services/attachListener.hpp" +#include "services/memTracker.hpp" #include "services/runtimeService.hpp" #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" @@ -2836,7 +2837,7 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, PAGE_READWRITE); // If reservation failed, return NULL if (p_buf == NULL) return NULL; - + MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, CALLER_PC); os::release_memory(p_buf, bytes + chunk_size); // we still need to round up to a page boundary (in case we are using large pages) @@ -2898,6 +2899,11 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, if (next_alloc_addr > p_buf) { // Some memory was committed so release it. size_t bytes_to_release = bytes - bytes_remaining; + // NMT has yet to record any individual blocks, so it + // need to create a dummy 'reserve' record to match + // the release. + MemTracker::record_virtual_memory_reserve((address)p_buf, + bytes_to_release, CALLER_PC); os::release_memory(p_buf, bytes_to_release); } #ifdef ASSERT @@ -2909,10 +2915,19 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, #endif return NULL; } + bytes_remaining -= bytes_to_rq; next_alloc_addr += bytes_to_rq; count++; } + // Although the memory is allocated individually, it is returned as one. + // NMT records it as one block. + address pc = CALLER_PC; + MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, pc); + if ((flags & MEM_COMMIT) != 0) { + MemTracker::record_virtual_memory_commit((address)p_buf, bytes, pc); + } + // made it this far, success return p_buf; } @@ -3099,11 +3114,20 @@ char* os::reserve_memory_special(size_t bytes, char* addr, bool exec) { // normal policy just allocate it all at once DWORD flag = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES; char * res = (char *)VirtualAlloc(NULL, bytes, flag, prot); + if (res != NULL) { + address pc = CALLER_PC; + MemTracker::record_virtual_memory_reserve((address)res, bytes, pc); + MemTracker::record_virtual_memory_commit((address)res, bytes, pc); + } + return res; } } bool os::release_memory_special(char* base, size_t bytes) { + assert(base != NULL, "Sanity check"); + // Memory allocated via reserve_memory_special() is committed + MemTracker::record_virtual_memory_uncommit((address)base, bytes); return release_memory(base, bytes); } diff --git a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp index 9eabc200bb8..aa36599ea2a 100644 --- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp +++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp @@ -516,7 +516,7 @@ JVM_handle_bsd_signal(int sig, // here if the underlying file has been truncated. // Do not crash the VM in such a case. CodeBlob* cb = CodeCache::find_blob_unsafe(pc); - nmethod* nm = cb->is_nmethod() ? (nmethod*)cb : NULL; + nmethod* nm = (cb != NULL && cb->is_nmethod()) ? (nmethod*)cb : NULL; if (nm != NULL && nm->has_unsafe_access()) { stub = StubRoutines::handler_for_unsafe_access(); } diff --git a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp index 81c013301d2..cf8634f90cb 100644 --- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp +++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp @@ -410,6 +410,11 @@ inline static bool checkOverflow(sigcontext* uc, // to handle_unexpected_exception way down below. thread->disable_stack_red_zone(); tty->print_raw_cr("An irrecoverable stack overflow has occurred."); + + // This is a likely cause, but hard to verify. Let's just print + // it as a hint. + tty->print_raw_cr("Please check if any of your loaded .so files has " + "enabled executable stack (see man page execstack(8))"); } else { // Accessing stack address below sp may cause SEGV if current // thread has MAP_GROWSDOWN stack. This should only happen when diff --git a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp index bfb0e960a0c..5cdab45d4cb 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp +++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp @@ -305,6 +305,11 @@ JVM_handle_linux_signal(int sig, // to handle_unexpected_exception way down below. thread->disable_stack_red_zone(); tty->print_raw_cr("An irrecoverable stack overflow has occurred."); + + // This is a likely cause, but hard to verify. Let's just print + // it as a hint. + tty->print_raw_cr("Please check if any of your loaded .so files has " + "enabled executable stack (see man page execstack(8))"); } else { // Accessing stack address below sp may cause SEGV if current // thread has MAP_GROWSDOWN stack. This should only happen when @@ -335,7 +340,7 @@ JVM_handle_linux_signal(int sig, // here if the underlying file has been truncated. // Do not crash the VM in such a case. CodeBlob* cb = CodeCache::find_blob_unsafe(pc); - nmethod* nm = cb->is_nmethod() ? (nmethod*)cb : NULL; + nmethod* nm = (cb != NULL && cb->is_nmethod()) ? (nmethod*)cb : NULL; if (nm != NULL && nm->has_unsafe_access()) { stub = StubRoutines::handler_for_unsafe_access(); } diff --git a/hotspot/src/share/vm/asm/assembler.cpp b/hotspot/src/share/vm/asm/assembler.cpp index 669f49039fc..d23c0f50f2e 100644 --- a/hotspot/src/share/vm/asm/assembler.cpp +++ b/hotspot/src/share/vm/asm/assembler.cpp @@ -284,15 +284,19 @@ void AbstractAssembler::update_delayed_values() { DelayedConstant::update_all(); } - - - void AbstractAssembler::block_comment(const char* comment) { if (sect() == CodeBuffer::SECT_INSTS) { code_section()->outer()->block_comment(offset(), comment); } } +const char* AbstractAssembler::code_string(const char* str) { + if (sect() == CodeBuffer::SECT_INSTS || sect() == CodeBuffer::SECT_STUBS) { + return code_section()->outer()->code_string(str); + } + return NULL; +} + bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { // Exception handler checks the nmethod's implicit null checks table // only when this method returns false. diff --git a/hotspot/src/share/vm/asm/assembler.hpp b/hotspot/src/share/vm/asm/assembler.hpp index 0a55dc90eb9..8a9e2758a58 100644 --- a/hotspot/src/share/vm/asm/assembler.hpp +++ b/hotspot/src/share/vm/asm/assembler.hpp @@ -336,6 +336,8 @@ class AbstractAssembler : public ResourceObj { // along with the disassembly when printing nmethods. Currently // only supported in the instruction section of the code buffer. void block_comment(const char* comment); + // Copy str to a buffer that has the same lifetime as the CodeBuffer + const char* code_string(const char* str); // Label functions void bind(Label& L); // binds an unbound label L to the current code position diff --git a/hotspot/src/share/vm/asm/codeBuffer.cpp b/hotspot/src/share/vm/asm/codeBuffer.cpp index 2a4a8f2981f..f885c415332 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.cpp +++ b/hotspot/src/share/vm/asm/codeBuffer.cpp @@ -703,8 +703,8 @@ void CodeBuffer::copy_code_to(CodeBlob* dest_blob) { this->compute_final_layout(&dest); relocate_code_to(&dest); - // transfer comments from buffer to blob - dest_blob->set_comments(_comments); + // transfer strings and comments from buffer to blob + dest_blob->set_strings(_strings); // Done moving code bytes; were they the right size? assert(round_to(dest.total_content_size(), oopSize) == dest_blob->content_size(), "sanity"); @@ -1003,58 +1003,78 @@ void CodeSection::decode() { void CodeBuffer::block_comment(intptr_t offset, const char * comment) { - _comments.add_comment(offset, comment); + _strings.add_comment(offset, comment); } -class CodeComment: public CHeapObj { - private: - friend class CodeComments; - intptr_t _offset; - const char * _comment; - CodeComment* _next; +const char* CodeBuffer::code_string(const char* str) { + return _strings.add_string(str); +} - ~CodeComment() { +class CodeString: public CHeapObj { + private: + friend class CodeStrings; + const char * _string; + CodeString* _next; + intptr_t _offset; + + ~CodeString() { assert(_next == NULL, "wrong interface for freeing list"); - os::free((void*)_comment, mtCode); + os::free((void*)_string, mtCode); } + bool is_comment() const { return _offset >= 0; } + public: - CodeComment(intptr_t offset, const char * comment) { - _offset = offset; - _comment = os::strdup(comment, mtCode); - _next = NULL; + CodeString(const char * string, intptr_t offset = -1) + : _next(NULL), _offset(offset) { + _string = os::strdup(string, mtCode); } - intptr_t offset() const { return _offset; } - const char * comment() const { return _comment; } - CodeComment* next() { return _next; } + const char * string() const { return _string; } + intptr_t offset() const { assert(_offset >= 0, "offset for non comment?"); return _offset; } + CodeString* next() const { return _next; } - void set_next(CodeComment* next) { _next = next; } + void set_next(CodeString* next) { _next = next; } - CodeComment* find(intptr_t offset) { - CodeComment* a = this; - while (a != NULL && a->_offset != offset) { - a = a->_next; + CodeString* first_comment() { + if (is_comment()) { + return this; + } else { + return next_comment(); } - return a; } - - // Convenience for add_comment. - CodeComment* find_last(intptr_t offset) { - CodeComment* a = find(offset); - if (a != NULL) { - while ((a->_next != NULL) && (a->_next->_offset == offset)) { - a = a->_next; - } + CodeString* next_comment() const { + CodeString* s = _next; + while (s != NULL && !s->is_comment()) { + s = s->_next; } - return a; + return s; } }; +CodeString* CodeStrings::find(intptr_t offset) const { + CodeString* a = _strings->first_comment(); + while (a != NULL && a->offset() != offset) { + a = a->next_comment(); + } + return a; +} -void CodeComments::add_comment(intptr_t offset, const char * comment) { - CodeComment* c = new CodeComment(offset, comment); - CodeComment* inspos = (_comments == NULL) ? NULL : _comments->find_last(offset); +// Convenience for add_comment. +CodeString* CodeStrings::find_last(intptr_t offset) const { + CodeString* a = find(offset); + if (a != NULL) { + CodeString* c = NULL; + while (((c = a->next_comment()) != NULL) && (c->offset() == offset)) { + a = c; + } + } + return a; +} + +void CodeStrings::add_comment(intptr_t offset, const char * comment) { + CodeString* c = new CodeString(comment, offset); + CodeString* inspos = (_strings == NULL) ? NULL : find_last(offset); if (inspos) { // insert after already existing comments with same offset @@ -1062,43 +1082,47 @@ void CodeComments::add_comment(intptr_t offset, const char * comment) { inspos->set_next(c); } else { // no comments with such offset, yet. Insert before anything else. - c->set_next(_comments); - _comments = c; + c->set_next(_strings); + _strings = c; } } - -void CodeComments::assign(CodeComments& other) { - _comments = other._comments; +void CodeStrings::assign(CodeStrings& other) { + _strings = other._strings; } - -void CodeComments::print_block_comment(outputStream* stream, intptr_t offset) const { - if (_comments != NULL) { - CodeComment* c = _comments->find(offset); +void CodeStrings::print_block_comment(outputStream* stream, intptr_t offset) const { + if (_strings != NULL) { + CodeString* c = find(offset); while (c && c->offset() == offset) { stream->bol(); stream->print(" ;; "); - stream->print_cr(c->comment()); - c = c->next(); + stream->print_cr(c->string()); + c = c->next_comment(); } } } -void CodeComments::free() { - CodeComment* n = _comments; +void CodeStrings::free() { + CodeString* n = _strings; while (n) { // unlink the node from the list saving a pointer to the next - CodeComment* p = n->_next; - n->_next = NULL; + CodeString* p = n->next(); + n->set_next(NULL); delete n; n = p; } - _comments = NULL; + _strings = NULL; } - +const char* CodeStrings::add_string(const char * string) { + CodeString* s = new CodeString(string); + s->set_next(_strings); + _strings = s; + assert(s->string() != NULL, "should have a string"); + return s->string(); +} void CodeBuffer::decode() { ttyLocker ttyl; diff --git a/hotspot/src/share/vm/asm/codeBuffer.hpp b/hotspot/src/share/vm/asm/codeBuffer.hpp index d13697ef46e..8ce94646d95 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.hpp +++ b/hotspot/src/share/vm/asm/codeBuffer.hpp @@ -28,7 +28,7 @@ #include "code/oopRecorder.hpp" #include "code/relocInfo.hpp" -class CodeComments; +class CodeStrings; class PhaseCFG; class Compile; class BufferBlob; @@ -240,27 +240,31 @@ class CodeSection VALUE_OBJ_CLASS_SPEC { #endif //PRODUCT }; -class CodeComment; -class CodeComments VALUE_OBJ_CLASS_SPEC { +class CodeString; +class CodeStrings VALUE_OBJ_CLASS_SPEC { private: #ifndef PRODUCT - CodeComment* _comments; + CodeString* _strings; #endif + CodeString* find(intptr_t offset) const; + CodeString* find_last(intptr_t offset) const; + public: - CodeComments() { + CodeStrings() { #ifndef PRODUCT - _comments = NULL; + _strings = NULL; #endif } + const char* add_string(const char * string) PRODUCT_RETURN_(return NULL;); + void add_comment(intptr_t offset, const char * comment) PRODUCT_RETURN; void print_block_comment(outputStream* stream, intptr_t offset) const PRODUCT_RETURN; - void assign(CodeComments& other) PRODUCT_RETURN; + void assign(CodeStrings& other) PRODUCT_RETURN; void free() PRODUCT_RETURN; }; - // A CodeBuffer describes a memory space into which assembly // code is generated. This memory space usually occupies the // interior of a single BufferBlob, but in some cases it may be @@ -326,7 +330,7 @@ class CodeBuffer: public StackObj { csize_t _total_size; // size in bytes of combined memory buffer OopRecorder* _oop_recorder; - CodeComments _comments; + CodeStrings _strings; OopRecorder _default_oop_recorder; // override with initialize_oop_recorder Arena* _overflow_arena; @@ -527,7 +531,7 @@ class CodeBuffer: public StackObj { void initialize_oop_recorder(OopRecorder* r); OopRecorder* oop_recorder() const { return _oop_recorder; } - CodeComments& comments() { return _comments; } + CodeStrings& strings() { return _strings; } // Code generation void relocate(address at, RelocationHolder const& rspec, int format = 0) { @@ -556,6 +560,7 @@ class CodeBuffer: public StackObj { address transform_address(const CodeBuffer &cb, address addr) const; void block_comment(intptr_t offset, const char * comment) PRODUCT_RETURN; + const char* code_string(const char* str) PRODUCT_RETURN_(return NULL;); // Log a little info about section usage in the CodeBuffer void log_section_sizes(const char* name); diff --git a/hotspot/src/share/vm/c1/c1_LIR.hpp b/hotspot/src/share/vm/c1/c1_LIR.hpp index cec92f78c27..72051f19f34 100644 --- a/hotspot/src/share/vm/c1/c1_LIR.hpp +++ b/hotspot/src/share/vm/c1/c1_LIR.hpp @@ -2375,7 +2375,7 @@ class LIR_OpVisitState: public StackObj { // collects all register operands of the instruction void visit(LIR_Op* op); -#if ASSERT +#ifdef ASSERT // check that an operation has no operands bool no_operands(LIR_Op* op); #endif diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index a9a3706df32..6dff1e9396e 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -802,6 +802,7 @@ ciInstanceKlass* ciEnv::get_instance_klass_for_declared_method_holder(ciKlass* m // require checks to make sure the expected type was found. Given that this // only occurs for clone() the more extensive fix seems like overkill so // instead we simply smear the array type into Object. + guarantee(method_holder != NULL, "no method holder"); if (method_holder->is_instance_klass()) { return method_holder->as_instance_klass(); } else if (method_holder->is_array_klass()) { diff --git a/hotspot/src/share/vm/ci/ciTypeFlow.cpp b/hotspot/src/share/vm/ci/ciTypeFlow.cpp index bdbeeaf933e..b76dd3d0fe3 100644 --- a/hotspot/src/share/vm/ci/ciTypeFlow.cpp +++ b/hotspot/src/share/vm/ci/ciTypeFlow.cpp @@ -2540,7 +2540,7 @@ void ciTypeFlow::build_loop_tree(Block* blk) { } else if (innermost->head() == blk) { // If loop header, complete the tree pointers if (blk->loop() != innermost) { -#if ASSERT +#ifdef ASSERT assert(blk->loop()->head() == innermost->head(), "same head"); Loop* dl; for (dl = innermost; dl != NULL && dl != blk->loop(); dl = dl->parent()); diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index 3650e05406f..9f2a9f419a4 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -90,8 +90,7 @@ // Extension method support. #define JAVA_8_VERSION 52 - -void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, constantPoolHandle cp, int length, TRAPS) { +void ClassFileParser::parse_constant_pool_entries(int length, TRAPS) { // Use a local copy of ClassFileStream. It helps the C++ compiler to optimize // this function (_current can be allocated in a register, with scalar // replacement of aggregates). The _current pointer is copied back to @@ -104,7 +103,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, assert(cfs->allocated_on_stack(),"should be local"); u1* old_current = cfs0->current(); #endif - Handle class_loader(THREAD, loader_data->class_loader()); + Handle class_loader(THREAD, _loader_data->class_loader()); // Used for batching symbol allocations. const char* names[SymbolTable::symbol_alloc_batch_size]; @@ -124,7 +123,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, { cfs->guarantee_more(3, CHECK); // name_index, tag/access_flags u2 name_index = cfs->get_u2_fast(); - cp->klass_index_at_put(index, name_index); + _cp->klass_index_at_put(index, name_index); } break; case JVM_CONSTANT_Fieldref : @@ -132,7 +131,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags u2 class_index = cfs->get_u2_fast(); u2 name_and_type_index = cfs->get_u2_fast(); - cp->field_at_put(index, class_index, name_and_type_index); + _cp->field_at_put(index, class_index, name_and_type_index); } break; case JVM_CONSTANT_Methodref : @@ -140,7 +139,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags u2 class_index = cfs->get_u2_fast(); u2 name_and_type_index = cfs->get_u2_fast(); - cp->method_at_put(index, class_index, name_and_type_index); + _cp->method_at_put(index, class_index, name_and_type_index); } break; case JVM_CONSTANT_InterfaceMethodref : @@ -148,14 +147,14 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags u2 class_index = cfs->get_u2_fast(); u2 name_and_type_index = cfs->get_u2_fast(); - cp->interface_method_at_put(index, class_index, name_and_type_index); + _cp->interface_method_at_put(index, class_index, name_and_type_index); } break; case JVM_CONSTANT_String : { cfs->guarantee_more(3, CHECK); // string_index, tag/access_flags u2 string_index = cfs->get_u2_fast(); - cp->string_index_at_put(index, string_index); + _cp->string_index_at_put(index, string_index); } break; case JVM_CONSTANT_MethodHandle : @@ -174,11 +173,11 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs->guarantee_more(4, CHECK); // ref_kind, method_index, tag/access_flags u1 ref_kind = cfs->get_u1_fast(); u2 method_index = cfs->get_u2_fast(); - cp->method_handle_index_at_put(index, ref_kind, method_index); + _cp->method_handle_index_at_put(index, ref_kind, method_index); } else if (tag == JVM_CONSTANT_MethodType) { cfs->guarantee_more(3, CHECK); // signature_index, tag/access_flags u2 signature_index = cfs->get_u2_fast(); - cp->method_type_index_at_put(index, signature_index); + _cp->method_type_index_at_put(index, signature_index); } else { ShouldNotReachHere(); } @@ -200,21 +199,21 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, u2 name_and_type_index = cfs->get_u2_fast(); if (_max_bootstrap_specifier_index < (int) bootstrap_specifier_index) _max_bootstrap_specifier_index = (int) bootstrap_specifier_index; // collect for later - cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index); + _cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index); } break; case JVM_CONSTANT_Integer : { cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags u4 bytes = cfs->get_u4_fast(); - cp->int_at_put(index, (jint) bytes); + _cp->int_at_put(index, (jint) bytes); } break; case JVM_CONSTANT_Float : { cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags u4 bytes = cfs->get_u4_fast(); - cp->float_at_put(index, *(jfloat*)&bytes); + _cp->float_at_put(index, *(jfloat*)&bytes); } break; case JVM_CONSTANT_Long : @@ -225,7 +224,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, { cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags u8 bytes = cfs->get_u8_fast(); - cp->long_at_put(index, bytes); + _cp->long_at_put(index, bytes); } index++; // Skip entry following eigth-byte constant, see JVM book p. 98 break; @@ -237,7 +236,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, { cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags u8 bytes = cfs->get_u8_fast(); - cp->double_at_put(index, *(jdouble*)&bytes); + _cp->double_at_put(index, *(jdouble*)&bytes); } index++; // Skip entry following eigth-byte constant, see JVM book p. 98 break; @@ -246,7 +245,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs->guarantee_more(5, CHECK); // name_index, signature_index, tag/access_flags u2 name_index = cfs->get_u2_fast(); u2 signature_index = cfs->get_u2_fast(); - cp->name_and_type_at_put(index, name_index, signature_index); + _cp->name_and_type_at_put(index, name_index, signature_index); } break; case JVM_CONSTANT_Utf8 : @@ -283,11 +282,11 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, indices[names_count] = index; hashValues[names_count++] = hash; if (names_count == SymbolTable::symbol_alloc_batch_size) { - SymbolTable::new_symbols(loader_data, cp, names_count, names, lengths, indices, hashValues, CHECK); + SymbolTable::new_symbols(_loader_data, _cp, names_count, names, lengths, indices, hashValues, CHECK); names_count = 0; } } else { - cp->symbol_at_put(index, result); + _cp->symbol_at_put(index, result); } } break; @@ -300,7 +299,7 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, // Allocate the remaining symbols if (names_count > 0) { - SymbolTable::new_symbols(loader_data, cp, names_count, names, lengths, indices, hashValues, CHECK); + SymbolTable::new_symbols(_loader_data, _cp, names_count, names, lengths, indices, hashValues, CHECK); } // Copy _current pointer of local copy back to stream(). @@ -310,23 +309,6 @@ void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, cfs0->set_current(cfs1.current()); } -// This class unreferences constant pool symbols if an error has occurred -// while parsing the class before it is assigned into the class. -// If it gets an error after that it is unloaded and the constant pool will -// be cleaned up then. -class ConstantPoolCleaner : public StackObj { - constantPoolHandle _cphandle; - bool _in_error; - public: - ConstantPoolCleaner(constantPoolHandle cp) : _cphandle(cp), _in_error(true) {} - ~ConstantPoolCleaner() { - if (_in_error && _cphandle.not_null()) { - _cphandle->unreference_symbols(); - } - } - void set_in_error(bool clean) { _in_error = clean; } -}; - bool inline valid_cp_range(int index, int length) { return (index > 0 && index < length); } inline Symbol* check_symbol_at(constantPoolHandle cp, int index) { @@ -336,7 +318,7 @@ inline Symbol* check_symbol_at(constantPoolHandle cp, int index) { return NULL; } -constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_data, TRAPS) { +constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) { ClassFileStream* cfs = stream(); constantPoolHandle nullHandle; @@ -345,16 +327,13 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ guarantee_property( length >= 1, "Illegal constant pool size %u in class file %s", length, CHECK_(nullHandle)); - ConstantPool* constant_pool = - ConstantPool::allocate(loader_data, - length, - CHECK_(nullHandle)); + ConstantPool* constant_pool = ConstantPool::allocate(_loader_data, length, + CHECK_(nullHandle)); + _cp = constant_pool; // save in case of errors constantPoolHandle cp (THREAD, constant_pool); - ConstantPoolCleaner cp_in_error(cp); // set constant pool to be cleaned up. - // parsing constant pool entries - parse_constant_pool_entries(loader_data, cp, length, CHECK_(nullHandle)); + parse_constant_pool_entries(length, CHECK_(nullHandle)); int index = 1; // declared outside of loops for portability @@ -373,8 +352,7 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ if (!_need_verify) break; int klass_ref_index = cp->klass_ref_index_at(index); int name_and_type_ref_index = cp->name_and_type_ref_index_at(index); - check_property(valid_cp_range(klass_ref_index, length) && - is_klass_reference(cp, klass_ref_index), + check_property(valid_klass_reference_at(klass_ref_index), "Invalid constant pool index %u in class file %s", klass_ref_index, CHECK_(nullHandle)); @@ -404,16 +382,12 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ if (!_need_verify) break; int name_ref_index = cp->name_ref_index_at(index); int signature_ref_index = cp->signature_ref_index_at(index); - check_property( - valid_cp_range(name_ref_index, length) && - cp->tag_at(name_ref_index).is_utf8(), - "Invalid constant pool index %u in class file %s", - name_ref_index, CHECK_(nullHandle)); - check_property( - valid_cp_range(signature_ref_index, length) && - cp->tag_at(signature_ref_index).is_utf8(), - "Invalid constant pool index %u in class file %s", - signature_ref_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(name_ref_index), + "Invalid constant pool index %u in class file %s", + name_ref_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(signature_ref_index), + "Invalid constant pool index %u in class file %s", + signature_ref_index, CHECK_(nullHandle)); break; } case JVM_CONSTANT_Utf8 : @@ -425,22 +399,18 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ case JVM_CONSTANT_ClassIndex : { int class_index = cp->klass_index_at(index); - check_property( - valid_cp_range(class_index, length) && - cp->tag_at(class_index).is_utf8(), - "Invalid constant pool index %u in class file %s", - class_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(class_index), + "Invalid constant pool index %u in class file %s", + class_index, CHECK_(nullHandle)); cp->unresolved_klass_at_put(index, cp->symbol_at(class_index)); } break; case JVM_CONSTANT_StringIndex : { int string_index = cp->string_index_at(index); - check_property( - valid_cp_range(string_index, length) && - cp->tag_at(string_index).is_utf8(), - "Invalid constant pool index %u in class file %s", - string_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(string_index), + "Invalid constant pool index %u in class file %s", + string_index, CHECK_(nullHandle)); Symbol* sym = cp->symbol_at(string_index); cp->unresolved_string_at_put(index, sym); } @@ -491,12 +461,9 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ case JVM_CONSTANT_MethodType : { int ref_index = cp->method_type_index_at(index); - check_property( - valid_cp_range(ref_index, length) && - cp->tag_at(ref_index).is_utf8() && - EnableInvokeDynamic, - "Invalid constant pool index %u in class file %s", - ref_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(ref_index) && EnableInvokeDynamic, + "Invalid constant pool index %u in class file %s", + ref_index, CHECK_(nullHandle)); } break; case JVM_CONSTANT_InvokeDynamic : @@ -541,7 +508,6 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ } if (!_need_verify) { - cp_in_error.set_in_error(false); return cp; } @@ -664,7 +630,6 @@ constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_ } // end of switch } // end of for - cp_in_error.set_in_error(false); return cp; } @@ -786,93 +751,92 @@ bool put_after_lookup(Symbol* name, Symbol* sig, NameSigHash** table) { } -Array* ClassFileParser::parse_interfaces(constantPoolHandle cp, - int length, - ClassLoaderData* loader_data, +Array* ClassFileParser::parse_interfaces(int length, Handle protection_domain, Symbol* class_name, bool* has_default_methods, TRAPS) { - ClassFileStream* cfs = stream(); - assert(length > 0, "only called for length>0"); - // FIXME: Leak at later OOM. - Array* interfaces = MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); + if (length == 0) { + _local_interfaces = Universe::the_empty_klass_array(); + } else { + ClassFileStream* cfs = stream(); + assert(length > 0, "only called for length>0"); + _local_interfaces = MetadataFactory::new_array(_loader_data, length, NULL, CHECK_NULL); - int index; - for (index = 0; index < length; index++) { - u2 interface_index = cfs->get_u2(CHECK_NULL); - KlassHandle interf; - check_property( - valid_cp_range(interface_index, cp->length()) && - is_klass_reference(cp, interface_index), - "Interface name has bad constant pool index %u in class file %s", - interface_index, CHECK_NULL); - if (cp->tag_at(interface_index).is_klass()) { - interf = KlassHandle(THREAD, cp->resolved_klass_at(interface_index)); - } else { - Symbol* unresolved_klass = cp->klass_name_at(interface_index); - - // Don't need to check legal name because it's checked when parsing constant pool. - // But need to make sure it's not an array type. - guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY, - "Bad interface name in class file %s", CHECK_NULL); - Handle class_loader(THREAD, loader_data->class_loader()); - - // Call resolve_super so classcircularity is checked - Klass* k = SystemDictionary::resolve_super_or_fail(class_name, - unresolved_klass, class_loader, protection_domain, - false, CHECK_NULL); - interf = KlassHandle(THREAD, k); - } - - if (!interf()->is_interface()) { - THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", NULL); - } - if (InstanceKlass::cast(interf())->has_default_methods()) { - *has_default_methods = true; - } - interfaces->at_put(index, interf()); - } - - if (!_need_verify || length <= 1) { - return interfaces; - } - - // Check if there's any duplicates in interfaces - ResourceMark rm(THREAD); - NameSigHash** interface_names = NEW_RESOURCE_ARRAY_IN_THREAD( - THREAD, NameSigHash*, HASH_ROW_SIZE); - initialize_hashtable(interface_names); - bool dup = false; - { - debug_only(No_Safepoint_Verifier nsv;) + int index; for (index = 0; index < length; index++) { - Klass* k = interfaces->at(index); - Symbol* name = InstanceKlass::cast(k)->name(); - // If no duplicates, add (name, NULL) in hashtable interface_names. - if (!put_after_lookup(name, NULL, interface_names)) { - dup = true; - break; + u2 interface_index = cfs->get_u2(CHECK_NULL); + KlassHandle interf; + check_property( + valid_klass_reference_at(interface_index), + "Interface name has bad constant pool index %u in class file %s", + interface_index, CHECK_NULL); + if (_cp->tag_at(interface_index).is_klass()) { + interf = KlassHandle(THREAD, _cp->resolved_klass_at(interface_index)); + } else { + Symbol* unresolved_klass = _cp->klass_name_at(interface_index); + + // Don't need to check legal name because it's checked when parsing constant pool. + // But need to make sure it's not an array type. + guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY, + "Bad interface name in class file %s", CHECK_NULL); + Handle class_loader(THREAD, _loader_data->class_loader()); + + // Call resolve_super so classcircularity is checked + Klass* k = SystemDictionary::resolve_super_or_fail(class_name, + unresolved_klass, class_loader, protection_domain, + false, CHECK_NULL); + interf = KlassHandle(THREAD, k); + } + + if (!interf()->is_interface()) { + THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", NULL); + } + if (InstanceKlass::cast(interf())->has_default_methods()) { + *has_default_methods = true; + } + _local_interfaces->at_put(index, interf()); + } + + if (!_need_verify || length <= 1) { + return _local_interfaces; + } + + // Check if there's any duplicates in interfaces + ResourceMark rm(THREAD); + NameSigHash** interface_names = NEW_RESOURCE_ARRAY_IN_THREAD( + THREAD, NameSigHash*, HASH_ROW_SIZE); + initialize_hashtable(interface_names); + bool dup = false; + { + debug_only(No_Safepoint_Verifier nsv;) + for (index = 0; index < length; index++) { + Klass* k = _local_interfaces->at(index); + Symbol* name = InstanceKlass::cast(k)->name(); + // If no duplicates, add (name, NULL) in hashtable interface_names. + if (!put_after_lookup(name, NULL, interface_names)) { + dup = true; + break; + } } } + if (dup) { + classfile_parse_error("Duplicate interface name in class file %s", CHECK_NULL); + } } - if (dup) { - classfile_parse_error("Duplicate interface name in class file %s", CHECK_NULL); - } - - return interfaces; + return _local_interfaces; } -void ClassFileParser::verify_constantvalue(int constantvalue_index, int signature_index, constantPoolHandle cp, TRAPS) { +void ClassFileParser::verify_constantvalue(int constantvalue_index, int signature_index, TRAPS) { // Make sure the constant pool entry is of a type appropriate to this field guarantee_property( (constantvalue_index > 0 && - constantvalue_index < cp->length()), + constantvalue_index < _cp->length()), "Bad initial value index %u in ConstantValue attribute in class file %s", constantvalue_index, CHECK); - constantTag value_type = cp->tag_at(constantvalue_index); - switch ( cp->basic_type_for_signature_at(signature_index) ) { + constantTag value_type = _cp->tag_at(constantvalue_index); + switch ( _cp->basic_type_for_signature_at(signature_index) ) { case T_LONG: guarantee_property(value_type.is_long(), "Inconsistent constant value type in class file %s", CHECK); break; @@ -886,7 +850,7 @@ void ClassFileParser::verify_constantvalue(int constantvalue_index, int signatur guarantee_property(value_type.is_int(), "Inconsistent constant value type in class file %s", CHECK); break; case T_OBJECT: - guarantee_property((cp->symbol_at(signature_index)->equals("Ljava/lang/String;") + guarantee_property((_cp->symbol_at(signature_index)->equals("Ljava/lang/String;") && value_type.is_string()), "Bad string initial value in class file %s", CHECK); break; @@ -899,15 +863,11 @@ void ClassFileParser::verify_constantvalue(int constantvalue_index, int signatur // Parse attributes for a field. -void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, - constantPoolHandle cp, - u2 attributes_count, +void ClassFileParser::parse_field_attributes(u2 attributes_count, bool is_static, u2 signature_index, u2* constantvalue_index_addr, bool* is_synthetic_addr, u2* generic_signature_index_addr, - AnnotationArray** field_annotations, - AnnotationArray** field_type_annotations, ClassFileParser::FieldAnnotationCollector* parsed_annotations, TRAPS) { ClassFileStream* cfs = stream(); @@ -927,12 +887,11 @@ void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length u2 attribute_name_index = cfs->get_u2_fast(); u4 attribute_length = cfs->get_u4_fast(); - check_property(valid_cp_range(attribute_name_index, cp->length()) && - cp->tag_at(attribute_name_index).is_utf8(), + check_property(valid_symbol_at(attribute_name_index), "Invalid field attribute index %u in class file %s", attribute_name_index, CHECK); - Symbol* attribute_name = cp->symbol_at(attribute_name_index); + Symbol* attribute_name = _cp->symbol_at(attribute_name_index); if (is_static && attribute_name == vmSymbols::tag_constant_value()) { // ignore if non-static if (constantvalue_index != 0) { @@ -944,7 +903,7 @@ void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, attribute_length, CHECK); constantvalue_index = cfs->get_u2(CHECK); if (_need_verify) { - verify_constantvalue(constantvalue_index, signature_index, cp, CHECK); + verify_constantvalue(constantvalue_index, signature_index, CHECK); } } else if (attribute_name == vmSymbols::tag_synthetic()) { if (attribute_length != 0) { @@ -971,10 +930,8 @@ void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, runtime_visible_annotations_length = attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); - parse_annotations(loader_data, - runtime_visible_annotations, + parse_annotations(runtime_visible_annotations, runtime_visible_annotations_length, - cp, parsed_annotations, CHECK); cfs->skip_u1(runtime_visible_annotations_length, CHECK); @@ -1004,18 +961,18 @@ void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, *constantvalue_index_addr = constantvalue_index; *is_synthetic_addr = is_synthetic; *generic_signature_index_addr = generic_signature_index; - *field_annotations = assemble_annotations(loader_data, - runtime_visible_annotations, + AnnotationArray* a = assemble_annotations(runtime_visible_annotations, runtime_visible_annotations_length, runtime_invisible_annotations, runtime_invisible_annotations_length, CHECK); - *field_type_annotations = assemble_annotations(loader_data, - runtime_visible_type_annotations, - runtime_visible_type_annotations_length, - runtime_invisible_type_annotations, - runtime_invisible_type_annotations_length, - CHECK); + parsed_annotations->set_field_annotations(a); + a = assemble_annotations(runtime_visible_type_annotations, + runtime_visible_type_annotations_length, + runtime_invisible_type_annotations, + runtime_invisible_type_annotations_length, + CHECK); + parsed_annotations->set_field_type_annotations(a); return; } @@ -1106,13 +1063,9 @@ class FieldAllocationCount: public ResourceObj { } }; -Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, - Symbol* class_name, - constantPoolHandle cp, +Array* ClassFileParser::parse_fields(Symbol* class_name, bool is_interface, FieldAllocationCount *fac, - Array** fields_annotations, - Array** fields_type_annotations, u2* java_fields_count_ptr, TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK_NULL); // length @@ -1147,8 +1100,6 @@ Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, u2* fa = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2, total_fields * (FieldInfo::field_slots + 1)); - AnnotationArray* field_annotations = NULL; - AnnotationArray* field_type_annotations = NULL; // The generic signature slots start after all other fields' data. int generic_signature_slot = total_fields * FieldInfo::field_slots; int num_generic_signature = 0; @@ -1161,53 +1112,52 @@ Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, access_flags.set_flags(flags); u2 name_index = cfs->get_u2_fast(); - int cp_size = cp->length(); - check_property( - valid_cp_range(name_index, cp_size) && cp->tag_at(name_index).is_utf8(), + int cp_size = _cp->length(); + check_property(valid_symbol_at(name_index), "Invalid constant pool index %u for field name in class file %s", - name_index, CHECK_NULL); - Symbol* name = cp->symbol_at(name_index); + name_index, + CHECK_NULL); + Symbol* name = _cp->symbol_at(name_index); verify_legal_field_name(name, CHECK_NULL); u2 signature_index = cfs->get_u2_fast(); - check_property( - valid_cp_range(signature_index, cp_size) && - cp->tag_at(signature_index).is_utf8(), + check_property(valid_symbol_at(signature_index), "Invalid constant pool index %u for field signature in class file %s", signature_index, CHECK_NULL); - Symbol* sig = cp->symbol_at(signature_index); + Symbol* sig = _cp->symbol_at(signature_index); verify_legal_field_signature(name, sig, CHECK_NULL); u2 constantvalue_index = 0; bool is_synthetic = false; u2 generic_signature_index = 0; bool is_static = access_flags.is_static(); - FieldAnnotationCollector parsed_annotations; + FieldAnnotationCollector parsed_annotations(_loader_data); u2 attributes_count = cfs->get_u2_fast(); if (attributes_count > 0) { - parse_field_attributes(loader_data, - cp, attributes_count, is_static, signature_index, + parse_field_attributes(attributes_count, is_static, signature_index, &constantvalue_index, &is_synthetic, - &generic_signature_index, &field_annotations, - &field_type_annotations, &parsed_annotations, + &generic_signature_index, &parsed_annotations, CHECK_NULL); - if (field_annotations != NULL) { - if (*fields_annotations == NULL) { - *fields_annotations = MetadataFactory::new_array( - loader_data, length, NULL, + if (parsed_annotations.field_annotations() != NULL) { + if (_fields_annotations == NULL) { + _fields_annotations = MetadataFactory::new_array( + _loader_data, length, NULL, CHECK_NULL); } - (*fields_annotations)->at_put(n, field_annotations); + _fields_annotations->at_put(n, parsed_annotations.field_annotations()); + parsed_annotations.set_field_annotations(NULL); } - if (field_type_annotations != NULL) { - if (*fields_type_annotations == NULL) { - *fields_type_annotations = MetadataFactory::new_array( - loader_data, length, NULL, + if (parsed_annotations.field_type_annotations() != NULL) { + if (_fields_type_annotations == NULL) { + _fields_type_annotations = MetadataFactory::new_array( + _loader_data, length, NULL, CHECK_NULL); } - (*fields_type_annotations)->at_put(n, field_type_annotations); + _fields_type_annotations->at_put(n, parsed_annotations.field_type_annotations()); + parsed_annotations.set_field_type_annotations(NULL); } + if (is_synthetic) { access_flags.set_is_synthetic(); } @@ -1224,7 +1174,7 @@ Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, name_index, signature_index, constantvalue_index); - BasicType type = cp->basic_type_for_signature_at(signature_index); + BasicType type = _cp->basic_type_for_signature_at(signature_index); // Remember how many oops we encountered and compute allocation type FieldAllocationType atype = fac->update(is_static, type); @@ -1245,8 +1195,8 @@ Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, bool duplicate = false; for (int i = 0; i < length; i++) { FieldInfo* f = FieldInfo::from_field_array(fa, i); - if (name == cp->symbol_at(f->name_index()) && - signature == cp->symbol_at(f->signature_index())) { + if (name == _cp->symbol_at(f->name_index()) && + signature == _cp->symbol_at(f->signature_index())) { // Symbol is desclared in Java so skip this one duplicate = true; break; @@ -1280,8 +1230,9 @@ Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, // fields array is trimed. Also unused slots that were reserved // for generic signature indexes are discarded. Array* fields = MetadataFactory::new_array( - loader_data, index * FieldInfo::field_slots + num_generic_signature, + _loader_data, index * FieldInfo::field_slots + num_generic_signature, CHECK_NULL); + _fields = fields; // save in case of error { int i = 0; for (; i < index * FieldInfo::field_slots; i++) { @@ -1303,7 +1254,7 @@ Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, bool dup = false; { debug_only(No_Safepoint_Verifier nsv;) - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { + for (AllFieldStream fs(fields, _cp); !fs.done(); fs.next()) { Symbol* name = fs.name(); Symbol* sig = fs.signature(); // If no duplicates, add name/signature in hashtable names_and_sigs. @@ -1330,10 +1281,8 @@ static void copy_u2_with_conversion(u2* dest, u2* src, int length) { } -u2* ClassFileParser::parse_exception_table(ClassLoaderData* loader_data, - u4 code_length, +u2* ClassFileParser::parse_exception_table(u4 code_length, u4 exception_table_length, - constantPoolHandle cp, TRAPS) { ClassFileStream* cfs = stream(); @@ -1354,8 +1303,7 @@ u2* ClassFileParser::parse_exception_table(ClassLoaderData* loader_data, "Illegal exception table handler in class file %s", CHECK_NULL); if (catch_type_index != 0) { - guarantee_property(valid_cp_range(catch_type_index, cp->length()) && - is_klass_reference(cp, catch_type_index), + guarantee_property(valid_klass_reference_at(catch_type_index), "Catch type in exception table has bad constant type in class file %s", CHECK_NULL); } } @@ -1506,7 +1454,6 @@ void copy_lvt_element(Classfile_LVT_Element *src, LocalVariableTableElement *lvt u2* ClassFileParser::parse_localvariable_table(u4 code_length, u2 max_locals, u4 code_attribute_length, - constantPoolHandle cp, u2* localvariable_table_length, bool isLVTT, TRAPS) { @@ -1544,20 +1491,16 @@ u2* ClassFileParser::parse_localvariable_table(u4 code_length, "Invalid length %u in %s in class file %s", length, tbl_name, CHECK_NULL); } - int cp_size = cp->length(); - guarantee_property( - valid_cp_range(name_index, cp_size) && - cp->tag_at(name_index).is_utf8(), + int cp_size = _cp->length(); + guarantee_property(valid_symbol_at(name_index), "Name index %u in %s has bad constant type in class file %s", name_index, tbl_name, CHECK_NULL); - guarantee_property( - valid_cp_range(descriptor_index, cp_size) && - cp->tag_at(descriptor_index).is_utf8(), + guarantee_property(valid_symbol_at(descriptor_index), "Signature index %u in %s has bad constant type in class file %s", descriptor_index, tbl_name, CHECK_NULL); - Symbol* name = cp->symbol_at(name_index); - Symbol* sig = cp->symbol_at(descriptor_index); + Symbol* name = _cp->symbol_at(name_index); + Symbol* sig = _cp->symbol_at(descriptor_index); verify_legal_field_name(name, CHECK_NULL); u2 extra_slot = 0; if (!isLVTT) { @@ -1579,7 +1522,7 @@ u2* ClassFileParser::parse_localvariable_table(u4 code_length, void ClassFileParser::parse_type_array(u2 array_length, u4 code_length, u4* u1_index, u4* u2_index, - u1* u1_array, u2* u2_array, constantPoolHandle cp, TRAPS) { + u1* u1_array, u2* u2_array, TRAPS) { ClassFileStream* cfs = stream(); u2 index = 0; // index in the array with long/double occupying two slots u4 i1 = *u1_index; @@ -1591,8 +1534,7 @@ void ClassFileParser::parse_type_array(u2 array_length, u4 code_length, u4* u1_i index++; } else if (tag == ITEM_Object) { u2 class_index = u2_array[i2++] = cfs->get_u2(CHECK); - guarantee_property(valid_cp_range(class_index, cp->length()) && - is_klass_reference(cp, class_index), + guarantee_property(valid_klass_reference_at(class_index), "Bad class index %u in StackMap in class file %s", class_index, CHECK); } else if (tag == ITEM_Uninitialized) { @@ -1613,8 +1555,7 @@ void ClassFileParser::parse_type_array(u2 array_length, u4 code_length, u4* u1_i *u2_index = i2; } -Array* ClassFileParser::parse_stackmap_table( - ClassLoaderData* loader_data, +u1* ClassFileParser::parse_stackmap_table( u4 code_attribute_length, TRAPS) { if (code_attribute_length == 0) return NULL; @@ -1629,18 +1570,12 @@ Array* ClassFileParser::parse_stackmap_table( if (!_need_verify && !DumpSharedSpaces) { return NULL; } - - Array* stackmap_data = - MetadataFactory::new_array(loader_data, code_attribute_length, 0, CHECK_NULL); - - memcpy((void*)stackmap_data->adr_at(0), - (void*)stackmap_table_start, code_attribute_length); - return stackmap_data; + return stackmap_table_start; } u2* ClassFileParser::parse_checked_exceptions(u2* checked_exceptions_length, u4 method_attribute_length, - constantPoolHandle cp, TRAPS) { + TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK_NULL); // checked_exceptions_length *checked_exceptions_length = cfs->get_u2_fast(); @@ -1657,8 +1592,7 @@ u2* ClassFileParser::parse_checked_exceptions(u2* checked_exceptions_length, for (int i = 0; i < len; i++) { checked_exception = cfs->get_u2_fast(); check_property( - valid_cp_range(checked_exception, cp->length()) && - is_klass_reference(cp, checked_exception), + valid_klass_reference_at(checked_exception), "Exception name has bad type at constant pool %u in class file %s", checked_exception, CHECK_NULL); } @@ -1735,9 +1669,7 @@ int ClassFileParser::skip_annotation_value(u1* buffer, int limit, int index) { } // Sift through annotations, looking for those significant to the VM: -void ClassFileParser::parse_annotations(ClassLoaderData* loader_data, - u1* buffer, int limit, - constantPoolHandle cp, +void ClassFileParser::parse_annotations(u1* buffer, int limit, ClassFileParser::AnnotationCollector* coll, TRAPS) { // annotations := do(nann:u2) {annotation} @@ -1767,17 +1699,17 @@ void ClassFileParser::parse_annotations(ClassLoaderData* loader_data, u1* abase = buffer + index0; int atype = Bytes::get_Java_u2(abase + atype_off); int count = Bytes::get_Java_u2(abase + count_off); - Symbol* aname = check_symbol_at(cp, atype); + Symbol* aname = check_symbol_at(_cp, atype); if (aname == NULL) break; // invalid annotation name Symbol* member = NULL; if (count >= 1) { int member_index = Bytes::get_Java_u2(abase + member_off); - member = check_symbol_at(cp, member_index); + member = check_symbol_at(_cp, member_index); if (member == NULL) break; // invalid member name } // Here is where parsing particular annotations will take place. - AnnotationCollector::ID id = coll->annotation_index(loader_data, aname); + AnnotationCollector::ID id = coll->annotation_index(_loader_data, aname); if (id == AnnotationCollector::_unknown) continue; coll->set_annotation(id); @@ -1836,6 +1768,12 @@ void ClassFileParser::FieldAnnotationCollector::apply_to(FieldInfo* f) { f->set_contended_group(contended_group()); } +ClassFileParser::FieldAnnotationCollector::~FieldAnnotationCollector() { + // If there's an error deallocate metadata for field annotations + MetadataFactory::free_array(_loader_data, _field_annotations); + MetadataFactory::free_array(_loader_data, _field_type_annotations); +} + void ClassFileParser::MethodAnnotationCollector::apply_to(methodHandle m) { if (has_annotation(_method_ForceInline)) m->set_force_inline(true); @@ -1894,10 +1832,9 @@ void ClassFileParser::copy_localvariable_table(ConstMethod* cm, && _need_verify && _major_version >= JAVA_1_5_VERSION) { clear_hashtable(lvt_Hash); - ConstantPool* cp = cm->constants(); classfile_parse_error("Duplicated LocalVariableTable attribute " "entry for '%s' in class file %s", - cp->symbol_at(lvt->name_cp_index)->as_utf8(), + _cp->symbol_at(lvt->name_cp_index)->as_utf8(), CHECK); } } @@ -1916,18 +1853,16 @@ void ClassFileParser::copy_localvariable_table(ConstMethod* cm, if (entry == NULL) { if (_need_verify) { clear_hashtable(lvt_Hash); - ConstantPool* cp = cm->constants(); classfile_parse_error("LVTT entry for '%s' in class file %s " "does not match any LVT entry", - cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), + _cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), CHECK); } } else if (entry->_elem->signature_cp_index != 0 && _need_verify) { clear_hashtable(lvt_Hash); - ConstantPool* cp = cm->constants(); classfile_parse_error("Duplicated LocalVariableTypeTable attribute " "entry for '%s' in class file %s", - cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), + _cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), CHECK); } else { // to add generic signatures into LocalVariableTable @@ -1939,8 +1874,7 @@ void ClassFileParser::copy_localvariable_table(ConstMethod* cm, } -void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, - ConstMethod* cm, +void ClassFileParser::copy_method_annotations(ConstMethod* cm, u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, @@ -1961,8 +1895,7 @@ void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, if (runtime_visible_annotations_length + runtime_invisible_annotations_length > 0) { - a = assemble_annotations(loader_data, - runtime_visible_annotations, + a = assemble_annotations(runtime_visible_annotations, runtime_visible_annotations_length, runtime_invisible_annotations, runtime_invisible_annotations_length, @@ -1972,8 +1905,7 @@ void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, if (runtime_visible_parameter_annotations_length + runtime_invisible_parameter_annotations_length > 0) { - a = assemble_annotations(loader_data, - runtime_visible_parameter_annotations, + a = assemble_annotations(runtime_visible_parameter_annotations, runtime_visible_parameter_annotations_length, runtime_invisible_parameter_annotations, runtime_invisible_parameter_annotations_length, @@ -1982,8 +1914,7 @@ void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, } if (annotation_default_length > 0) { - a = assemble_annotations(loader_data, - annotation_default, + a = assemble_annotations(annotation_default, annotation_default_length, NULL, 0, @@ -1993,8 +1924,7 @@ void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, if (runtime_visible_type_annotations_length + runtime_invisible_type_annotations_length > 0) { - a = assemble_annotations(loader_data, - runtime_visible_type_annotations, + a = assemble_annotations(runtime_visible_type_annotations, runtime_visible_type_annotations_length, runtime_invisible_type_annotations, runtime_invisible_type_annotations_length, @@ -2013,9 +1943,7 @@ void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, // from the method back up to the containing klass. These flag values // are added to klass's access_flags. -methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, - constantPoolHandle cp, - bool is_interface, +methodHandle ClassFileParser::parse_method(bool is_interface, AccessFlags *promoted_flags, TRAPS) { ClassFileStream* cfs = stream(); @@ -2026,22 +1954,20 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, int flags = cfs->get_u2_fast(); u2 name_index = cfs->get_u2_fast(); - int cp_size = cp->length(); + int cp_size = _cp->length(); check_property( - valid_cp_range(name_index, cp_size) && - cp->tag_at(name_index).is_utf8(), + valid_symbol_at(name_index), "Illegal constant pool index %u for method name in class file %s", name_index, CHECK_(nullHandle)); - Symbol* name = cp->symbol_at(name_index); + Symbol* name = _cp->symbol_at(name_index); verify_legal_method_name(name, CHECK_(nullHandle)); u2 signature_index = cfs->get_u2_fast(); guarantee_property( - valid_cp_range(signature_index, cp_size) && - cp->tag_at(signature_index).is_utf8(), + valid_symbol_at(signature_index), "Illegal constant pool index %u for method signature in class file %s", signature_index, CHECK_(nullHandle)); - Symbol* signature = cp->symbol_at(signature_index); + Symbol* signature = _cp->symbol_at(signature_index); AccessFlags access_flags; if (name == vmSymbols::class_initializer_name()) { @@ -2097,7 +2023,8 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, bool parsed_checked_exceptions_attribute = false; bool parsed_stackmap_attribute = false; // stackmap attribute - JDK1.5 - Array* stackmap_data = NULL; + u1* stackmap_data = NULL; + int stackmap_data_length = 0; u2 generic_signature_index = 0; MethodAnnotationCollector parsed_annotations; u1* runtime_visible_annotations = NULL; @@ -2122,12 +2049,11 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, u2 method_attribute_name_index = cfs->get_u2_fast(); u4 method_attribute_length = cfs->get_u4_fast(); check_property( - valid_cp_range(method_attribute_name_index, cp_size) && - cp->tag_at(method_attribute_name_index).is_utf8(), + valid_symbol_at(method_attribute_name_index), "Invalid method attribute name index %u in class file %s", method_attribute_name_index, CHECK_(nullHandle)); - Symbol* method_attribute_name = cp->symbol_at(method_attribute_name_index); + Symbol* method_attribute_name = _cp->symbol_at(method_attribute_name_index); if (method_attribute_name == vmSymbols::tag_code()) { // Parse Code attribute if (_need_verify) { @@ -2171,7 +2097,7 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, exception_table_length = cfs->get_u2_fast(); if (exception_table_length > 0) { exception_table_start = - parse_exception_table(loader_data, code_length, exception_table_length, cp, CHECK_(nullHandle)); + parse_exception_table(code_length, exception_table_length, CHECK_(nullHandle)); } // Parse additional attributes in code attribute @@ -2204,19 +2130,18 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, calculated_attribute_length += code_attribute_length + sizeof(code_attribute_name_index) + sizeof(code_attribute_length); - check_property(valid_cp_range(code_attribute_name_index, cp_size) && - cp->tag_at(code_attribute_name_index).is_utf8(), + check_property(valid_symbol_at(code_attribute_name_index), "Invalid code attribute name index %u in class file %s", code_attribute_name_index, CHECK_(nullHandle)); if (LoadLineNumberTables && - cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_line_number_table()) { + _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_line_number_table()) { // Parse and compress line number table parse_linenumber_table(code_attribute_length, code_length, &linenumber_table, CHECK_(nullHandle)); } else if (LoadLocalVariableTables && - cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_table()) { + _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_table()) { // Parse local variable table if (!lvt_allocated) { localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD( @@ -2238,7 +2163,6 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, parse_localvariable_table(code_length, max_locals, code_attribute_length, - cp, &localvariable_table_length[lvt_cnt], false, // is not LVTT CHECK_(nullHandle)); @@ -2246,7 +2170,7 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, lvt_cnt++; } else if (LoadLocalVariableTypeTables && _major_version >= JAVA_1_5_VERSION && - cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_type_table()) { + _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_type_table()) { if (!lvt_allocated) { localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2, INITIAL_MAX_LVT_NUMBER); @@ -2268,19 +2192,19 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, parse_localvariable_table(code_length, max_locals, code_attribute_length, - cp, &localvariable_type_table_length[lvtt_cnt], true, // is LVTT CHECK_(nullHandle)); lvtt_cnt++; } else if (UseSplitVerifier && _major_version >= Verifier::STACKMAP_ATTRIBUTE_MAJOR_VERSION && - cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_stack_map_table()) { + _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_stack_map_table()) { // Stack map is only needed by the new verifier in JDK1.5. if (parsed_stackmap_attribute) { classfile_parse_error("Multiple StackMapTable attributes in class file %s", CHECK_(nullHandle)); } - stackmap_data = parse_stackmap_table(loader_data, code_attribute_length, CHECK_(nullHandle)); + stackmap_data = parse_stackmap_table(code_attribute_length, CHECK_(nullHandle)); + stackmap_data_length = code_attribute_length; parsed_stackmap_attribute = true; } else { // Skip unknown attributes @@ -2301,7 +2225,7 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, checked_exceptions_start = parse_checked_exceptions(&checked_exceptions_length, method_attribute_length, - cp, CHECK_(nullHandle)); + CHECK_(nullHandle)); } else if (method_attribute_name == vmSymbols::tag_method_parameters()) { // reject multiple method parameters if (method_parameters_seen) { @@ -2359,9 +2283,8 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, runtime_visible_annotations_length = method_attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); - parse_annotations(loader_data, - runtime_visible_annotations, - runtime_visible_annotations_length, cp, &parsed_annotations, + parse_annotations(runtime_visible_annotations, + runtime_visible_annotations_length, &parsed_annotations, CHECK_(nullHandle)); cfs->skip_u1(runtime_visible_annotations_length, CHECK_(nullHandle)); } else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) { @@ -2434,18 +2357,18 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, 0); Method* m = Method::allocate( - loader_data, code_length, access_flags, &sizes, + _loader_data, code_length, access_flags, &sizes, ConstMethod::NORMAL, CHECK_(nullHandle)); ClassLoadingService::add_class_method_size(m->size()*HeapWordSize); // Fill in information from fixed part (access_flags already set) - m->set_constants(cp()); + m->set_constants(_cp); m->set_name_index(name_index); m->set_signature_index(signature_index); #ifdef CC_INTERP // hmm is there a gc issue here?? - ResultTypeFinder rtf(cp->symbol_at(signature_index)); + ResultTypeFinder rtf(_cp->symbol_at(signature_index)); m->set_result_index(rtf.type()); #endif @@ -2464,7 +2387,10 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, // Fill in code attribute information m->set_max_stack(max_stack); m->set_max_locals(max_locals); - m->constMethod()->set_stackmap_data(stackmap_data); + if (stackmap_data != NULL) { + m->constMethod()->copy_stackmap_data(_loader_data, stackmap_data, + stackmap_data_length, CHECK_NULL); + } // Copy byte codes m->set_code(code_start); @@ -2520,7 +2446,7 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, parsed_annotations.apply_to(m); // Copy annotations - copy_method_annotations(loader_data, m->constMethod(), + copy_method_annotations(m->constMethod(), runtime_visible_annotations, runtime_visible_annotations_length, runtime_invisible_annotations, @@ -2560,9 +2486,7 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, // from the methods back up to the containing klass. These flag values // are added to klass's access_flags. -Array* ClassFileParser::parse_methods(ClassLoaderData* loader_data, - constantPoolHandle cp, - bool is_interface, +Array* ClassFileParser::parse_methods(bool is_interface, AccessFlags* promoted_flags, bool* has_final_method, bool* has_default_methods, @@ -2571,15 +2495,13 @@ Array* ClassFileParser::parse_methods(ClassLoaderData* loader_data, cfs->guarantee_more(2, CHECK_NULL); // length u2 length = cfs->get_u2_fast(); if (length == 0) { - return Universe::the_empty_method_array(); + _methods = Universe::the_empty_method_array(); } else { - // FIXME: Handle leaks at later failures. - Array* methods = MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); + _methods = MetadataFactory::new_array(_loader_data, length, NULL, CHECK_NULL); HandleMark hm(THREAD); for (int index = 0; index < length; index++) { - methodHandle method = parse_method(loader_data, - cp, is_interface, + methodHandle method = parse_method(is_interface, promoted_flags, CHECK_NULL); @@ -2590,7 +2512,7 @@ Array* ClassFileParser::parse_methods(ClassLoaderData* loader_data, // default method *has_default_methods = true; } - methods->at_put(index, method()); + _methods->at_put(index, method()); } if (_need_verify && length > 1) { @@ -2603,7 +2525,7 @@ Array* ClassFileParser::parse_methods(ClassLoaderData* loader_data, { debug_only(No_Safepoint_Verifier nsv;) for (int i = 0; i < length; i++) { - Method* m = methods->at(i); + Method* m = _methods->at(i); // If no duplicates, add name/signature in hashtable names_and_sigs. if (!put_after_lookup(m->name(), m->signature(), names_and_sigs)) { dup = true; @@ -2616,14 +2538,12 @@ Array* ClassFileParser::parse_methods(ClassLoaderData* loader_data, CHECK_NULL); } } - return methods; } + return _methods; } -Array* ClassFileParser::sort_methods(ClassLoaderData* loader_data, - Array* methods, - TRAPS) { +intArray* ClassFileParser::sort_methods(Array* methods) { int length = methods->length(); // If JVMTI original method ordering or sharing is enabled we have to // remember the original class file ordering. @@ -2641,10 +2561,11 @@ Array* ClassFileParser::sort_methods(ClassLoaderData* loader_data, // Note that the ordering is not alphabetical, see Symbol::fast_compare Method::sort_methods(methods); + intArray* method_ordering = NULL; // If JVMTI original method ordering or sharing is enabled construct int // array remembering the original ordering if (JvmtiExport::can_maintain_original_method_order() || DumpSharedSpaces) { - Array* method_ordering = MetadataFactory::new_array(loader_data, length, CHECK_NULL); + method_ordering = new intArray(length); for (int index = 0; index < length; index++) { Method* m = methods->at(index); int old_index = m->vtable_index(); @@ -2652,29 +2573,25 @@ Array* ClassFileParser::sort_methods(ClassLoaderData* loader_data, method_ordering->at_put(index, old_index); m->set_vtable_index(Method::invalid_vtable_index); } - return method_ordering; - } else { - return Universe::the_empty_int_array(); } + return method_ordering; } -void ClassFileParser::parse_classfile_sourcefile_attribute(constantPoolHandle cp, TRAPS) { +void ClassFileParser::parse_classfile_sourcefile_attribute(TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK); // sourcefile_index u2 sourcefile_index = cfs->get_u2_fast(); check_property( - valid_cp_range(sourcefile_index, cp->length()) && - cp->tag_at(sourcefile_index).is_utf8(), + valid_symbol_at(sourcefile_index), "Invalid SourceFile attribute at constant pool index %u in class file %s", sourcefile_index, CHECK); - set_class_sourcefile(cp->symbol_at(sourcefile_index)); + set_class_sourcefile(_cp->symbol_at(sourcefile_index)); } -void ClassFileParser::parse_classfile_source_debug_extension_attribute(constantPoolHandle cp, - int length, TRAPS) { +void ClassFileParser::parse_classfile_source_debug_extension_attribute(int length, TRAPS) { ClassFileStream* cfs = stream(); u1* sde_buffer = cfs->get_u1_buffer(); assert(sde_buffer != NULL, "null sde buffer"); @@ -2698,12 +2615,10 @@ void ClassFileParser::parse_classfile_source_debug_extension_attribute(constantP #define RECOGNIZED_INNER_CLASS_MODIFIERS (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED | JVM_ACC_STATIC) // Return number of classes in the inner classes attribute table -u2 ClassFileParser::parse_classfile_inner_classes_attribute(ClassLoaderData* loader_data, - u1* inner_classes_attribute_start, +u2 ClassFileParser::parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start, bool parsed_enclosingmethod_attribute, u2 enclosing_method_class_index, u2 enclosing_method_method_index, - constantPoolHandle cp, TRAPS) { ClassFileStream* cfs = stream(); u1* current_mark = cfs->current(); @@ -2724,33 +2639,31 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(ClassLoaderData* loa // enclosing_method_class_index, // enclosing_method_method_index] int size = length * 4 + (parsed_enclosingmethod_attribute ? 2 : 0); - // FIXME: Will leak on exceptions. - Array* inner_classes = MetadataFactory::new_array(loader_data, size, CHECK_0); + Array* inner_classes = MetadataFactory::new_array(_loader_data, size, CHECK_0); + _inner_classes = inner_classes; + int index = 0; - int cp_size = cp->length(); + int cp_size = _cp->length(); cfs->guarantee_more(8 * length, CHECK_0); // 4-tuples of u2 for (int n = 0; n < length; n++) { // Inner class index u2 inner_class_info_index = cfs->get_u2_fast(); check_property( inner_class_info_index == 0 || - (valid_cp_range(inner_class_info_index, cp_size) && - is_klass_reference(cp, inner_class_info_index)), + valid_klass_reference_at(inner_class_info_index), "inner_class_info_index %u has bad constant type in class file %s", inner_class_info_index, CHECK_0); // Outer class index u2 outer_class_info_index = cfs->get_u2_fast(); check_property( outer_class_info_index == 0 || - (valid_cp_range(outer_class_info_index, cp_size) && - is_klass_reference(cp, outer_class_info_index)), + valid_klass_reference_at(outer_class_info_index), "outer_class_info_index %u has bad constant type in class file %s", outer_class_info_index, CHECK_0); // Inner class name u2 inner_name_index = cfs->get_u2_fast(); check_property( - inner_name_index == 0 || (valid_cp_range(inner_name_index, cp_size) && - cp->tag_at(inner_name_index).is_utf8()), + inner_name_index == 0 || valid_symbol_at(inner_name_index), "inner_name_index %u has bad constant type in class file %s", inner_name_index, CHECK_0); if (_need_verify) { @@ -2794,33 +2707,27 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(ClassLoaderData* loa } assert(index == size, "wrong size"); - // Update InstanceKlass with inner class info. - set_class_inner_classes(inner_classes); - // Restore buffer's current position. cfs->set_current(current_mark); return length; } -void ClassFileParser::parse_classfile_synthetic_attribute(constantPoolHandle cp, TRAPS) { +void ClassFileParser::parse_classfile_synthetic_attribute(TRAPS) { set_class_synthetic_flag(true); } -void ClassFileParser::parse_classfile_signature_attribute(constantPoolHandle cp, TRAPS) { +void ClassFileParser::parse_classfile_signature_attribute(TRAPS) { ClassFileStream* cfs = stream(); u2 signature_index = cfs->get_u2(CHECK); check_property( - valid_cp_range(signature_index, cp->length()) && - cp->tag_at(signature_index).is_utf8(), + valid_symbol_at(signature_index), "Invalid constant pool index %u in Signature attribute in class file %s", signature_index, CHECK); - set_class_generic_signature(cp->symbol_at(signature_index)); + set_class_generic_signature(_cp->symbol_at(signature_index)); } -void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderData* loader_data, - constantPoolHandle cp, - u4 attribute_byte_length, TRAPS) { +void ClassFileParser::parse_classfile_bootstrap_methods_attribute(u4 attribute_byte_length, TRAPS) { ClassFileStream* cfs = stream(); u1* current_start = cfs->current(); @@ -2841,10 +2748,14 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderDat // The array begins with a series of short[2] pairs, one for each tuple. int index_size = (attribute_array_length * 2); - Array* operands = MetadataFactory::new_array(loader_data, index_size + operand_count, CHECK); + Array* operands = MetadataFactory::new_array(_loader_data, index_size + operand_count, CHECK); + + // Eagerly assign operands so they will be deallocated with the constant + // pool if there is an error. + _cp->set_operands(operands); int operand_fill_index = index_size; - int cp_size = cp->length(); + int cp_size = _cp->length(); for (int n = 0; n < attribute_array_length; n++) { // Store a 32-bit offset into the header of the operand array. @@ -2856,7 +2767,7 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderDat u2 argument_count = cfs->get_u2_fast(); check_property( valid_cp_range(bootstrap_method_index, cp_size) && - cp->tag_at(bootstrap_method_index).is_method_handle(), + _cp->tag_at(bootstrap_method_index).is_method_handle(), "bootstrap_method_index %u has bad constant type in class file %s", bootstrap_method_index, CHECK); @@ -2868,7 +2779,7 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderDat u2 argument_index = cfs->get_u2_fast(); check_property( valid_cp_range(argument_index, cp_size) && - cp->tag_at(argument_index).is_loadable_constant(), + _cp->tag_at(argument_index).is_loadable_constant(), "argument_index %u has bad constant type in class file %s", argument_index, CHECK); @@ -2883,17 +2794,13 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderDat guarantee_property(current_end == current_start + attribute_byte_length, "Bad length on BootstrapMethods in class file %s", CHECK); - - cp->set_operands(operands); } -void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, - constantPoolHandle cp, - ClassFileParser::ClassAnnotationCollector* parsed_annotations, +void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotationCollector* parsed_annotations, TRAPS) { ClassFileStream* cfs = stream(); // Set inner classes attribute to default sentinel - set_class_inner_classes(Universe::the_empty_short_array()); + _inner_classes = Universe::the_empty_short_array(); cfs->guarantee_more(2, CHECK); // attributes_count u2 attributes_count = cfs->get_u2_fast(); bool parsed_sourcefile_attribute = false; @@ -2918,11 +2825,10 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, u2 attribute_name_index = cfs->get_u2_fast(); u4 attribute_length = cfs->get_u4_fast(); check_property( - valid_cp_range(attribute_name_index, cp->length()) && - cp->tag_at(attribute_name_index).is_utf8(), + valid_symbol_at(attribute_name_index), "Attribute name has bad constant pool index %u in class file %s", attribute_name_index, CHECK); - Symbol* tag = cp->symbol_at(attribute_name_index); + Symbol* tag = _cp->symbol_at(attribute_name_index); if (tag == vmSymbols::tag_source_file()) { // Check for SourceFile tag if (_need_verify) { @@ -2933,10 +2839,10 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, } else { parsed_sourcefile_attribute = true; } - parse_classfile_sourcefile_attribute(cp, CHECK); + parse_classfile_sourcefile_attribute(CHECK); } else if (tag == vmSymbols::tag_source_debug_extension()) { // Check for SourceDebugExtension tag - parse_classfile_source_debug_extension_attribute(cp, (int)attribute_length, CHECK); + parse_classfile_source_debug_extension_attribute((int)attribute_length, CHECK); } else if (tag == vmSymbols::tag_inner_classes()) { // Check for InnerClasses tag if (parsed_innerclasses_attribute) { @@ -2955,7 +2861,7 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, "Invalid Synthetic classfile attribute length %u in class file %s", attribute_length, CHECK); } - parse_classfile_synthetic_attribute(cp, CHECK); + parse_classfile_synthetic_attribute(CHECK); } else if (tag == vmSymbols::tag_deprecated()) { // Check for Deprecatd tag - 4276120 if (attribute_length != 0) { @@ -2970,15 +2876,13 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, "Wrong Signature attribute length %u in class file %s", attribute_length, CHECK); } - parse_classfile_signature_attribute(cp, CHECK); + parse_classfile_signature_attribute(CHECK); } else if (tag == vmSymbols::tag_runtime_visible_annotations()) { runtime_visible_annotations_length = attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); - parse_annotations(loader_data, - runtime_visible_annotations, + parse_annotations(runtime_visible_annotations, runtime_visible_annotations_length, - cp, parsed_annotations, CHECK); cfs->skip_u1(runtime_visible_annotations_length, CHECK); @@ -3000,13 +2904,11 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, classfile_parse_error("Invalid class index in EnclosingMethod attribute in class file %s", CHECK); } // Validate the constant pool indices and types - if (!cp->is_within_bounds(enclosing_method_class_index) || - !is_klass_reference(cp, enclosing_method_class_index)) { - classfile_parse_error("Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK); - } + check_property(valid_klass_reference_at(enclosing_method_class_index), + "Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK); if (enclosing_method_method_index != 0 && - (!cp->is_within_bounds(enclosing_method_method_index) || - !cp->tag_at(enclosing_method_method_index).is_name_and_type())) { + (!_cp->is_within_bounds(enclosing_method_method_index) || + !_cp->tag_at(enclosing_method_method_index).is_name_and_type())) { classfile_parse_error("Invalid or out-of-bounds method index in EnclosingMethod attribute in class file %s", CHECK); } } else if (tag == vmSymbols::tag_bootstrap_methods() && @@ -3014,7 +2916,7 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, if (parsed_bootstrap_methods_attribute) classfile_parse_error("Multiple BootstrapMethods attributes in class file %s", CHECK); parsed_bootstrap_methods_attribute = true; - parse_classfile_bootstrap_methods_attribute(loader_data, cp, attribute_length, CHECK); + parse_classfile_bootstrap_methods_attribute(attribute_length, CHECK); } else if (tag == vmSymbols::tag_runtime_visible_type_annotations()) { runtime_visible_type_annotations_length = attribute_length; runtime_visible_type_annotations = cfs->get_u1_buffer(); @@ -3035,29 +2937,24 @@ void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, cfs->skip_u1(attribute_length, CHECK); } } - AnnotationArray* annotations = assemble_annotations(loader_data, - runtime_visible_annotations, - runtime_visible_annotations_length, - runtime_invisible_annotations, - runtime_invisible_annotations_length, - CHECK); - set_class_annotations(annotations); - AnnotationArray* type_annotations = assemble_annotations(loader_data, - runtime_visible_type_annotations, - runtime_visible_type_annotations_length, - runtime_invisible_type_annotations, - runtime_invisible_type_annotations_length, - CHECK); - set_class_type_annotations(type_annotations); + _annotations = assemble_annotations(runtime_visible_annotations, + runtime_visible_annotations_length, + runtime_invisible_annotations, + runtime_invisible_annotations_length, + CHECK); + _type_annotations = assemble_annotations(runtime_visible_type_annotations, + runtime_visible_type_annotations_length, + runtime_invisible_type_annotations, + runtime_invisible_type_annotations_length, + CHECK); if (parsed_innerclasses_attribute || parsed_enclosingmethod_attribute) { u2 num_of_classes = parse_classfile_inner_classes_attribute( - loader_data, inner_classes_attribute_start, parsed_innerclasses_attribute, enclosing_method_class_index, enclosing_method_method_index, - cp, CHECK); + CHECK); if (parsed_innerclasses_attribute &&_need_verify && _major_version >= JAVA_1_5_VERSION) { guarantee_property( inner_classes_attribute_length == sizeof(num_of_classes) + 4 * sizeof(u2) * num_of_classes, @@ -3085,18 +2982,43 @@ void ClassFileParser::apply_parsed_class_attributes(instanceKlassHandle k) { if (_sde_buffer != NULL) { k->set_source_debug_extension(_sde_buffer, _sde_length); } - k->set_inner_classes(_inner_classes); } -AnnotationArray* ClassFileParser::assemble_annotations(ClassLoaderData* loader_data, - u1* runtime_visible_annotations, +// Transfer ownership of metadata allocated to the InstanceKlass. +void ClassFileParser::apply_parsed_class_metadata( + instanceKlassHandle this_klass, + int java_fields_count, TRAPS) { + // Assign annotations if needed + if (_annotations != NULL || _type_annotations != NULL || + _fields_annotations != NULL || _fields_type_annotations != NULL) { + Annotations* annotations = Annotations::allocate(_loader_data, CHECK); + annotations->set_class_annotations(_annotations); + annotations->set_class_type_annotations(_type_annotations); + annotations->set_fields_annotations(_fields_annotations); + annotations->set_fields_type_annotations(_fields_type_annotations); + this_klass->set_annotations(annotations); + } + + _cp->set_pool_holder(this_klass()); + this_klass->set_constants(_cp); + this_klass->set_fields(_fields, java_fields_count); + this_klass->set_methods(_methods); + this_klass->set_inner_classes(_inner_classes); + this_klass->set_local_interfaces(_local_interfaces); + this_klass->set_transitive_interfaces(_transitive_interfaces); + + // Clear out these fields so they don't get deallocated by the destructor + clear_class_metadata(); +} + +AnnotationArray* ClassFileParser::assemble_annotations(u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, int runtime_invisible_annotations_length, TRAPS) { AnnotationArray* annotations = NULL; if (runtime_visible_annotations != NULL || runtime_invisible_annotations != NULL) { - annotations = MetadataFactory::new_array(loader_data, + annotations = MetadataFactory::new_array(_loader_data, runtime_visible_annotations_length + runtime_invisible_annotations_length, CHECK_(annotations)); @@ -3144,6 +3066,581 @@ static void parseAndPrintGenericSignatures( #endif // ndef PRODUCT +instanceKlassHandle ClassFileParser::parse_super_class(int super_class_index, + TRAPS) { + instanceKlassHandle super_klass; + if (super_class_index == 0) { + check_property(_class_name == vmSymbols::java_lang_Object(), + "Invalid superclass index %u in class file %s", + super_class_index, + CHECK_NULL); + } else { + check_property(valid_klass_reference_at(super_class_index), + "Invalid superclass index %u in class file %s", + super_class_index, + CHECK_NULL); + // The class name should be legal because it is checked when parsing constant pool. + // However, make sure it is not an array type. + bool is_array = false; + if (_cp->tag_at(super_class_index).is_klass()) { + super_klass = instanceKlassHandle(THREAD, _cp->resolved_klass_at(super_class_index)); + if (_need_verify) + is_array = super_klass->oop_is_array(); + } else if (_need_verify) { + is_array = (_cp->unresolved_klass_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY); + } + if (_need_verify) { + guarantee_property(!is_array, + "Bad superclass name in class file %s", CHECK_NULL); + } + } + return super_klass; +} + + +// Values needed for oopmap and InstanceKlass creation +class FieldLayoutInfo : public StackObj { + public: + int* nonstatic_oop_offsets; + unsigned int* nonstatic_oop_counts; + unsigned int nonstatic_oop_map_count; + unsigned int total_oop_map_count; + int instance_size; + int nonstatic_field_size; + int static_field_size; + bool has_nonstatic_fields; +}; + +// Layout fields and fill in FieldLayoutInfo. Could use more refactoring! +void ClassFileParser::layout_fields(Handle class_loader, + FieldAllocationCount* fac, + ClassAnnotationCollector* parsed_annotations, + FieldLayoutInfo* info, + TRAPS) { + + // get the padding width from the option + // TODO: Ask VM about specific CPU we are running on + int pad_size = ContendedPaddingWidth; + + // Field size and offset computation + int nonstatic_field_size = _super_klass() == NULL ? 0 : _super_klass()->nonstatic_field_size(); +#ifndef PRODUCT + int orig_nonstatic_field_size = 0; +#endif + int next_static_oop_offset; + int next_static_double_offset; + int next_static_word_offset; + int next_static_short_offset; + int next_static_byte_offset; + int next_nonstatic_oop_offset; + int next_nonstatic_double_offset; + int next_nonstatic_word_offset; + int next_nonstatic_short_offset; + int next_nonstatic_byte_offset; + int next_nonstatic_type_offset; + int first_nonstatic_oop_offset; + int first_nonstatic_field_offset; + int next_nonstatic_field_offset; + int next_nonstatic_padded_offset; + + // Count the contended fields by type. + int nonstatic_contended_count = 0; + FieldAllocationCount fac_contended; + for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { + FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); + if (fs.is_contended()) { + fac_contended.count[atype]++; + if (!fs.access_flags().is_static()) { + nonstatic_contended_count++; + } + } + } + int contended_count = nonstatic_contended_count; + + + // Calculate the starting byte offsets + next_static_oop_offset = InstanceMirrorKlass::offset_of_static_fields(); + next_static_double_offset = next_static_oop_offset + + ((fac->count[STATIC_OOP]) * heapOopSize); + if ( fac->count[STATIC_DOUBLE] && + (Universe::field_type_should_be_aligned(T_DOUBLE) || + Universe::field_type_should_be_aligned(T_LONG)) ) { + next_static_double_offset = align_size_up(next_static_double_offset, BytesPerLong); + } + + next_static_word_offset = next_static_double_offset + + ((fac->count[STATIC_DOUBLE]) * BytesPerLong); + next_static_short_offset = next_static_word_offset + + ((fac->count[STATIC_WORD]) * BytesPerInt); + next_static_byte_offset = next_static_short_offset + + ((fac->count[STATIC_SHORT]) * BytesPerShort); + + first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() + + nonstatic_field_size * heapOopSize; + + // class is contended, pad before all the fields + if (parsed_annotations->is_contended()) { + first_nonstatic_field_offset += pad_size; + } + + next_nonstatic_field_offset = first_nonstatic_field_offset; + + unsigned int nonstatic_double_count = fac->count[NONSTATIC_DOUBLE] - fac_contended.count[NONSTATIC_DOUBLE]; + unsigned int nonstatic_word_count = fac->count[NONSTATIC_WORD] - fac_contended.count[NONSTATIC_WORD]; + unsigned int nonstatic_short_count = fac->count[NONSTATIC_SHORT] - fac_contended.count[NONSTATIC_SHORT]; + unsigned int nonstatic_byte_count = fac->count[NONSTATIC_BYTE] - fac_contended.count[NONSTATIC_BYTE]; + unsigned int nonstatic_oop_count = fac->count[NONSTATIC_OOP] - fac_contended.count[NONSTATIC_OOP]; + + bool super_has_nonstatic_fields = + (_super_klass() != NULL && _super_klass->has_nonstatic_fields()); + bool has_nonstatic_fields = super_has_nonstatic_fields || + ((nonstatic_double_count + nonstatic_word_count + + nonstatic_short_count + nonstatic_byte_count + + nonstatic_oop_count) != 0); + + + // Prepare list of oops for oop map generation. + int* nonstatic_oop_offsets; + unsigned int* nonstatic_oop_counts; + unsigned int nonstatic_oop_map_count = 0; + + nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD( + THREAD, int, nonstatic_oop_count + 1); + nonstatic_oop_counts = NEW_RESOURCE_ARRAY_IN_THREAD( + THREAD, unsigned int, nonstatic_oop_count + 1); + + first_nonstatic_oop_offset = 0; // will be set for first oop field + +#ifndef PRODUCT + if( PrintCompactFieldsSavings ) { + next_nonstatic_double_offset = next_nonstatic_field_offset + + (nonstatic_oop_count * heapOopSize); + if ( nonstatic_double_count > 0 ) { + next_nonstatic_double_offset = align_size_up(next_nonstatic_double_offset, BytesPerLong); + } + next_nonstatic_word_offset = next_nonstatic_double_offset + + (nonstatic_double_count * BytesPerLong); + next_nonstatic_short_offset = next_nonstatic_word_offset + + (nonstatic_word_count * BytesPerInt); + next_nonstatic_byte_offset = next_nonstatic_short_offset + + (nonstatic_short_count * BytesPerShort); + next_nonstatic_type_offset = align_size_up((next_nonstatic_byte_offset + + nonstatic_byte_count ), heapOopSize ); + orig_nonstatic_field_size = nonstatic_field_size + + ((next_nonstatic_type_offset - first_nonstatic_field_offset)/heapOopSize); + } +#endif + bool compact_fields = CompactFields; + int allocation_style = FieldsAllocationStyle; + if( allocation_style < 0 || allocation_style > 2 ) { // Out of range? + assert(false, "0 <= FieldsAllocationStyle <= 2"); + allocation_style = 1; // Optimistic + } + + // The next classes have predefined hard-coded fields offsets + // (see in JavaClasses::compute_hard_coded_offsets()). + // Use default fields allocation order for them. + if( (allocation_style != 0 || compact_fields ) && class_loader.is_null() && + (_class_name == vmSymbols::java_lang_AssertionStatusDirectives() || + _class_name == vmSymbols::java_lang_Class() || + _class_name == vmSymbols::java_lang_ClassLoader() || + _class_name == vmSymbols::java_lang_ref_Reference() || + _class_name == vmSymbols::java_lang_ref_SoftReference() || + _class_name == vmSymbols::java_lang_StackTraceElement() || + _class_name == vmSymbols::java_lang_String() || + _class_name == vmSymbols::java_lang_Throwable() || + _class_name == vmSymbols::java_lang_Boolean() || + _class_name == vmSymbols::java_lang_Character() || + _class_name == vmSymbols::java_lang_Float() || + _class_name == vmSymbols::java_lang_Double() || + _class_name == vmSymbols::java_lang_Byte() || + _class_name == vmSymbols::java_lang_Short() || + _class_name == vmSymbols::java_lang_Integer() || + _class_name == vmSymbols::java_lang_Long())) { + allocation_style = 0; // Allocate oops first + compact_fields = false; // Don't compact fields + } + + if( allocation_style == 0 ) { + // Fields order: oops, longs/doubles, ints, shorts/chars, bytes, padded fields + next_nonstatic_oop_offset = next_nonstatic_field_offset; + next_nonstatic_double_offset = next_nonstatic_oop_offset + + (nonstatic_oop_count * heapOopSize); + } else if( allocation_style == 1 ) { + // Fields order: longs/doubles, ints, shorts/chars, bytes, oops, padded fields + next_nonstatic_double_offset = next_nonstatic_field_offset; + } else if( allocation_style == 2 ) { + // Fields allocation: oops fields in super and sub classes are together. + if( nonstatic_field_size > 0 && _super_klass() != NULL && + _super_klass->nonstatic_oop_map_size() > 0 ) { + unsigned int map_count = _super_klass->nonstatic_oop_map_count(); + OopMapBlock* first_map = _super_klass->start_of_nonstatic_oop_maps(); + OopMapBlock* last_map = first_map + map_count - 1; + int next_offset = last_map->offset() + (last_map->count() * heapOopSize); + if (next_offset == next_nonstatic_field_offset) { + allocation_style = 0; // allocate oops first + next_nonstatic_oop_offset = next_nonstatic_field_offset; + next_nonstatic_double_offset = next_nonstatic_oop_offset + + (nonstatic_oop_count * heapOopSize); + } + } + if( allocation_style == 2 ) { + allocation_style = 1; // allocate oops last + next_nonstatic_double_offset = next_nonstatic_field_offset; + } + } else { + ShouldNotReachHere(); + } + + int nonstatic_oop_space_count = 0; + int nonstatic_word_space_count = 0; + int nonstatic_short_space_count = 0; + int nonstatic_byte_space_count = 0; + int nonstatic_oop_space_offset; + int nonstatic_word_space_offset; + int nonstatic_short_space_offset; + int nonstatic_byte_space_offset; + + if( nonstatic_double_count > 0 ) { + int offset = next_nonstatic_double_offset; + next_nonstatic_double_offset = align_size_up(offset, BytesPerLong); + if( compact_fields && offset != next_nonstatic_double_offset ) { + // Allocate available fields into the gap before double field. + int length = next_nonstatic_double_offset - offset; + assert(length == BytesPerInt, ""); + nonstatic_word_space_offset = offset; + if( nonstatic_word_count > 0 ) { + nonstatic_word_count -= 1; + nonstatic_word_space_count = 1; // Only one will fit + length -= BytesPerInt; + offset += BytesPerInt; + } + nonstatic_short_space_offset = offset; + while( length >= BytesPerShort && nonstatic_short_count > 0 ) { + nonstatic_short_count -= 1; + nonstatic_short_space_count += 1; + length -= BytesPerShort; + offset += BytesPerShort; + } + nonstatic_byte_space_offset = offset; + while( length > 0 && nonstatic_byte_count > 0 ) { + nonstatic_byte_count -= 1; + nonstatic_byte_space_count += 1; + length -= 1; + } + // Allocate oop field in the gap if there are no other fields for that. + nonstatic_oop_space_offset = offset; + if( length >= heapOopSize && nonstatic_oop_count > 0 && + allocation_style != 0 ) { // when oop fields not first + nonstatic_oop_count -= 1; + nonstatic_oop_space_count = 1; // Only one will fit + length -= heapOopSize; + offset += heapOopSize; + } + } + } + + next_nonstatic_word_offset = next_nonstatic_double_offset + + (nonstatic_double_count * BytesPerLong); + next_nonstatic_short_offset = next_nonstatic_word_offset + + (nonstatic_word_count * BytesPerInt); + next_nonstatic_byte_offset = next_nonstatic_short_offset + + (nonstatic_short_count * BytesPerShort); + next_nonstatic_padded_offset = next_nonstatic_byte_offset + + nonstatic_byte_count; + + // let oops jump before padding with this allocation style + if( allocation_style == 1 ) { + next_nonstatic_oop_offset = next_nonstatic_padded_offset; + if( nonstatic_oop_count > 0 ) { + next_nonstatic_oop_offset = align_size_up(next_nonstatic_oop_offset, heapOopSize); + } + next_nonstatic_padded_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize); + } + + // Iterate over fields again and compute correct offsets. + // The field allocation type was temporarily stored in the offset slot. + // oop fields are located before non-oop fields (static and non-static). + for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { + + // skip already laid out fields + if (fs.is_offset_set()) continue; + + // contended instance fields are handled below + if (fs.is_contended() && !fs.access_flags().is_static()) continue; + + int real_offset; + FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); + + // pack the rest of the fields + switch (atype) { + case STATIC_OOP: + real_offset = next_static_oop_offset; + next_static_oop_offset += heapOopSize; + break; + case STATIC_BYTE: + real_offset = next_static_byte_offset; + next_static_byte_offset += 1; + break; + case STATIC_SHORT: + real_offset = next_static_short_offset; + next_static_short_offset += BytesPerShort; + break; + case STATIC_WORD: + real_offset = next_static_word_offset; + next_static_word_offset += BytesPerInt; + break; + case STATIC_DOUBLE: + real_offset = next_static_double_offset; + next_static_double_offset += BytesPerLong; + break; + case NONSTATIC_OOP: + if( nonstatic_oop_space_count > 0 ) { + real_offset = nonstatic_oop_space_offset; + nonstatic_oop_space_offset += heapOopSize; + nonstatic_oop_space_count -= 1; + } else { + real_offset = next_nonstatic_oop_offset; + next_nonstatic_oop_offset += heapOopSize; + } + // Update oop maps + if( nonstatic_oop_map_count > 0 && + nonstatic_oop_offsets[nonstatic_oop_map_count - 1] == + real_offset - + int(nonstatic_oop_counts[nonstatic_oop_map_count - 1]) * + heapOopSize ) { + // Extend current oop map + nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1; + } else { + // Create new oop map + nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; + nonstatic_oop_counts [nonstatic_oop_map_count] = 1; + nonstatic_oop_map_count += 1; + if( first_nonstatic_oop_offset == 0 ) { // Undefined + first_nonstatic_oop_offset = real_offset; + } + } + break; + case NONSTATIC_BYTE: + if( nonstatic_byte_space_count > 0 ) { + real_offset = nonstatic_byte_space_offset; + nonstatic_byte_space_offset += 1; + nonstatic_byte_space_count -= 1; + } else { + real_offset = next_nonstatic_byte_offset; + next_nonstatic_byte_offset += 1; + } + break; + case NONSTATIC_SHORT: + if( nonstatic_short_space_count > 0 ) { + real_offset = nonstatic_short_space_offset; + nonstatic_short_space_offset += BytesPerShort; + nonstatic_short_space_count -= 1; + } else { + real_offset = next_nonstatic_short_offset; + next_nonstatic_short_offset += BytesPerShort; + } + break; + case NONSTATIC_WORD: + if( nonstatic_word_space_count > 0 ) { + real_offset = nonstatic_word_space_offset; + nonstatic_word_space_offset += BytesPerInt; + nonstatic_word_space_count -= 1; + } else { + real_offset = next_nonstatic_word_offset; + next_nonstatic_word_offset += BytesPerInt; + } + break; + case NONSTATIC_DOUBLE: + real_offset = next_nonstatic_double_offset; + next_nonstatic_double_offset += BytesPerLong; + break; + default: + ShouldNotReachHere(); + } + fs.set_offset(real_offset); + } + + + // Handle the contended cases. + // + // Each contended field should not intersect the cache line with another contended field. + // In the absence of alignment information, we end up with pessimistically separating + // the fields with full-width padding. + // + // Additionally, this should not break alignment for the fields, so we round the alignment up + // for each field. + if (contended_count > 0) { + + // if there is at least one contended field, we need to have pre-padding for them + if (nonstatic_contended_count > 0) { + next_nonstatic_padded_offset += pad_size; + } + + // collect all contended groups + BitMap bm(_cp->size()); + for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { + // skip already laid out fields + if (fs.is_offset_set()) continue; + + if (fs.is_contended()) { + bm.set_bit(fs.contended_group()); + } + } + + int current_group = -1; + while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) { + + for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { + + // skip already laid out fields + if (fs.is_offset_set()) continue; + + // skip non-contended fields and fields from different group + if (!fs.is_contended() || (fs.contended_group() != current_group)) continue; + + // handle statics below + if (fs.access_flags().is_static()) continue; + + int real_offset; + FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); + + switch (atype) { + case NONSTATIC_BYTE: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, 1); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += 1; + break; + + case NONSTATIC_SHORT: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerShort); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += BytesPerShort; + break; + + case NONSTATIC_WORD: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerInt); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += BytesPerInt; + break; + + case NONSTATIC_DOUBLE: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerLong); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += BytesPerLong; + break; + + case NONSTATIC_OOP: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, heapOopSize); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += heapOopSize; + + // Create new oop map + nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; + nonstatic_oop_counts [nonstatic_oop_map_count] = 1; + nonstatic_oop_map_count += 1; + if( first_nonstatic_oop_offset == 0 ) { // Undefined + first_nonstatic_oop_offset = real_offset; + } + break; + + default: + ShouldNotReachHere(); + } + + if (fs.contended_group() == 0) { + // Contended group defines the equivalence class over the fields: + // the fields within the same contended group are not inter-padded. + // The only exception is default group, which does not incur the + // equivalence, and so requires intra-padding. + next_nonstatic_padded_offset += pad_size; + } + + fs.set_offset(real_offset); + } // for + + // Start laying out the next group. + // Note that this will effectively pad the last group in the back; + // this is expected to alleviate memory contention effects for + // subclass fields and/or adjacent object. + // If this was the default group, the padding is already in place. + if (current_group != 0) { + next_nonstatic_padded_offset += pad_size; + } + } + + // handle static fields + } + + // Size of instances + int notaligned_offset = next_nonstatic_padded_offset; + + // Entire class is contended, pad in the back. + // This helps to alleviate memory contention effects for subclass fields + // and/or adjacent object. + if (parsed_annotations->is_contended()) { + notaligned_offset += pad_size; + } + + int next_static_type_offset = align_size_up(next_static_byte_offset, wordSize); + int static_field_size = (next_static_type_offset - + InstanceMirrorKlass::offset_of_static_fields()) / wordSize; + + next_nonstatic_type_offset = align_size_up(notaligned_offset, heapOopSize ); + nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset + - first_nonstatic_field_offset)/heapOopSize); + + next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize ); + int instance_size = align_object_size(next_nonstatic_type_offset / wordSize); + + assert(instance_size == align_object_size(align_size_up( + (instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize + ((parsed_annotations->is_contended()) ? pad_size : 0)), + wordSize) / wordSize), "consistent layout helper value"); + + // Number of non-static oop map blocks allocated at end of klass. + const unsigned int total_oop_map_count = + compute_oop_map_count(_super_klass, nonstatic_oop_map_count, + first_nonstatic_oop_offset); + +#ifndef PRODUCT + if( PrintCompactFieldsSavings ) { + ResourceMark rm; + if( nonstatic_field_size < orig_nonstatic_field_size ) { + tty->print("[Saved %d of %d bytes in %s]\n", + (orig_nonstatic_field_size - nonstatic_field_size)*heapOopSize, + orig_nonstatic_field_size*heapOopSize, + _class_name); + } else if( nonstatic_field_size > orig_nonstatic_field_size ) { + tty->print("[Wasted %d over %d bytes in %s]\n", + (nonstatic_field_size - orig_nonstatic_field_size)*heapOopSize, + orig_nonstatic_field_size*heapOopSize, + _class_name); + } + } + + if (PrintFieldLayout) { + print_field_layout(_class_name, + _fields, + _cp, + instance_size, + first_nonstatic_field_offset, + next_nonstatic_field_offset, + next_static_type_offset); + } + +#endif + // Pass back information needed for InstanceKlass creation + info->nonstatic_oop_offsets = nonstatic_oop_offsets; + info->nonstatic_oop_counts = nonstatic_oop_counts; + info->nonstatic_oop_map_count = nonstatic_oop_map_count; + info->total_oop_map_count = total_oop_map_count; + info->instance_size = instance_size; + info->static_field_size = static_field_size; + info->nonstatic_field_size = nonstatic_field_size; + info->has_nonstatic_fields = has_nonstatic_fields; +} + + instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, ClassLoaderData* loader_data, Handle protection_domain, @@ -3176,7 +3673,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, jt->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::PARSE_CLASS); - init_parsed_class_attributes(); + init_parsed_class_attributes(loader_data); if (JvmtiExport::should_post_class_file_load_hook()) { // Get the cached class file bytes (if any) from the class that @@ -3271,8 +3768,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, _relax_verify = Verifier::relax_verify_for(class_loader()); // Constant pool - constantPoolHandle cp = parse_constant_pool(loader_data, CHECK_(nullHandle)); - ConstantPoolCleaner error_handler(cp); // set constant pool to be cleaned up. + constantPoolHandle cp = parse_constant_pool(CHECK_(nullHandle)); int cp_size = cp->length(); @@ -3290,7 +3786,6 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, access_flags.set_flags(flags); // This class and superclass - instanceKlassHandle super_klass; u2 this_class_index = cfs->get_u2_fast(); check_property( valid_cp_range(this_class_index, cp_size) && @@ -3345,59 +3840,27 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, } u2 super_class_index = cfs->get_u2_fast(); - if (super_class_index == 0) { - check_property(class_name == vmSymbols::java_lang_Object(), - "Invalid superclass index %u in class file %s", - super_class_index, - CHECK_(nullHandle)); - } else { - check_property(valid_cp_range(super_class_index, cp_size) && - is_klass_reference(cp, super_class_index), - "Invalid superclass index %u in class file %s", - super_class_index, - CHECK_(nullHandle)); - // The class name should be legal because it is checked when parsing constant pool. - // However, make sure it is not an array type. - bool is_array = false; - if (cp->tag_at(super_class_index).is_klass()) { - super_klass = instanceKlassHandle(THREAD, cp->resolved_klass_at(super_class_index)); - if (_need_verify) - is_array = super_klass->oop_is_array(); - } else if (_need_verify) { - is_array = (cp->unresolved_klass_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY); - } - if (_need_verify) { - guarantee_property(!is_array, - "Bad superclass name in class file %s", CHECK_(nullHandle)); - } - } + instanceKlassHandle super_klass = parse_super_class(super_class_index, + CHECK_NULL); // Interfaces u2 itfs_len = cfs->get_u2_fast(); - Array* local_interfaces; - if (itfs_len == 0) { - local_interfaces = Universe::the_empty_klass_array(); - } else { - local_interfaces = parse_interfaces( - cp, itfs_len, loader_data, protection_domain, _class_name, - &has_default_methods, CHECK_(nullHandle)); - } + Array* local_interfaces = + parse_interfaces(itfs_len, protection_domain, _class_name, + &has_default_methods, CHECK_(nullHandle)); u2 java_fields_count = 0; // Fields (offsets are filled in later) FieldAllocationCount fac; - Array* fields_annotations = NULL; - Array* fields_type_annotations = NULL; - Array* fields = parse_fields(loader_data, class_name, cp, access_flags.is_interface(), &fac, &fields_annotations, - &fields_type_annotations, - &java_fields_count, - CHECK_(nullHandle)); + Array* fields = parse_fields(class_name, + access_flags.is_interface(), + &fac, &java_fields_count, + CHECK_(nullHandle)); // Methods bool has_final_method = false; AccessFlags promoted_flags; promoted_flags.set_flags(0); - Array* methods = parse_methods(loader_data, - cp, access_flags.is_interface(), + Array* methods = parse_methods(access_flags.is_interface(), &promoted_flags, &has_final_method, &has_default_methods, @@ -3405,7 +3868,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, // Additional attributes ClassAnnotationCollector parsed_annotations; - parse_classfile_attributes(loader_data, cp, &parsed_annotations, CHECK_(nullHandle)); + parse_classfile_attributes(&parsed_annotations, CHECK_(nullHandle)); // Make sure this is the end of class file stream guarantee_property(cfs->at_eos(), "Extra bytes at the end of class file %s", CHECK_(nullHandle)); @@ -3452,13 +3915,15 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, } } + // save super klass for error handling. + _super_klass = super_klass; + // Compute the transitive list of all unique interfaces implemented by this class - Array* transitive_interfaces = compute_transitive_interfaces(loader_data, super_klass, local_interfaces, CHECK_(nullHandle)); + _transitive_interfaces = + compute_transitive_interfaces(super_klass, local_interfaces, CHECK_(nullHandle)); // sort methods - Array* method_ordering = sort_methods(loader_data, - methods, - CHECK_(nullHandle)); + intArray* method_ordering = sort_methods(methods); // promote flags from parse_methods() to the klass' flags access_flags.add_promoted_flags(promoted_flags.as_int()); @@ -3476,587 +3941,14 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, CHECK_(nullHandle)); // Size of Java itable (in words) - itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(transitive_interfaces); + itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(_transitive_interfaces); - // get the padding width from the option - // TODO: Ask VM about specific CPU we are running on - int pad_size = ContendedPaddingWidth; + FieldLayoutInfo info; + layout_fields(class_loader, &fac, &parsed_annotations, &info, CHECK_NULL); - // Field size and offset computation - int nonstatic_field_size = super_klass() == NULL ? 0 : super_klass->nonstatic_field_size(); -#ifndef PRODUCT - int orig_nonstatic_field_size = 0; -#endif - int next_static_oop_offset; - int next_static_double_offset; - int next_static_word_offset; - int next_static_short_offset; - int next_static_byte_offset; - int next_static_padded_offset; - int next_nonstatic_oop_offset; - int next_nonstatic_double_offset; - int next_nonstatic_word_offset; - int next_nonstatic_short_offset; - int next_nonstatic_byte_offset; - int next_nonstatic_type_offset; - int first_nonstatic_oop_offset; - int first_nonstatic_field_offset; - int next_nonstatic_field_offset; - int next_nonstatic_padded_offset; + int total_oop_map_size2 = + InstanceKlass::nonstatic_oop_map_size(info.total_oop_map_count); - // Count the contended fields by type. - int static_contended_count = 0; - int nonstatic_contended_count = 0; - FieldAllocationCount fac_contended; - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); - if (fs.is_contended()) { - fac_contended.count[atype]++; - if (fs.access_flags().is_static()) { - static_contended_count++; - } else { - nonstatic_contended_count++; - } - } - } - int contended_count = static_contended_count + nonstatic_contended_count; - - - // Calculate the starting byte offsets - next_static_oop_offset = InstanceMirrorKlass::offset_of_static_fields(); - - // class is contended, pad before all the fields - if (parsed_annotations.is_contended()) { - next_static_oop_offset += pad_size; - } - - next_static_double_offset = next_static_oop_offset + - ((fac.count[STATIC_OOP] - fac_contended.count[STATIC_OOP]) * heapOopSize); - if ( fac.count[STATIC_DOUBLE] && - (Universe::field_type_should_be_aligned(T_DOUBLE) || - Universe::field_type_should_be_aligned(T_LONG)) ) { - next_static_double_offset = align_size_up(next_static_double_offset, BytesPerLong); - } - - next_static_word_offset = next_static_double_offset + - ((fac.count[STATIC_DOUBLE] - fac_contended.count[STATIC_DOUBLE]) * BytesPerLong); - next_static_short_offset = next_static_word_offset + - ((fac.count[STATIC_WORD] - fac_contended.count[STATIC_WORD]) * BytesPerInt); - next_static_byte_offset = next_static_short_offset + - ((fac.count[STATIC_SHORT] - fac_contended.count[STATIC_SHORT]) * BytesPerShort); - next_static_padded_offset = next_static_byte_offset + - ((fac.count[STATIC_BYTE] - fac_contended.count[STATIC_BYTE]) * 1); - - first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() + - nonstatic_field_size * heapOopSize; - - // class is contended, pad before all the fields - if (parsed_annotations.is_contended()) { - first_nonstatic_field_offset += pad_size; - } - - next_nonstatic_field_offset = first_nonstatic_field_offset; - - unsigned int nonstatic_double_count = fac.count[NONSTATIC_DOUBLE] - fac_contended.count[NONSTATIC_DOUBLE]; - unsigned int nonstatic_word_count = fac.count[NONSTATIC_WORD] - fac_contended.count[NONSTATIC_WORD]; - unsigned int nonstatic_short_count = fac.count[NONSTATIC_SHORT] - fac_contended.count[NONSTATIC_SHORT]; - unsigned int nonstatic_byte_count = fac.count[NONSTATIC_BYTE] - fac_contended.count[NONSTATIC_BYTE]; - unsigned int nonstatic_oop_count = fac.count[NONSTATIC_OOP] - fac_contended.count[NONSTATIC_OOP]; - - bool super_has_nonstatic_fields = - (super_klass() != NULL && super_klass->has_nonstatic_fields()); - bool has_nonstatic_fields = super_has_nonstatic_fields || - ((nonstatic_double_count + nonstatic_word_count + - nonstatic_short_count + nonstatic_byte_count + - nonstatic_oop_count) != 0); - - - // Prepare list of oops for oop map generation. - int* nonstatic_oop_offsets; - unsigned int* nonstatic_oop_counts; - unsigned int nonstatic_oop_map_count = 0; - - nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD( - THREAD, int, nonstatic_oop_count + 1); - nonstatic_oop_counts = NEW_RESOURCE_ARRAY_IN_THREAD( - THREAD, unsigned int, nonstatic_oop_count + 1); - - first_nonstatic_oop_offset = 0; // will be set for first oop field - -#ifndef PRODUCT - if( PrintCompactFieldsSavings ) { - next_nonstatic_double_offset = next_nonstatic_field_offset + - (nonstatic_oop_count * heapOopSize); - if ( nonstatic_double_count > 0 ) { - next_nonstatic_double_offset = align_size_up(next_nonstatic_double_offset, BytesPerLong); - } - next_nonstatic_word_offset = next_nonstatic_double_offset + - (nonstatic_double_count * BytesPerLong); - next_nonstatic_short_offset = next_nonstatic_word_offset + - (nonstatic_word_count * BytesPerInt); - next_nonstatic_byte_offset = next_nonstatic_short_offset + - (nonstatic_short_count * BytesPerShort); - next_nonstatic_type_offset = align_size_up((next_nonstatic_byte_offset + - nonstatic_byte_count ), heapOopSize ); - orig_nonstatic_field_size = nonstatic_field_size + - ((next_nonstatic_type_offset - first_nonstatic_field_offset)/heapOopSize); - } -#endif - bool compact_fields = CompactFields; - int allocation_style = FieldsAllocationStyle; - if( allocation_style < 0 || allocation_style > 2 ) { // Out of range? - assert(false, "0 <= FieldsAllocationStyle <= 2"); - allocation_style = 1; // Optimistic - } - - // The next classes have predefined hard-coded fields offsets - // (see in JavaClasses::compute_hard_coded_offsets()). - // Use default fields allocation order for them. - if( (allocation_style != 0 || compact_fields ) && class_loader.is_null() && - (class_name == vmSymbols::java_lang_AssertionStatusDirectives() || - class_name == vmSymbols::java_lang_Class() || - class_name == vmSymbols::java_lang_ClassLoader() || - class_name == vmSymbols::java_lang_ref_Reference() || - class_name == vmSymbols::java_lang_ref_SoftReference() || - class_name == vmSymbols::java_lang_StackTraceElement() || - class_name == vmSymbols::java_lang_String() || - class_name == vmSymbols::java_lang_Throwable() || - class_name == vmSymbols::java_lang_Boolean() || - class_name == vmSymbols::java_lang_Character() || - class_name == vmSymbols::java_lang_Float() || - class_name == vmSymbols::java_lang_Double() || - class_name == vmSymbols::java_lang_Byte() || - class_name == vmSymbols::java_lang_Short() || - class_name == vmSymbols::java_lang_Integer() || - class_name == vmSymbols::java_lang_Long())) { - allocation_style = 0; // Allocate oops first - compact_fields = false; // Don't compact fields - } - - if( allocation_style == 0 ) { - // Fields order: oops, longs/doubles, ints, shorts/chars, bytes, padded fields - next_nonstatic_oop_offset = next_nonstatic_field_offset; - next_nonstatic_double_offset = next_nonstatic_oop_offset + - (nonstatic_oop_count * heapOopSize); - } else if( allocation_style == 1 ) { - // Fields order: longs/doubles, ints, shorts/chars, bytes, oops, padded fields - next_nonstatic_double_offset = next_nonstatic_field_offset; - } else if( allocation_style == 2 ) { - // Fields allocation: oops fields in super and sub classes are together. - if( nonstatic_field_size > 0 && super_klass() != NULL && - super_klass->nonstatic_oop_map_size() > 0 ) { - int map_count = super_klass->nonstatic_oop_map_count(); - OopMapBlock* first_map = super_klass->start_of_nonstatic_oop_maps(); - OopMapBlock* last_map = first_map + map_count - 1; - int next_offset = last_map->offset() + (last_map->count() * heapOopSize); - if (next_offset == next_nonstatic_field_offset) { - allocation_style = 0; // allocate oops first - next_nonstatic_oop_offset = next_nonstatic_field_offset; - next_nonstatic_double_offset = next_nonstatic_oop_offset + - (nonstatic_oop_count * heapOopSize); - } - } - if( allocation_style == 2 ) { - allocation_style = 1; // allocate oops last - next_nonstatic_double_offset = next_nonstatic_field_offset; - } - } else { - ShouldNotReachHere(); - } - - int nonstatic_oop_space_count = 0; - int nonstatic_word_space_count = 0; - int nonstatic_short_space_count = 0; - int nonstatic_byte_space_count = 0; - int nonstatic_oop_space_offset; - int nonstatic_word_space_offset; - int nonstatic_short_space_offset; - int nonstatic_byte_space_offset; - - if( nonstatic_double_count > 0 ) { - int offset = next_nonstatic_double_offset; - next_nonstatic_double_offset = align_size_up(offset, BytesPerLong); - if( compact_fields && offset != next_nonstatic_double_offset ) { - // Allocate available fields into the gap before double field. - int length = next_nonstatic_double_offset - offset; - assert(length == BytesPerInt, ""); - nonstatic_word_space_offset = offset; - if( nonstatic_word_count > 0 ) { - nonstatic_word_count -= 1; - nonstatic_word_space_count = 1; // Only one will fit - length -= BytesPerInt; - offset += BytesPerInt; - } - nonstatic_short_space_offset = offset; - while( length >= BytesPerShort && nonstatic_short_count > 0 ) { - nonstatic_short_count -= 1; - nonstatic_short_space_count += 1; - length -= BytesPerShort; - offset += BytesPerShort; - } - nonstatic_byte_space_offset = offset; - while( length > 0 && nonstatic_byte_count > 0 ) { - nonstatic_byte_count -= 1; - nonstatic_byte_space_count += 1; - length -= 1; - } - // Allocate oop field in the gap if there are no other fields for that. - nonstatic_oop_space_offset = offset; - if( length >= heapOopSize && nonstatic_oop_count > 0 && - allocation_style != 0 ) { // when oop fields not first - nonstatic_oop_count -= 1; - nonstatic_oop_space_count = 1; // Only one will fit - length -= heapOopSize; - offset += heapOopSize; - } - } - } - - next_nonstatic_word_offset = next_nonstatic_double_offset + - (nonstatic_double_count * BytesPerLong); - next_nonstatic_short_offset = next_nonstatic_word_offset + - (nonstatic_word_count * BytesPerInt); - next_nonstatic_byte_offset = next_nonstatic_short_offset + - (nonstatic_short_count * BytesPerShort); - next_nonstatic_padded_offset = next_nonstatic_byte_offset + - nonstatic_byte_count; - - // let oops jump before padding with this allocation style - if( allocation_style == 1 ) { - next_nonstatic_oop_offset = next_nonstatic_padded_offset; - if( nonstatic_oop_count > 0 ) { - next_nonstatic_oop_offset = align_size_up(next_nonstatic_oop_offset, heapOopSize); - } - next_nonstatic_padded_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize); - } - - // Iterate over fields again and compute correct offsets. - // The field allocation type was temporarily stored in the offset slot. - // oop fields are located before non-oop fields (static and non-static). - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - - // skip already laid out fields - if (fs.is_offset_set()) continue; - - // contended fields are handled below - if (fs.is_contended()) continue; - - int real_offset; - FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); - - // pack the rest of the fields - switch (atype) { - case STATIC_OOP: - real_offset = next_static_oop_offset; - next_static_oop_offset += heapOopSize; - break; - case STATIC_BYTE: - real_offset = next_static_byte_offset; - next_static_byte_offset += 1; - break; - case STATIC_SHORT: - real_offset = next_static_short_offset; - next_static_short_offset += BytesPerShort; - break; - case STATIC_WORD: - real_offset = next_static_word_offset; - next_static_word_offset += BytesPerInt; - break; - case STATIC_DOUBLE: - real_offset = next_static_double_offset; - next_static_double_offset += BytesPerLong; - break; - case NONSTATIC_OOP: - if( nonstatic_oop_space_count > 0 ) { - real_offset = nonstatic_oop_space_offset; - nonstatic_oop_space_offset += heapOopSize; - nonstatic_oop_space_count -= 1; - } else { - real_offset = next_nonstatic_oop_offset; - next_nonstatic_oop_offset += heapOopSize; - } - // Update oop maps - if( nonstatic_oop_map_count > 0 && - nonstatic_oop_offsets[nonstatic_oop_map_count - 1] == - real_offset - - int(nonstatic_oop_counts[nonstatic_oop_map_count - 1]) * - heapOopSize ) { - // Extend current oop map - nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1; - } else { - // Create new oop map - nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; - nonstatic_oop_counts [nonstatic_oop_map_count] = 1; - nonstatic_oop_map_count += 1; - if( first_nonstatic_oop_offset == 0 ) { // Undefined - first_nonstatic_oop_offset = real_offset; - } - } - break; - case NONSTATIC_BYTE: - if( nonstatic_byte_space_count > 0 ) { - real_offset = nonstatic_byte_space_offset; - nonstatic_byte_space_offset += 1; - nonstatic_byte_space_count -= 1; - } else { - real_offset = next_nonstatic_byte_offset; - next_nonstatic_byte_offset += 1; - } - break; - case NONSTATIC_SHORT: - if( nonstatic_short_space_count > 0 ) { - real_offset = nonstatic_short_space_offset; - nonstatic_short_space_offset += BytesPerShort; - nonstatic_short_space_count -= 1; - } else { - real_offset = next_nonstatic_short_offset; - next_nonstatic_short_offset += BytesPerShort; - } - break; - case NONSTATIC_WORD: - if( nonstatic_word_space_count > 0 ) { - real_offset = nonstatic_word_space_offset; - nonstatic_word_space_offset += BytesPerInt; - nonstatic_word_space_count -= 1; - } else { - real_offset = next_nonstatic_word_offset; - next_nonstatic_word_offset += BytesPerInt; - } - break; - case NONSTATIC_DOUBLE: - real_offset = next_nonstatic_double_offset; - next_nonstatic_double_offset += BytesPerLong; - break; - default: - ShouldNotReachHere(); - } - fs.set_offset(real_offset); - } - - - // Handle the contended cases. - // - // Each contended field should not intersect the cache line with another contended field. - // In the absence of alignment information, we end up with pessimistically separating - // the fields with full-width padding. - // - // Additionally, this should not break alignment for the fields, so we round the alignment up - // for each field. - if (contended_count > 0) { - - // if there is at least one contended field, we need to have pre-padding for them - if (nonstatic_contended_count > 0) { - next_nonstatic_padded_offset += pad_size; - } - - // collect all contended groups - BitMap bm(cp->size()); - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - // skip already laid out fields - if (fs.is_offset_set()) continue; - - if (fs.is_contended()) { - bm.set_bit(fs.contended_group()); - } - } - - int current_group = -1; - while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) { - - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - - // skip already laid out fields - if (fs.is_offset_set()) continue; - - // skip non-contended fields and fields from different group - if (!fs.is_contended() || (fs.contended_group() != current_group)) continue; - - // handle statics below - if (fs.access_flags().is_static()) continue; - - int real_offset; - FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); - - switch (atype) { - case NONSTATIC_BYTE: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, 1); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += 1; - break; - - case NONSTATIC_SHORT: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerShort); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += BytesPerShort; - break; - - case NONSTATIC_WORD: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerInt); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += BytesPerInt; - break; - - case NONSTATIC_DOUBLE: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerLong); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += BytesPerLong; - break; - - case NONSTATIC_OOP: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, heapOopSize); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += heapOopSize; - - // Create new oop map - nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; - nonstatic_oop_counts [nonstatic_oop_map_count] = 1; - nonstatic_oop_map_count += 1; - if( first_nonstatic_oop_offset == 0 ) { // Undefined - first_nonstatic_oop_offset = real_offset; - } - break; - - default: - ShouldNotReachHere(); - } - - if (fs.contended_group() == 0) { - // Contended group defines the equivalence class over the fields: - // the fields within the same contended group are not inter-padded. - // The only exception is default group, which does not incur the - // equivalence, and so requires intra-padding. - next_nonstatic_padded_offset += pad_size; - } - - fs.set_offset(real_offset); - } // for - - // Start laying out the next group. - // Note that this will effectively pad the last group in the back; - // this is expected to alleviate memory contention effects for - // subclass fields and/or adjacent object. - // If this was the default group, the padding is already in place. - if (current_group != 0) { - next_nonstatic_padded_offset += pad_size; - } - } - - // handle static fields - - // if there is at least one contended field, we need to have pre-padding for them - if (static_contended_count > 0) { - next_static_padded_offset += pad_size; - } - - current_group = -1; - while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) { - - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - - // skip already laid out fields - if (fs.is_offset_set()) continue; - - // skip non-contended fields and fields from different group - if (!fs.is_contended() || (fs.contended_group() != current_group)) continue; - - // non-statics already handled above - if (!fs.access_flags().is_static()) continue; - - int real_offset; - FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); - - switch (atype) { - - case STATIC_BYTE: - next_static_padded_offset = align_size_up(next_static_padded_offset, 1); - real_offset = next_static_padded_offset; - next_static_padded_offset += 1; - break; - - case STATIC_SHORT: - next_static_padded_offset = align_size_up(next_static_padded_offset, BytesPerShort); - real_offset = next_static_padded_offset; - next_static_padded_offset += BytesPerShort; - break; - - case STATIC_WORD: - next_static_padded_offset = align_size_up(next_static_padded_offset, BytesPerInt); - real_offset = next_static_padded_offset; - next_static_padded_offset += BytesPerInt; - break; - - case STATIC_DOUBLE: - next_static_padded_offset = align_size_up(next_static_padded_offset, BytesPerLong); - real_offset = next_static_padded_offset; - next_static_padded_offset += BytesPerLong; - break; - - case STATIC_OOP: - next_static_padded_offset = align_size_up(next_static_padded_offset, heapOopSize); - real_offset = next_static_padded_offset; - next_static_padded_offset += heapOopSize; - break; - - default: - ShouldNotReachHere(); - } - - if (fs.contended_group() == 0) { - // Contended group defines the equivalence class over the fields: - // the fields within the same contended group are not inter-padded. - // The only exception is default group, which does not incur the - // equivalence, and so requires intra-padding. - next_static_padded_offset += pad_size; - } - - fs.set_offset(real_offset); - } // for - - // Start laying out the next group. - // Note that this will effectively pad the last group in the back; - // this is expected to alleviate memory contention effects for - // subclass fields and/or adjacent object. - // If this was the default group, the padding is already in place. - if (current_group != 0) { - next_static_padded_offset += pad_size; - } - - } - - } // handle contended - - // Size of instances - int instance_size; - - int notaligned_offset = next_nonstatic_padded_offset; - - // Entire class is contended, pad in the back. - // This helps to alleviate memory contention effects for subclass fields - // and/or adjacent object. - if (parsed_annotations.is_contended()) { - notaligned_offset += pad_size; - next_static_padded_offset += pad_size; - } - - int next_static_type_offset = align_size_up(next_static_padded_offset, wordSize); - int static_field_size = (next_static_type_offset - - InstanceMirrorKlass::offset_of_static_fields()) / wordSize; - - next_nonstatic_type_offset = align_size_up(notaligned_offset, heapOopSize ); - nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset - - first_nonstatic_field_offset)/heapOopSize); - - next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize ); - instance_size = align_object_size(next_nonstatic_type_offset / wordSize); - - assert(instance_size == align_object_size(align_size_up( - (instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize + ((parsed_annotations.is_contended()) ? pad_size : 0)), - wordSize) / wordSize), "consistent layout helper value"); - - // Number of non-static oop map blocks allocated at end of klass. - const unsigned int total_oop_map_count = - compute_oop_map_count(super_klass, nonstatic_oop_map_count, - first_nonstatic_oop_offset); // Compute reference type ReferenceType rt; if (super_klass() == NULL) { @@ -4066,53 +3958,42 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, } // We can now create the basic Klass* for this klass - int total_oop_map_size2 = - InstanceKlass::nonstatic_oop_map_size(total_oop_map_count); + _klass = InstanceKlass::allocate_instance_klass(loader_data, + vtable_size, + itable_size, + info.static_field_size, + total_oop_map_size2, + rt, + access_flags, + name, + super_klass(), + !host_klass.is_null(), + CHECK_(nullHandle)); + instanceKlassHandle this_klass (THREAD, _klass); - Klass* ik = InstanceKlass::allocate_instance_klass(loader_data, - vtable_size, - itable_size, - static_field_size, - total_oop_map_size2, - rt, - access_flags, - name, - super_klass(), - !host_klass.is_null(), - CHECK_(nullHandle)); - - // Add all classes to our internal class loader list here, - // including classes in the bootstrap (NULL) class loader. - loader_data->add_class(ik); - - instanceKlassHandle this_klass (THREAD, ik); - - assert(this_klass->static_field_size() == static_field_size, "sanity"); - assert(this_klass->nonstatic_oop_map_count() == total_oop_map_count, + assert(this_klass->static_field_size() == info.static_field_size, "sanity"); + assert(this_klass->nonstatic_oop_map_count() == info.total_oop_map_count, "sanity"); // Fill in information already parsed this_klass->set_should_verify_class(verify); - jint lh = Klass::instance_layout_helper(instance_size, false); + jint lh = Klass::instance_layout_helper(info.instance_size, false); this_klass->set_layout_helper(lh); assert(this_klass->oop_is_instance(), "layout is correct"); - assert(this_klass->size_helper() == instance_size, "correct size_helper"); + assert(this_klass->size_helper() == info.instance_size, "correct size_helper"); // Not yet: supers are done below to support the new subtype-checking fields //this_klass->set_super(super_klass()); this_klass->set_class_loader_data(loader_data); - this_klass->set_nonstatic_field_size(nonstatic_field_size); - this_klass->set_has_nonstatic_fields(has_nonstatic_fields); + this_klass->set_nonstatic_field_size(info.nonstatic_field_size); + this_klass->set_has_nonstatic_fields(info.has_nonstatic_fields); this_klass->set_static_oop_field_count(fac.count[STATIC_OOP]); - cp->set_pool_holder(this_klass()); - error_handler.set_in_error(false); // turn off error handler for cp - this_klass->set_constants(cp()); - this_klass->set_local_interfaces(local_interfaces); - this_klass->set_fields(fields, java_fields_count); - this_klass->set_methods(methods); + + apply_parsed_class_metadata(this_klass, java_fields_count, CHECK_NULL); + if (has_final_method) { this_klass->set_has_final_method(); } - this_klass->set_method_ordering(method_ordering); + this_klass->copy_method_ordering(method_ordering, CHECK_NULL); // The InstanceKlass::_methods_jmethod_ids cache and the // InstanceKlass::_methods_cached_itable_indices cache are // both managed on the assumption that the initial cache @@ -4124,17 +4005,6 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, if (is_anonymous()) // I am well known to myself cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve - // Assign allocations if needed - if (_annotations != NULL || _type_annotations != NULL || - fields_annotations != NULL || fields_type_annotations != NULL) { - Annotations* annotations = Annotations::allocate(loader_data, CHECK_NULL); - annotations->set_class_annotations(_annotations); - annotations->set_class_type_annotations(_type_annotations); - annotations->set_fields_annotations(fields_annotations); - annotations->set_fields_type_annotations(fields_type_annotations); - this_klass->set_annotations(annotations); - } - this_klass->set_minor_version(minor_version); this_klass->set_major_version(major_version); this_klass->set_has_default_methods(has_default_methods); @@ -4169,8 +4039,6 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, this_klass->set_has_miranda_methods(); // then set a flag } - this_klass->set_transitive_interfaces(transitive_interfaces); - // Fill in information needed to compute superclasses. this_klass->initialize_supers(super_klass(), CHECK_(nullHandle)); @@ -4179,7 +4047,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, // Compute transitive closure of interfaces this class implements // Do final class setup - fill_oop_maps(this_klass, nonstatic_oop_map_count, nonstatic_oop_offsets, nonstatic_oop_counts); + fill_oop_maps(this_klass, info.nonstatic_oop_map_count, info.nonstatic_oop_offsets, info.nonstatic_oop_counts); // Fill in has_finalizer, has_vanilla_constructor, and layout_helper set_precomputed_flags(this_klass); @@ -4278,35 +4146,6 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, } } -#ifndef PRODUCT - if( PrintCompactFieldsSavings ) { - ResourceMark rm; - if( nonstatic_field_size < orig_nonstatic_field_size ) { - tty->print("[Saved %d of %d bytes in %s]\n", - (orig_nonstatic_field_size - nonstatic_field_size)*heapOopSize, - orig_nonstatic_field_size*heapOopSize, - this_klass->external_name()); - } else if( nonstatic_field_size > orig_nonstatic_field_size ) { - tty->print("[Wasted %d over %d bytes in %s]\n", - (nonstatic_field_size - orig_nonstatic_field_size)*heapOopSize, - orig_nonstatic_field_size*heapOopSize, - this_klass->external_name()); - } - } -#endif - -#ifndef PRODUCT - if (PrintFieldLayout) { - print_field_layout(name, - fields, - cp, - instance_size, - first_nonstatic_field_offset, - next_nonstatic_field_offset, - next_static_type_offset); - } -#endif - // preserve result across HandleMark preserve_this_klass = this_klass(); } @@ -4316,9 +4155,40 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, instanceKlassHandle this_klass (THREAD, preserve_this_klass); debug_only(this_klass->verify();) + // Clear class if no error has occurred so destructor doesn't deallocate it + _klass = NULL; return this_klass; } +// Destructor to clean up if there's an error +ClassFileParser::~ClassFileParser() { + MetadataFactory::free_metadata(_loader_data, _cp); + MetadataFactory::free_array(_loader_data, _fields); + + // Free methods + InstanceKlass::deallocate_methods(_loader_data, _methods); + + // beware of the Universe::empty_blah_array!! + if (_inner_classes != Universe::the_empty_short_array()) { + MetadataFactory::free_array(_loader_data, _inner_classes); + } + + // Free interfaces + InstanceKlass::deallocate_interfaces(_loader_data, _super_klass(), + _local_interfaces, _transitive_interfaces); + + MetadataFactory::free_array(_loader_data, _annotations); + MetadataFactory::free_array(_loader_data, _type_annotations); + Annotations::free_contents(_loader_data, _fields_annotations); + Annotations::free_contents(_loader_data, _fields_type_annotations); + + clear_class_metadata(); + + // deallocate the klass if already created. + MetadataFactory::free_metadata(_loader_data, _klass); + _klass = NULL; +} + void ClassFileParser::print_field_layout(Symbol* name, Array* fields, constantPoolHandle cp, @@ -4510,7 +4380,7 @@ void ClassFileParser::record_defined_class_dependencies(instanceKlassHandle defi } } -// utility method for appending and array with check for duplicates +// utility methods for appending an array with check for duplicates void append_interfaces(GrowableArray* result, Array* ifs) { // iterate over new interfaces @@ -4522,8 +4392,9 @@ void append_interfaces(GrowableArray* result, Array* ifs) { } } - -Array* ClassFileParser::compute_transitive_interfaces(ClassLoaderData* loader_data, instanceKlassHandle super, Array* local_ifs, TRAPS) { +Array* ClassFileParser::compute_transitive_interfaces( + instanceKlassHandle super, + Array* local_ifs, TRAPS) { // Compute maximum size for transitive interfaces int max_transitive_size = 0; int super_size = 0; @@ -4570,7 +4441,7 @@ Array* ClassFileParser::compute_transitive_interfaces(ClassLoaderData* l // length will be less than the max_transitive_size if duplicates were removed int length = result->length(); assert(length <= max_transitive_size, "just checking"); - Array* new_result = MetadataFactory::new_array(loader_data, length, CHECK_NULL); + Array* new_result = MetadataFactory::new_array(_loader_data, length, CHECK_NULL); for (int i = 0; i < length; i++) { Klass* e = result->at(i); assert(e != NULL, "just checking"); @@ -4580,7 +4451,6 @@ Array* ClassFileParser::compute_transitive_interfaces(ClassLoaderData* l } } - void ClassFileParser::check_super_class_access(instanceKlassHandle this_klass, TRAPS) { Klass* super = this_klass->super(); if ((super != NULL) && diff --git a/hotspot/src/share/vm/classfile/classFileParser.hpp b/hotspot/src/share/vm/classfile/classFileParser.hpp index 7cedcefb3a4..0fd8830463d 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.hpp +++ b/hotspot/src/share/vm/classfile/classFileParser.hpp @@ -34,6 +34,7 @@ #include "classfile/symbolTable.hpp" class FieldAllocationCount; +class FieldLayoutInfo; // Parser for for .class files @@ -47,6 +48,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { u2 _major_version; u2 _minor_version; Symbol* _class_name; + ClassLoaderData* _loader_data; KlassHandle _host_klass; GrowableArray* _cp_patches; // overrides for CP entries @@ -58,33 +60,59 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { // class attributes parsed before the instance klass is created: bool _synthetic_flag; + int _sde_length; + char* _sde_buffer; Symbol* _sourcefile; Symbol* _generic_signature; - char* _sde_buffer; - int _sde_length; - Array* _inner_classes; + + // Metadata created before the instance klass is created. Must be deallocated + // if not transferred to the InstanceKlass upon successful class loading + // in which case these pointers have been set to NULL. + instanceKlassHandle _super_klass; + ConstantPool* _cp; + Array* _fields; + Array* _methods; + Array* _inner_classes; + Array* _local_interfaces; + Array* _transitive_interfaces; AnnotationArray* _annotations; AnnotationArray* _type_annotations; + Array* _fields_annotations; + Array* _fields_type_annotations; + InstanceKlass* _klass; // InstanceKlass once created. void set_class_synthetic_flag(bool x) { _synthetic_flag = x; } void set_class_sourcefile(Symbol* x) { _sourcefile = x; } void set_class_generic_signature(Symbol* x) { _generic_signature = x; } void set_class_sde_buffer(char* x, int len) { _sde_buffer = x; _sde_length = len; } - void set_class_inner_classes(Array* x) { _inner_classes = x; } - void set_class_annotations(AnnotationArray* x) { _annotations = x; } - void set_class_type_annotations(AnnotationArray* x) { _type_annotations = x; } - void init_parsed_class_attributes() { + + void init_parsed_class_attributes(ClassLoaderData* loader_data) { + _loader_data = loader_data; _synthetic_flag = false; _sourcefile = NULL; _generic_signature = NULL; _sde_buffer = NULL; _sde_length = 0; - _annotations = _type_annotations = NULL; // initialize the other flags too: _has_finalizer = _has_empty_finalizer = _has_vanilla_constructor = false; _max_bootstrap_specifier_index = -1; + clear_class_metadata(); + _klass = NULL; } void apply_parsed_class_attributes(instanceKlassHandle k); // update k + void apply_parsed_class_metadata(instanceKlassHandle k, int fields_count, TRAPS); + void clear_class_metadata() { + // metadata created before the instance klass is created. Must be + // deallocated if classfile parsing returns an error. + _cp = NULL; + _fields = NULL; + _methods = NULL; + _inner_classes = NULL; + _local_interfaces = NULL; + _transitive_interfaces = NULL; + _annotations = _type_annotations = NULL; + _fields_annotations = _fields_type_annotations = NULL; + } class AnnotationCollector { public: @@ -124,11 +152,27 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { void set_contended(bool contended) { set_annotation(_sun_misc_Contended); } bool is_contended() { return has_annotation(_sun_misc_Contended); } }; + + // This class also doubles as a holder for metadata cleanup. class FieldAnnotationCollector: public AnnotationCollector { + ClassLoaderData* _loader_data; + AnnotationArray* _field_annotations; + AnnotationArray* _field_type_annotations; public: - FieldAnnotationCollector() : AnnotationCollector(_in_field) { } + FieldAnnotationCollector(ClassLoaderData* loader_data) : + AnnotationCollector(_in_field), + _loader_data(loader_data), + _field_annotations(NULL), + _field_type_annotations(NULL) {} void apply_to(FieldInfo* f); + ~FieldAnnotationCollector(); + AnnotationArray* field_annotations() { return _field_annotations; } + AnnotationArray* field_type_annotations() { return _field_type_annotations; } + + void set_field_annotations(AnnotationArray* a) { _field_annotations = a; } + void set_field_type_annotations(AnnotationArray* a) { _field_type_annotations = a; } }; + class MethodAnnotationCollector: public AnnotationCollector { public: MethodAnnotationCollector() : AnnotationCollector(_in_method) { } @@ -152,38 +196,30 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { void set_stream(ClassFileStream* st) { _stream = st; } // Constant pool parsing - void parse_constant_pool_entries(ClassLoaderData* loader_data, - constantPoolHandle cp, int length, TRAPS); + void parse_constant_pool_entries(int length, TRAPS); - constantPoolHandle parse_constant_pool(ClassLoaderData* loader_data, TRAPS); + constantPoolHandle parse_constant_pool(TRAPS); // Interface parsing - Array* parse_interfaces(constantPoolHandle cp, - int length, - ClassLoaderData* loader_data, + Array* parse_interfaces(int length, Handle protection_domain, Symbol* class_name, bool* has_default_methods, TRAPS); void record_defined_class_dependencies(instanceKlassHandle defined_klass, TRAPS); + instanceKlassHandle parse_super_class(int super_class_index, TRAPS); // Field parsing - void parse_field_attributes(ClassLoaderData* loader_data, - constantPoolHandle cp, u2 attributes_count, + void parse_field_attributes(u2 attributes_count, bool is_static, u2 signature_index, u2* constantvalue_index_addr, bool* is_synthetic_addr, u2* generic_signature_index_addr, - AnnotationArray** field_annotations, - AnnotationArray** field_type_annotations, FieldAnnotationCollector* parsed_annotations, TRAPS); - Array* parse_fields(ClassLoaderData* loader_data, - Symbol* class_name, - constantPoolHandle cp, bool is_interface, + Array* parse_fields(Symbol* class_name, + bool is_interface, FieldAllocationCount *fac, - Array** fields_annotations, - Array** fields_type_annotations, u2* java_fields_count_ptr, TRAPS); void print_field_layout(Symbol* name, @@ -195,65 +231,52 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { int static_fields_end); // Method parsing - methodHandle parse_method(ClassLoaderData* loader_data, - constantPoolHandle cp, - bool is_interface, + methodHandle parse_method(bool is_interface, AccessFlags* promoted_flags, TRAPS); - Array* parse_methods(ClassLoaderData* loader_data, - constantPoolHandle cp, - bool is_interface, + Array* parse_methods(bool is_interface, AccessFlags* promoted_flags, bool* has_final_method, bool* has_default_method, TRAPS); - Array* sort_methods(ClassLoaderData* loader_data, - Array* methods, - TRAPS); - u2* parse_exception_table(ClassLoaderData* loader_data, - u4 code_length, u4 exception_table_length, - constantPoolHandle cp, TRAPS); + intArray* sort_methods(Array* methods); + + u2* parse_exception_table(u4 code_length, u4 exception_table_length, + TRAPS); void parse_linenumber_table( u4 code_attribute_length, u4 code_length, CompressedLineNumberWriteStream** write_stream, TRAPS); u2* parse_localvariable_table(u4 code_length, u2 max_locals, u4 code_attribute_length, - constantPoolHandle cp, u2* localvariable_table_length, + u2* localvariable_table_length, bool isLVTT, TRAPS); u2* parse_checked_exceptions(u2* checked_exceptions_length, u4 method_attribute_length, - constantPoolHandle cp, TRAPS); + TRAPS); void parse_type_array(u2 array_length, u4 code_length, u4* u1_index, u4* u2_index, - u1* u1_array, u2* u2_array, constantPoolHandle cp, TRAPS); - Array* parse_stackmap_table(ClassLoaderData* loader_data, u4 code_attribute_length, TRAPS); + u1* u1_array, u2* u2_array, TRAPS); + u1* parse_stackmap_table(u4 code_attribute_length, TRAPS); // Classfile attribute parsing - void parse_classfile_sourcefile_attribute(constantPoolHandle cp, TRAPS); - void parse_classfile_source_debug_extension_attribute(constantPoolHandle cp, - int length, TRAPS); - u2 parse_classfile_inner_classes_attribute(ClassLoaderData* loader_data, - u1* inner_classes_attribute_start, + void parse_classfile_sourcefile_attribute(TRAPS); + void parse_classfile_source_debug_extension_attribute(int length, TRAPS); + u2 parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start, bool parsed_enclosingmethod_attribute, u2 enclosing_method_class_index, u2 enclosing_method_method_index, - constantPoolHandle cp, TRAPS); - void parse_classfile_attributes(ClassLoaderData* loader_data, - constantPoolHandle cp, - ClassAnnotationCollector* parsed_annotations, + void parse_classfile_attributes(ClassAnnotationCollector* parsed_annotations, TRAPS); - void parse_classfile_synthetic_attribute(constantPoolHandle cp, TRAPS); - void parse_classfile_signature_attribute(constantPoolHandle cp, TRAPS); - void parse_classfile_bootstrap_methods_attribute(ClassLoaderData* loader_data, constantPoolHandle cp, u4 attribute_length, TRAPS); + void parse_classfile_synthetic_attribute(TRAPS); + void parse_classfile_signature_attribute(TRAPS); + void parse_classfile_bootstrap_methods_attribute(u4 attribute_length, TRAPS); // Annotations handling - AnnotationArray* assemble_annotations(ClassLoaderData* loader_data, - u1* runtime_visible_annotations, + AnnotationArray* assemble_annotations(u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, int runtime_invisible_annotations_length, TRAPS); int skip_annotation(u1* buffer, int limit, int index); int skip_annotation_value(u1* buffer, int limit, int index); - void parse_annotations(ClassLoaderData* loader_data, - u1* buffer, int limit, constantPoolHandle cp, + void parse_annotations(u1* buffer, int limit, /* Results (currently, only one result is supported): */ AnnotationCollector* result, TRAPS); @@ -267,8 +290,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { int* nonstatic_oop_offsets, unsigned int* nonstatic_oop_counts); void set_precomputed_flags(instanceKlassHandle k); - Array* compute_transitive_interfaces(ClassLoaderData* loader_data, - instanceKlassHandle super, + Array* compute_transitive_interfaces(instanceKlassHandle super, Array* local_ifs, TRAPS); // Format checker methods @@ -318,7 +340,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { bool is_supported_version(u2 major, u2 minor); bool has_illegal_visibility(jint flags); - void verify_constantvalue(int constantvalue_index, int signature_index, constantPoolHandle cp, TRAPS); + void verify_constantvalue(int constantvalue_index, int signature_index, TRAPS); void verify_legal_utf8(const unsigned char* buffer, int length, TRAPS); void verify_legal_class_name(Symbol* name, TRAPS); void verify_legal_field_name(Symbol* name, TRAPS); @@ -359,10 +381,17 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { // In older versions of the VM, Klass*s cannot sneak into early phases of // constant pool construction, but in later versions they can. // %%% Let's phase out the old is_klass_reference. - bool is_klass_reference(constantPoolHandle cp, int index) { - return (EnableInvokeDynamic - ? cp->tag_at(index).is_klass_or_reference() - : cp->tag_at(index).is_klass_reference()); + bool valid_klass_reference_at(int index) { + return _cp->is_within_bounds(index) && + (EnableInvokeDynamic + ? _cp->tag_at(index).is_klass_or_reference() + : _cp->tag_at(index).is_klass_reference()); + } + + // Checks that the cpool index is in range and is a utf8 + bool valid_symbol_at(int cpool_index) { + return (_cp->is_within_bounds(cpool_index) && + _cp->tag_at(cpool_index).is_utf8()); } void copy_localvariable_table(ConstMethod* cm, int lvt_cnt, @@ -373,8 +402,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { u2** localvariable_type_table_start, TRAPS); - void copy_method_annotations(ClassLoaderData* loader_data, - ConstMethod* cm, + void copy_method_annotations(ConstMethod* cm, u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, @@ -391,9 +419,15 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { int annotation_default_length, TRAPS); + // lays out fields in class and returns the total oopmap count + void layout_fields(Handle class_loader, FieldAllocationCount* fac, + ClassAnnotationCollector* parsed_annotations, + FieldLayoutInfo* info, TRAPS); + public: // Constructor ClassFileParser(ClassFileStream* st) { set_stream(st); } + ~ClassFileParser(); // Parse .class file and return new Klass*. The Klass* is not hooked up // to the system dictionary or any other structures, so a .class file can diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index e74a88d7d33..f74f8f1ce13 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -105,6 +105,7 @@ void ClassLoaderData::oops_do(OopClosure* f, KlassClosure* klass_closure, bool m void ClassLoaderData::classes_do(KlassClosure* klass_closure) { for (Klass* k = _klasses; k != NULL; k = k->next_link()) { klass_closure->do_klass(k); + assert(k != k->next_link(), "no loops!"); } } @@ -113,6 +114,7 @@ void ClassLoaderData::classes_do(void f(InstanceKlass*)) { if (k->oop_is_instance()) { f(InstanceKlass::cast(k)); } + assert(k != k->next_link(), "no loops!"); } } @@ -258,6 +260,7 @@ void ClassLoaderData::remove_class(Klass* scratch_class) { return; } prev = k; + assert(k != k->next_link(), "no loops!"); } ShouldNotReachHere(); // should have found this class!! } @@ -439,6 +442,7 @@ void ClassLoaderData::dump(outputStream * const out) { while (k != NULL) { out->print_cr("klass "PTR_FORMAT", %s, CT: %d, MUT: %d", k, k->name()->as_C_string(), k->has_modified_oops(), k->has_accumulated_modified_oops()); + assert(k != k->next_link(), "no loops!"); k = k->next_link(); } } @@ -465,6 +469,7 @@ void ClassLoaderData::verify() { for (Klass* k = _klasses; k != NULL; k = k->next_link()) { guarantee(k->class_loader_data() == this, "Must be the same"); k->verify(); + assert(k != k->next_link(), "no loops!"); } } diff --git a/hotspot/src/share/vm/classfile/defaultMethods.cpp b/hotspot/src/share/vm/classfile/defaultMethods.cpp index 4e43d7fd323..1977b07ea10 100644 --- a/hotspot/src/share/vm/classfile/defaultMethods.cpp +++ b/hotspot/src/share/vm/classfile/defaultMethods.cpp @@ -348,7 +348,7 @@ class MethodFamily : public ResourceObj { void disqualify_method(Method* method) { int* index = _member_index.get(method); - assert(index != NULL && *index >= 0 && *index < _members.length(), "bad index"); + guarantee(index != NULL && *index >= 0 && *index < _members.length(), "bad index"); _members.at(*index).second = DISQUALIFIED; } diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp index 87de232d7a5..fc19dd55564 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.cpp +++ b/hotspot/src/share/vm/classfile/symbolTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,18 +49,17 @@ Symbol* SymbolTable::allocate_symbol(const u1* name, int len, bool c_heap, TRAPS Symbol* sym; - if (c_heap) { + if (DumpSharedSpaces) { + // Allocate all symbols to CLD shared metaspace + sym = new (len, ClassLoaderData::the_null_class_loader_data(), THREAD) Symbol(name, len, -1); + } else if (c_heap) { // refcount starts as 1 - assert(!DumpSharedSpaces, "never allocate to C heap"); sym = new (len, THREAD) Symbol(name, len, 1); assert(sym != NULL, "new should call vm_exit_out_of_memory if C_HEAP is exhausted"); } else { - if (DumpSharedSpaces) { - sym = new (len, ClassLoaderData::the_null_class_loader_data(), THREAD) Symbol(name, len, -1); - } else { + // Allocate to global arena sym = new (len, arena(), THREAD) Symbol(name, len, -1); } - } return sym; } diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index 002d781f928..edd3107062b 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -804,6 +804,32 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla } } // load_instance_class loop + if (HAS_PENDING_EXCEPTION) { + // An exception, such as OOM could have happened at various places inside + // load_instance_class. We might have partially initialized a shared class + // and need to clean it up. + if (class_loader.is_null()) { + // In some cases k may be null. Let's find the shared class again. + instanceKlassHandle ik(THREAD, find_shared_class(name)); + if (ik.not_null()) { + if (ik->class_loader_data() == NULL) { + // We didn't go as far as Klass::restore_unshareable_info(), + // so nothing to clean up. + } else { + MutexLocker mu(SystemDictionary_lock, THREAD); + Klass* kk = find_class(name, ik->class_loader_data()); + if (kk != NULL) { + // No clean up is needed if the shared class has been entered + // into system dictionary, as load_shared_class() won't be called + // again. + } else { + clean_up_shared_class(ik, class_loader, THREAD); + } + } + } + } + } + if (load_instance_added == true) { // clean up placeholder entries for LOAD_INSTANCE success or error // This brackets the SystemDictionary updates for both defining @@ -1140,11 +1166,6 @@ instanceKlassHandle SystemDictionary::load_shared_class( return load_shared_class(ik, class_loader, THREAD); } -// Note well! Changes to this method may affect oop access order -// in the shared archive. Please take care to not make changes that -// adversely affect cold start time by changing the oop access order -// that is specified in dump.cpp MarkAndMoveOrderedReadOnly and -// MarkAndMoveOrderedReadWrite closures. instanceKlassHandle SystemDictionary::load_shared_class( instanceKlassHandle ik, Handle class_loader, TRAPS) { assert(class_loader.is_null(), "non-null classloader for shared class?"); @@ -1205,6 +1226,19 @@ instanceKlassHandle SystemDictionary::load_shared_class( return ik; } +void SystemDictionary::clean_up_shared_class(instanceKlassHandle ik, Handle class_loader, TRAPS) { + // Updating methods must be done under a lock so multiple + // threads don't update these in parallel + // Shared classes are all currently loaded by the bootstrap + // classloader, so this will never cause a deadlock on + // a custom class loader lock. + { + Handle lockObject = compute_loader_lock_object(class_loader, THREAD); + check_loader_lock_contention(lockObject, THREAD); + ObjectLocker ol(lockObject, THREAD, true); + ik->remove_unshareable_info(); + } +} instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) { instanceKlassHandle nh = instanceKlassHandle(); // null Handle diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index d415c9b1e4f..d282fedfb4d 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp @@ -621,6 +621,7 @@ private: Handle class_loader, TRAPS); static instanceKlassHandle load_shared_class(instanceKlassHandle ik, Handle class_loader, TRAPS); + static void clean_up_shared_class(instanceKlassHandle ik, Handle class_loader, TRAPS); static instanceKlassHandle load_instance_class(Symbol* class_name, Handle class_loader, TRAPS); static Handle compute_loader_lock_object(Handle class_loader, TRAPS); static void check_loader_lock_contention(Handle loader_lock, TRAPS); diff --git a/hotspot/src/share/vm/code/codeBlob.cpp b/hotspot/src/share/vm/code/codeBlob.cpp index 779235f25fe..6120d3535ae 100644 --- a/hotspot/src/share/vm/code/codeBlob.cpp +++ b/hotspot/src/share/vm/code/codeBlob.cpp @@ -186,7 +186,7 @@ void CodeBlob::flush() { FREE_C_HEAP_ARRAY(unsigned char, _oop_maps, mtCode); _oop_maps = NULL; } - _comments.free(); + _strings.free(); } diff --git a/hotspot/src/share/vm/code/codeBlob.hpp b/hotspot/src/share/vm/code/codeBlob.hpp index 1d47bd9729c..e59ae7f1f89 100644 --- a/hotspot/src/share/vm/code/codeBlob.hpp +++ b/hotspot/src/share/vm/code/codeBlob.hpp @@ -66,7 +66,7 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC { int _data_offset; // offset to where data region begins int _frame_size; // size of stack frame OopMapSet* _oop_maps; // OopMap for this CodeBlob - CodeComments _comments; + CodeStrings _strings; public: // Returns the space needed for CodeBlob @@ -186,12 +186,12 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC { // Print the comment associated with offset on stream, if there is one virtual void print_block_comment(outputStream* stream, address block_begin) const { intptr_t offset = (intptr_t)(block_begin - code_begin()); - _comments.print_block_comment(stream, offset); + _strings.print_block_comment(stream, offset); } // Transfer ownership of comments to this CodeBlob - void set_comments(CodeComments& comments) { - _comments.assign(comments); + void set_strings(CodeStrings& strings) { + _strings.assign(strings); } }; diff --git a/hotspot/src/share/vm/code/compiledIC.cpp b/hotspot/src/share/vm/code/compiledIC.cpp index 7677dae57c5..85eeda47056 100644 --- a/hotspot/src/share/vm/code/compiledIC.cpp +++ b/hotspot/src/share/vm/code/compiledIC.cpp @@ -552,7 +552,7 @@ bool CompiledStaticCall::is_call_to_interpreted() const { void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) { address stub=find_stub(); - assert(stub!=NULL, "stub not found"); + guarantee(stub != NULL, "stub not found"); if (TraceICs) { ResourceMark rm; diff --git a/hotspot/src/share/vm/code/compressedStream.cpp b/hotspot/src/share/vm/code/compressedStream.cpp index 1d5cb341372..82b05fc03f9 100644 --- a/hotspot/src/share/vm/code/compressedStream.cpp +++ b/hotspot/src/share/vm/code/compressedStream.cpp @@ -195,7 +195,7 @@ void CompressedWriteStream::write_int_mb(jint value) { // for this block (a matching directive turns it back on later). // These directives can be removed once the MS VS.NET 2005 // compiler stack overflow is fixed. -#if _MSC_VER >=1400 && !defined(_WIN64) +#if defined(_MSC_VER) && _MSC_VER >=1400 && !defined(_WIN64) #pragma optimize("", off) #pragma warning(disable: 4748) #endif @@ -276,7 +276,7 @@ void test_compressed_stream(int trace) { guarantee(fails == 0, "test failures"); } -#if _MSC_VER >=1400 && !defined(_WIN64) +#if defined(_MSC_VER) &&_MSC_VER >=1400 && !defined(_WIN64) #pragma warning(default: 4748) #pragma optimize("", on) #endif diff --git a/hotspot/src/share/vm/code/icBuffer.hpp b/hotspot/src/share/vm/code/icBuffer.hpp index 36d0c761666..47db2d6b269 100644 --- a/hotspot/src/share/vm/code/icBuffer.hpp +++ b/hotspot/src/share/vm/code/icBuffer.hpp @@ -50,7 +50,7 @@ class ICStub: public Stub { friend class ICStubInterface; // This will be called only by ICStubInterface void initialize(int size, - CodeComments comments) { _size = size; _ic_site = NULL; } + CodeStrings strings) { _size = size; _ic_site = NULL; } void finalize(); // called when a method is removed // General info diff --git a/hotspot/src/share/vm/code/stubs.cpp b/hotspot/src/share/vm/code/stubs.cpp index 245a2463a05..930c637fac9 100644 --- a/hotspot/src/share/vm/code/stubs.cpp +++ b/hotspot/src/share/vm/code/stubs.cpp @@ -101,8 +101,8 @@ Stub* StubQueue::stub_containing(address pc) const { Stub* StubQueue::request_committed(int code_size) { Stub* s = request(code_size); - CodeComments comments; - if (s != NULL) commit(code_size, comments); + CodeStrings strings; + if (s != NULL) commit(code_size, strings); return s; } @@ -119,8 +119,8 @@ Stub* StubQueue::request(int requested_code_size) { assert(_buffer_limit == _buffer_size, "buffer must be fully usable"); if (_queue_end + requested_size <= _buffer_size) { // code fits in at the end => nothing to do - CodeComments comments; - stub_initialize(s, requested_size, comments); + CodeStrings strings; + stub_initialize(s, requested_size, strings); return s; } else { // stub doesn't fit in at the queue end @@ -137,8 +137,8 @@ Stub* StubQueue::request(int requested_code_size) { // Queue: |XXX|.......|XXXXXXX|.......| // ^0 ^end ^begin ^limit ^size s = current_stub(); - CodeComments comments; - stub_initialize(s, requested_size, comments); + CodeStrings strings; + stub_initialize(s, requested_size, strings); return s; } // Not enough space left @@ -147,12 +147,12 @@ Stub* StubQueue::request(int requested_code_size) { } -void StubQueue::commit(int committed_code_size, CodeComments& comments) { +void StubQueue::commit(int committed_code_size, CodeStrings& strings) { assert(committed_code_size > 0, "committed_code_size must be > 0"); int committed_size = round_to(stub_code_size_to_size(committed_code_size), CodeEntryAlignment); Stub* s = current_stub(); assert(committed_size <= stub_size(s), "committed size must not exceed requested size"); - stub_initialize(s, committed_size, comments); + stub_initialize(s, committed_size, strings); _queue_end += committed_size; _number_of_stubs++; if (_mutex != NULL) _mutex->unlock(); diff --git a/hotspot/src/share/vm/code/stubs.hpp b/hotspot/src/share/vm/code/stubs.hpp index 36ada2a4cd9..233f43e2dae 100644 --- a/hotspot/src/share/vm/code/stubs.hpp +++ b/hotspot/src/share/vm/code/stubs.hpp @@ -73,7 +73,7 @@ class Stub VALUE_OBJ_CLASS_SPEC { public: // Initialization/finalization void initialize(int size, - CodeComments& comments) { ShouldNotCallThis(); } // called to initialize/specify the stub's size + CodeStrings& strings) { ShouldNotCallThis(); } // called to initialize/specify the stub's size void finalize() { ShouldNotCallThis(); } // called before the stub is deallocated // General info/converters @@ -107,7 +107,7 @@ class StubInterface: public CHeapObj { public: // Initialization/finalization virtual void initialize(Stub* self, int size, - CodeComments& comments) = 0; // called after creation (called twice if allocated via (request, commit)) + CodeStrings& strings) = 0; // called after creation (called twice if allocated via (request, commit)) virtual void finalize(Stub* self) = 0; // called before deallocation // General info/converters @@ -136,7 +136,7 @@ class StubInterface: public CHeapObj { public: \ /* Initialization/finalization */ \ virtual void initialize(Stub* self, int size, \ - CodeComments& comments) { cast(self)->initialize(size, comments); } \ + CodeStrings& strings) { cast(self)->initialize(size, strings); } \ virtual void finalize(Stub* self) { cast(self)->finalize(); } \ \ /* General info */ \ @@ -176,7 +176,7 @@ class StubQueue: public CHeapObj { // Stub functionality accessed via interface void stub_initialize(Stub* s, int size, - CodeComments& comments) { assert(size % CodeEntryAlignment == 0, "size not aligned"); _stub_interface->initialize(s, size, comments); } + CodeStrings& strings) { assert(size % CodeEntryAlignment == 0, "size not aligned"); _stub_interface->initialize(s, size, strings); } void stub_finalize(Stub* s) { _stub_interface->finalize(s); } int stub_size(Stub* s) const { return _stub_interface->size(s); } bool stub_contains(Stub* s, address pc) const { return _stub_interface->code_begin(s) <= pc && pc < _stub_interface->code_end(s); } @@ -206,7 +206,7 @@ class StubQueue: public CHeapObj { Stub* request_committed(int code_size); // request a stub that provides exactly code_size space for code Stub* request(int requested_code_size); // request a stub with a (maximum) code space - locks the queue void commit (int committed_code_size, - CodeComments& comments); // commit the previously requested stub - unlocks the queue + CodeStrings& strings); // commit the previously requested stub - unlocks the queue // Stub deallocation void remove_first(); // remove the first stub in the queue diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 6f4e671c165..1b1e2d1cdd5 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -65,9 +65,8 @@ HS_DTRACE_PROBE_DECL8(hotspot, method__compile__begin, HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end, char*, intptr_t, char*, intptr_t, char*, intptr_t, char*, intptr_t, bool); -#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method) \ +#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method, comp_name) \ { \ - char* comp_name = (char*)(compiler)->name(); \ Symbol* klass_name = (method)->klass_name(); \ Symbol* name = (method)->name(); \ Symbol* signature = (method)->signature(); \ @@ -78,9 +77,9 @@ HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end, signature->bytes(), signature->utf8_length()); \ } -#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, success) \ +#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, \ + comp_name, success) \ { \ - char* comp_name = (char*)(compiler)->name(); \ Symbol* klass_name = (method)->klass_name(); \ Symbol* name = (method)->name(); \ Symbol* signature = (method)->signature(); \ @@ -93,22 +92,21 @@ HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end, #else /* USDT2 */ -#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method) \ +#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method, comp_name) \ { \ - char* comp_name = (char*)(compiler)->name(); \ Symbol* klass_name = (method)->klass_name(); \ Symbol* name = (method)->name(); \ Symbol* signature = (method)->signature(); \ - HOTSPOT_METHOD_COMPILE_BEGIN( \ + HOTSPOT_METHOD_COMPILE_BEGIN( \ comp_name, strlen(comp_name), \ - (char *) klass_name->bytes(), klass_name->utf8_length(), \ + (char *) klass_name->bytes(), klass_name->utf8_length(), \ (char *) name->bytes(), name->utf8_length(), \ (char *) signature->bytes(), signature->utf8_length()); \ } -#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, success) \ +#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, \ + comp_name, success) \ { \ - char* comp_name = (char*)(compiler)->name(); \ Symbol* klass_name = (method)->klass_name(); \ Symbol* name = (method)->name(); \ Symbol* signature = (method)->signature(); \ @@ -122,8 +120,8 @@ HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end, #else // ndef DTRACE_ENABLED -#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method) -#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, success) +#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method, comp_name) +#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, comp_name, success) #endif // ndef DTRACE_ENABLED @@ -359,7 +357,7 @@ void CompileTask::print() { // void CompileTask::print_line_on_error(outputStream* st, char* buf, int buflen) { // print compiler name - st->print("%s:", CompileBroker::compiler(comp_level())->name()); + st->print("%s:", CompileBroker::compiler_name(comp_level())); print_compilation(st); } @@ -368,7 +366,7 @@ void CompileTask::print_line_on_error(outputStream* st, char* buf, int buflen) { void CompileTask::print_line() { ttyLocker ttyl; // keep the following output all in one block // print compiler name if requested - if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler(comp_level())->name()); + if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler_name(comp_level())); print_compilation(); } @@ -505,7 +503,7 @@ void CompileTask::log_task(xmlStream* log) { ResourceMark rm(thread); // - if (_compile_id != 0) log->print(" compile_id='%d'", _compile_id); + log->print(" compile_id='%d'", _compile_id); if (_osr_bci != CompileBroker::standard_entry_bci) { log->print(" compile_kind='osr'"); // same as nmethod::compile_kind } // else compile_kind='c2c' @@ -1217,8 +1215,9 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci, // lock, make sure that the compilation // isn't prohibited in a straightforward way. - - if (compiler(comp_level) == NULL || !compiler(comp_level)->can_compile_method(method) || compilation_is_prohibited(method, osr_bci, comp_level)) { + AbstractCompiler *comp = CompileBroker::compiler(comp_level); + if (comp == NULL || !comp->can_compile_method(method) || + compilation_is_prohibited(method, osr_bci, comp_level)) { return NULL; } @@ -1255,7 +1254,7 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci, assert(!HAS_PENDING_EXCEPTION, "No exception should be present"); // some prerequisites that are compiler specific - if (compiler(comp_level)->is_c2() || compiler(comp_level)->is_shark()) { + if (comp->is_c2() || comp->is_shark()) { method->constants()->resolve_string_constants(CHECK_AND_CLEAR_NULL); // Resolve all classes seen in the signature of the method // we are compiling. @@ -1372,8 +1371,9 @@ bool CompileBroker::compilation_is_in_queue(methodHandle method, bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level) { bool is_native = method->is_native(); // Some compilers may not support the compilation of natives. + AbstractCompiler *comp = compiler(comp_level); if (is_native && - (!CICompileNatives || !compiler(comp_level)->supports_native())) { + (!CICompileNatives || comp == NULL || !comp->supports_native())) { method->set_not_compilable_quietly(comp_level); return true; } @@ -1381,7 +1381,7 @@ bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci, bool is_osr = (osr_bci != standard_entry_bci); // Some compilers may not support on stack replacement. if (is_osr && - (!CICompileOSR || !compiler(comp_level)->supports_osr())) { + (!CICompileOSR || comp == NULL || !comp->supports_osr())) { method->set_not_osr_compilable(comp_level); return true; } @@ -1753,6 +1753,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { bool is_osr = (osr_bci != standard_entry_bci); bool should_log = (thread->log() != NULL); bool should_break = false; + int task_level = task->comp_level(); { // create the handle inside it's own block so it can't // accidentally be referenced once the thread transitions to @@ -1766,9 +1767,10 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { assert(!method->is_native(), "no longer compile natives"); // Save information about this method in case of failure. - set_last_compile(thread, method, is_osr, task->comp_level()); + set_last_compile(thread, method, is_osr, task_level); - DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler(task->comp_level()), method); + DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler(task_level), method, + compiler_name(task_level)); } // Allocate a new set of JNI handles. @@ -1805,7 +1807,12 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { TraceTime t1("compilation", &time); - compiler(task->comp_level())->compile_method(&ci_env, target, osr_bci); + AbstractCompiler *comp = compiler(task_level); + if (comp == NULL) { + ci_env.record_method_not_compilable("no compiler", !TieredCompilation); + } else { + comp->compile_method(&ci_env, target, osr_bci); + } if (!ci_env.failing() && task->code() == NULL) { //assert(false, "compiler should always document failure"); @@ -1843,7 +1850,8 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { methodHandle method(thread, task->method()); - DTRACE_METHOD_COMPILE_END_PROBE(compiler(task->comp_level()), method, task->is_success()); + DTRACE_METHOD_COMPILE_END_PROBE(compiler(task_level), method, + compiler_name(task_level), task->is_success()); collect_statistics(thread, time, task); @@ -1868,9 +1876,9 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { break; case ciEnv::MethodCompilable_not_at_tier: if (is_osr) - method->set_not_osr_compilable_quietly(task->comp_level()); + method->set_not_osr_compilable_quietly(task_level); else - method->set_not_compilable_quietly(task->comp_level()); + method->set_not_compilable_quietly(task_level); break; } @@ -2128,7 +2136,14 @@ void CompileBroker::collect_statistics(CompilerThread* thread, elapsedTimer time if (UsePerfData) counters->set_current_method(""); } - +const char* CompileBroker::compiler_name(int comp_level) { + AbstractCompiler *comp = CompileBroker::compiler(comp_level); + if (comp == NULL) { + return "no compiler"; + } else { + return (comp->name()); + } +} void CompileBroker::print_times() { tty->cr(); @@ -2142,11 +2157,13 @@ void CompileBroker::print_times() { CompileBroker::_t_standard_compilation.seconds() / CompileBroker::_total_standard_compile_count); tty->print_cr(" On stack replacement : %6.3f s, Average : %2.3f", CompileBroker::_t_osr_compilation.seconds(), CompileBroker::_t_osr_compilation.seconds() / CompileBroker::_total_osr_compile_count); - if (compiler(CompLevel_simple) != NULL) { - compiler(CompLevel_simple)->print_timers(); + AbstractCompiler *comp = compiler(CompLevel_simple); + if (comp != NULL) { + comp->print_timers(); } - if (compiler(CompLevel_full_optimization) != NULL) { - compiler(CompLevel_full_optimization)->print_timers(); + comp = compiler(CompLevel_full_optimization); + if (comp != NULL) { + comp->print_timers(); } tty->cr(); int tcb = CompileBroker::_sum_osr_bytes_compiled + CompileBroker::_sum_standard_bytes_compiled; diff --git a/hotspot/src/share/vm/compiler/compileBroker.hpp b/hotspot/src/share/vm/compiler/compileBroker.hpp index 7ba448b804a..27fe52851d3 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.hpp +++ b/hotspot/src/share/vm/compiler/compileBroker.hpp @@ -418,6 +418,9 @@ class CompileBroker: AllStatic { static void print_last_compile(); static void print_compiler_threads_on(outputStream* st); + + // compiler name for debugging + static const char* compiler_name(int comp_level); }; #endif // SHARE_VM_COMPILER_COMPILEBROKER_HPP diff --git a/hotspot/src/share/vm/compiler/disassembler.cpp b/hotspot/src/share/vm/compiler/disassembler.cpp index 3efe079142f..070e0321e08 100644 --- a/hotspot/src/share/vm/compiler/disassembler.cpp +++ b/hotspot/src/share/vm/compiler/disassembler.cpp @@ -158,7 +158,7 @@ class decode_env { private: nmethod* _nm; CodeBlob* _code; - CodeComments _comments; + CodeStrings _strings; outputStream* _output; address _start, _end; @@ -198,7 +198,7 @@ class decode_env { void print_address(address value); public: - decode_env(CodeBlob* code, outputStream* output, CodeComments c = CodeComments()); + decode_env(CodeBlob* code, outputStream* output, CodeStrings c = CodeStrings()); address decode_instructions(address start, address end); @@ -242,13 +242,13 @@ class decode_env { const char* options() { return _option_buf; } }; -decode_env::decode_env(CodeBlob* code, outputStream* output, CodeComments c) { +decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c) { memset(this, 0, sizeof(*this)); _output = output ? output : tty; _code = code; if (code != NULL && code->is_nmethod()) _nm = (nmethod*) code; - _comments.assign(c); + _strings.assign(c); // by default, output pc but not bytes: _print_pc = true; @@ -370,7 +370,7 @@ void decode_env::print_insn_labels() { if (cb != NULL) { cb->print_block_comment(st, p); } - _comments.print_block_comment(st, (intptr_t)(p - _start)); + _strings.print_block_comment(st, (intptr_t)(p - _start)); if (_print_pc) { st->print(" " PTR_FORMAT ": ", p); } @@ -498,7 +498,7 @@ void Disassembler::decode(CodeBlob* cb, outputStream* st) { env.decode_instructions(cb->code_begin(), cb->code_end()); } -void Disassembler::decode(address start, address end, outputStream* st, CodeComments c) { +void Disassembler::decode(address start, address end, outputStream* st, CodeStrings c) { if (!load_library()) return; decode_env env(CodeCache::find_blob_unsafe(start), st, c); env.decode_instructions(start, end); diff --git a/hotspot/src/share/vm/compiler/disassembler.hpp b/hotspot/src/share/vm/compiler/disassembler.hpp index fd1f52eee1b..c81666ec25d 100644 --- a/hotspot/src/share/vm/compiler/disassembler.hpp +++ b/hotspot/src/share/vm/compiler/disassembler.hpp @@ -100,7 +100,7 @@ class Disassembler { } static void decode(CodeBlob *cb, outputStream* st = NULL); static void decode(nmethod* nm, outputStream* st = NULL); - static void decode(address begin, address end, outputStream* st = NULL, CodeComments c = CodeComments()); + static void decode(address begin, address end, outputStream* st = NULL, CodeStrings c = CodeStrings()); }; #endif // SHARE_VM_COMPILER_DISASSEMBLER_HPP diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index a9b2714c213..df6aabbb527 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -2063,11 +2063,6 @@ void CMSCollector::do_mark_sweep_work(bool clear_all_soft_refs, // required. _collectorState = FinalMarking; } - if (PrintGCDetails && - (_collectorState > Idling || - !GCCause::is_user_requested_gc(GenCollectedHeap::heap()->gc_cause()))) { - gclog_or_tty->print(" (concurrent mode failure)"); - } collect_in_foreground(clear_all_soft_refs); // For a mark-sweep, compute_new_size() will be called @@ -3400,10 +3395,10 @@ CMSPhaseAccounting::CMSPhaseAccounting(CMSCollector *collector, if (PrintCMSStatistics != 0) { _collector->resetYields(); } - if (PrintGCDetails && PrintGCTimeStamps) { + if (PrintGCDetails) { gclog_or_tty->date_stamp(PrintGCDateStamps); - gclog_or_tty->stamp(); - gclog_or_tty->print_cr(": [%s-concurrent-%s-start]", + gclog_or_tty->stamp(PrintGCTimeStamps); + gclog_or_tty->print_cr("[%s-concurrent-%s-start]", _collector->cmsGen()->short_name(), _phase); } _collector->resetTimer(); @@ -6073,6 +6068,10 @@ void CMSCollector::sweep(bool asynch) { verify_work_stacks_empty(); verify_overflow_empty(); + if (should_unload_classes()) { + ClassLoaderDataGraph::purge(); + } + _intra_sweep_timer.stop(); _intra_sweep_estimate.sample(_intra_sweep_timer.seconds()); diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index cc2a611f0f0..d9d70620e47 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -784,7 +784,7 @@ void ConcurrentMark::reset_marking_state(bool clear_overflow) { } } -void ConcurrentMark::set_phase(uint active_tasks, bool concurrent) { +void ConcurrentMark::set_concurrency(uint active_tasks) { assert(active_tasks <= _max_worker_id, "we should not have more"); _active_tasks = active_tasks; @@ -793,6 +793,10 @@ void ConcurrentMark::set_phase(uint active_tasks, bool concurrent) { _terminator = ParallelTaskTerminator((int) active_tasks, _task_queues); _first_overflow_barrier_sync.set_n_workers((int) active_tasks); _second_overflow_barrier_sync.set_n_workers((int) active_tasks); +} + +void ConcurrentMark::set_concurrency_and_phase(uint active_tasks, bool concurrent) { + set_concurrency(active_tasks); _concurrent = concurrent; // We propagate this to all tasks, not just the active ones. @@ -806,7 +810,9 @@ void ConcurrentMark::set_phase(uint active_tasks, bool concurrent) { // false before we start remark. At this point we should also be // in a STW phase. assert(!concurrent_marking_in_progress(), "invariant"); - assert(_finger == _heap_end, "only way to get here"); + assert(_finger == _heap_end, + err_msg("only way to get here: _finger: "PTR_FORMAT", _heap_end: "PTR_FORMAT, + _finger, _heap_end)); update_g1_committed(true); } } @@ -974,20 +980,28 @@ void ConcurrentMark::enter_first_sync_barrier(uint worker_id) { gclog_or_tty->print_cr("[%u] leaving first barrier", worker_id); } - // let the task associated with with worker 0 do this - if (worker_id == 0) { - // task 0 is responsible for clearing the global data structures - // We should be here because of an overflow. During STW we should - // not clear the overflow flag since we rely on it being true when - // we exit this method to abort the pause and restart concurent - // marking. - reset_marking_state(concurrent() /* clear_overflow */); - force_overflow()->update(); + // If we're executing the concurrent phase of marking, reset the marking + // state; otherwise the marking state is reset after reference processing, + // during the remark pause. + // If we reset here as a result of an overflow during the remark we will + // see assertion failures from any subsequent set_concurrency_and_phase() + // calls. + if (concurrent()) { + // let the task associated with with worker 0 do this + if (worker_id == 0) { + // task 0 is responsible for clearing the global data structures + // We should be here because of an overflow. During STW we should + // not clear the overflow flag since we rely on it being true when + // we exit this method to abort the pause and restart concurent + // marking. + reset_marking_state(true /* clear_overflow */); + force_overflow()->update(); - if (G1Log::fine()) { - gclog_or_tty->date_stamp(PrintGCDateStamps); - gclog_or_tty->stamp(PrintGCTimeStamps); - gclog_or_tty->print_cr("[GC concurrent-mark-reset-for-overflow]"); + if (G1Log::fine()) { + gclog_or_tty->date_stamp(PrintGCDateStamps); + gclog_or_tty->stamp(PrintGCTimeStamps); + gclog_or_tty->print_cr("[GC concurrent-mark-reset-for-overflow]"); + } } } @@ -1007,7 +1021,7 @@ void ConcurrentMark::enter_second_sync_barrier(uint worker_id) { if (concurrent()) { ConcurrentGCThread::stsJoin(); } - // at this point everything should be re-initialised and ready to go + // at this point everything should be re-initialized and ready to go if (verbose_low()) { gclog_or_tty->print_cr("[%u] leaving second barrier", worker_id); @@ -1065,8 +1079,8 @@ public: double mark_step_duration_ms = G1ConcMarkStepDurationMillis; the_task->do_marking_step(mark_step_duration_ms, - true /* do_stealing */, - true /* do_termination */); + true /* do_termination */, + false /* is_serial*/); double end_time_sec = os::elapsedTime(); double end_vtime_sec = os::elapsedVTime(); @@ -1222,8 +1236,8 @@ void ConcurrentMark::markFromRoots() { uint active_workers = MAX2(1U, parallel_marking_threads()); - // Parallel task terminator is set in "set_phase()" - set_phase(active_workers, true /* concurrent */); + // Parallel task terminator is set in "set_concurrency_and_phase()" + set_concurrency_and_phase(active_workers, true /* concurrent */); CMConcurrentMarkingTask markingTask(this, cmThread()); if (use_parallel_marking_threads()) { @@ -1275,12 +1289,22 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { if (has_overflown()) { // Oops. We overflowed. Restart concurrent marking. _restart_for_overflow = true; - // Clear the marking state because we will be restarting - // marking due to overflowing the global mark stack. - reset_marking_state(); if (G1TraceMarkStackOverflow) { gclog_or_tty->print_cr("\nRemark led to restart for overflow."); } + + // Verify the heap w.r.t. the previous marking bitmap. + if (VerifyDuringGC) { + HandleMark hm; // handle scope + gclog_or_tty->print(" VerifyDuringGC:(overflow)"); + Universe::heap()->prepare_for_verify(); + Universe::verify(/* silent */ false, + /* option */ VerifyOption_G1UsePrevMarking); + } + + // Clear the marking state because we will be restarting + // marking due to overflowing the global mark stack. + reset_marking_state(); } else { // Aggregate the per-task counting data that we have accumulated // while marking. @@ -1310,11 +1334,6 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { _markStack.expand(); } -#if VERIFY_OBJS_PROCESSED - _scan_obj_cl.objs_processed = 0; - ThreadLocalObjQueue::objs_enqueued = 0; -#endif - // Statistics double now = os::elapsedTime(); _remark_mark_times.add((mark_work_end - start) * 1000.0); @@ -2189,14 +2208,17 @@ bool G1CMIsAliveClosure::do_object_b(oop obj) { // operating on the global stack. class G1CMKeepAliveAndDrainClosure: public OopClosure { - ConcurrentMark* _cm; - CMTask* _task; - int _ref_counter_limit; - int _ref_counter; + ConcurrentMark* _cm; + CMTask* _task; + int _ref_counter_limit; + int _ref_counter; + bool _is_serial; public: - G1CMKeepAliveAndDrainClosure(ConcurrentMark* cm, CMTask* task) : - _cm(cm), _task(task), _ref_counter_limit(G1RefProcDrainInterval) { + G1CMKeepAliveAndDrainClosure(ConcurrentMark* cm, CMTask* task, bool is_serial) : + _cm(cm), _task(task), _is_serial(is_serial), + _ref_counter_limit(G1RefProcDrainInterval) { assert(_ref_counter_limit > 0, "sanity"); + assert(!_is_serial || _task->worker_id() == 0, "only task 0 for serial code"); _ref_counter = _ref_counter_limit; } @@ -2235,8 +2257,8 @@ class G1CMKeepAliveAndDrainClosure: public OopClosure { do { double mark_step_duration_ms = G1ConcMarkStepDurationMillis; _task->do_marking_step(mark_step_duration_ms, - false /* do_stealing */, - false /* do_termination */); + false /* do_termination */, + _is_serial); } while (_task->has_aborted() && !_cm->has_overflown()); _ref_counter = _ref_counter_limit; } @@ -2258,27 +2280,18 @@ class G1CMKeepAliveAndDrainClosure: public OopClosure { class G1CMDrainMarkingStackClosure: public VoidClosure { ConcurrentMark* _cm; CMTask* _task; - bool _do_stealing; - bool _do_termination; + bool _is_serial; public: - G1CMDrainMarkingStackClosure(ConcurrentMark* cm, CMTask* task, bool is_par) : - _cm(cm), _task(task) { - assert(is_par || _task->worker_id() == 0, - "Only task for worker 0 should be used if ref processing is single threaded"); - // We only allow stealing and only enter the termination protocol - // in CMTask::do_marking_step() if this closure is being instantiated - // for parallel reference processing. - _do_stealing = _do_termination = is_par; + G1CMDrainMarkingStackClosure(ConcurrentMark* cm, CMTask* task, bool is_serial) : + _cm(cm), _task(task), _is_serial(is_serial) { + assert(!_is_serial || _task->worker_id() == 0, "only task 0 for serial code"); } void do_void() { do { if (_cm->verbose_high()) { - gclog_or_tty->print_cr("\t[%u] Drain: Calling do_marking_step - " - "stealing: %s, termination: %s", - _task->worker_id(), - BOOL_TO_STR(_do_stealing), - BOOL_TO_STR(_do_termination)); + gclog_or_tty->print_cr("\t[%u] Drain: Calling do_marking_step - serial: %s", + _task->worker_id(), BOOL_TO_STR(_is_serial)); } // We call CMTask::do_marking_step() to completely drain the local @@ -2299,8 +2312,8 @@ class G1CMDrainMarkingStackClosure: public VoidClosure { // has_aborted() flag that the marking step has completed. _task->do_marking_step(1000000000.0 /* something very large */, - _do_stealing, - _do_termination); + true /* do_termination */, + _is_serial); } while (_task->has_aborted() && !_cm->has_overflown()); } }; @@ -2333,7 +2346,6 @@ class G1CMRefProcTaskProxy: public AbstractGangTask { ProcessTask& _proc_task; G1CollectedHeap* _g1h; ConcurrentMark* _cm; - bool _processing_is_mt; public: G1CMRefProcTaskProxy(ProcessTask& proc_task, @@ -2341,15 +2353,15 @@ public: ConcurrentMark* cm) : AbstractGangTask("Process reference objects in parallel"), _proc_task(proc_task), _g1h(g1h), _cm(cm) { - ReferenceProcessor* rp = _g1h->ref_processor_cm(); - _processing_is_mt = rp->processing_is_mt(); - } + ReferenceProcessor* rp = _g1h->ref_processor_cm(); + assert(rp->processing_is_mt(), "shouldn't be here otherwise"); + } virtual void work(uint worker_id) { - CMTask* marking_task = _cm->task(worker_id); + CMTask* task = _cm->task(worker_id); G1CMIsAliveClosure g1_is_alive(_g1h); - G1CMKeepAliveAndDrainClosure g1_par_keep_alive(_cm, marking_task); - G1CMDrainMarkingStackClosure g1_par_drain(_cm, marking_task, _processing_is_mt); + G1CMKeepAliveAndDrainClosure g1_par_keep_alive(_cm, task, false /* is_serial */); + G1CMDrainMarkingStackClosure g1_par_drain(_cm, task, false /* is_serial */); _proc_task.work(worker_id, g1_is_alive, g1_par_keep_alive, g1_par_drain); } @@ -2361,9 +2373,11 @@ void G1CMRefProcTaskExecutor::execute(ProcessTask& proc_task) { G1CMRefProcTaskProxy proc_task_proxy(proc_task, _g1h, _cm); - // We need to reset the phase for each task execution so that - // the termination protocol of CMTask::do_marking_step works. - _cm->set_phase(_active_workers, false /* concurrent */); + // We need to reset the concurrency level before each + // proxy task execution, so that the termination protocol + // and overflow handling in CMTask::do_marking_step() knows + // how many workers to wait for. + _cm->set_concurrency(_active_workers); _g1h->set_par_threads(_active_workers); _workers->run_task(&proc_task_proxy); _g1h->set_par_threads(0); @@ -2389,12 +2403,29 @@ void G1CMRefProcTaskExecutor::execute(EnqueueTask& enq_task) { G1CMRefEnqueueTaskProxy enq_task_proxy(enq_task); + // Not strictly necessary but... + // + // We need to reset the concurrency level before each + // proxy task execution, so that the termination protocol + // and overflow handling in CMTask::do_marking_step() knows + // how many workers to wait for. + _cm->set_concurrency(_active_workers); _g1h->set_par_threads(_active_workers); _workers->run_task(&enq_task_proxy); _g1h->set_par_threads(0); } void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { + if (has_overflown()) { + // Skip processing the discovered references if we have + // overflown the global marking stack. Reference objects + // only get discovered once so it is OK to not + // de-populate the discovered reference lists. We could have, + // but the only benefit would be that, when marking restarts, + // less reference objects are discovered. + return; + } + ResourceMark rm; HandleMark hm; @@ -2420,26 +2451,39 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { rp->setup_policy(clear_all_soft_refs); assert(_markStack.isEmpty(), "mark stack should be empty"); - // Non-MT instances 'Keep Alive' and 'Complete GC' oop closures. - G1CMKeepAliveAndDrainClosure g1_keep_alive(this, task(0)); - G1CMDrainMarkingStackClosure g1_drain_mark_stack(this, task(0), false); - - // We need at least one active thread. If reference processing is - // not multi-threaded we use the current (ConcurrentMarkThread) thread, - // otherwise we use the work gang from the G1CollectedHeap and we - // utilize all the worker threads we can. - uint active_workers = (rp->processing_is_mt() && g1h->workers() != NULL - ? g1h->workers()->active_workers() - : 1U); + // Instances of the 'Keep Alive' and 'Complete GC' closures used + // in serial reference processing. Note these closures are also + // used for serially processing (by the the current thread) the + // JNI references during parallel reference processing. + // + // These closures do not need to synchronize with the worker + // threads involved in parallel reference processing as these + // instances are executed serially by the current thread (e.g. + // reference processing is not multi-threaded and is thus + // performed by the current thread instead of a gang worker). + // + // The gang tasks involved in parallel reference procssing create + // their own instances of these closures, which do their own + // synchronization among themselves. + G1CMKeepAliveAndDrainClosure g1_keep_alive(this, task(0), true /* is_serial */); + G1CMDrainMarkingStackClosure g1_drain_mark_stack(this, task(0), true /* is_serial */); + // We need at least one active thread. If reference processing + // is not multi-threaded we use the current (VMThread) thread, + // otherwise we use the work gang from the G1CollectedHeap and + // we utilize all the worker threads we can. + bool processing_is_mt = rp->processing_is_mt() && g1h->workers() != NULL; + uint active_workers = (processing_is_mt ? g1h->workers()->active_workers() : 1U); active_workers = MAX2(MIN2(active_workers, _max_worker_id), 1U); + // Parallel processing task executor. G1CMRefProcTaskExecutor par_task_executor(g1h, this, g1h->workers(), active_workers); + AbstractRefProcTaskExecutor* executor = (processing_is_mt ? &par_task_executor : NULL); - AbstractRefProcTaskExecutor* executor = (rp->processing_is_mt() - ? &par_task_executor - : NULL); + // Set the concurrency level. The phase was already set prior to + // executing the remark task. + set_concurrency(active_workers); // Set the degree of MT processing here. If the discovery was done MT, // the number of threads involved during discovery could differ from @@ -2459,6 +2503,7 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { assert(_markStack.overflow() || _markStack.isEmpty(), "mark stack should be empty (unless it overflowed)"); + if (_markStack.overflow()) { // This should have been done already when we tried to push an // entry on to the global mark stack. But let's do it again. @@ -2487,8 +2532,8 @@ void ConcurrentMark::swapMarkBitMaps() { class CMRemarkTask: public AbstractGangTask { private: - ConcurrentMark *_cm; - + ConcurrentMark* _cm; + bool _is_serial; public: void work(uint worker_id) { // Since all available tasks are actually started, we should @@ -2498,8 +2543,8 @@ public: task->record_start_time(); do { task->do_marking_step(1000000000.0 /* something very large */, - true /* do_stealing */, - true /* do_termination */); + true /* do_termination */, + _is_serial); } while (task->has_aborted() && !_cm->has_overflown()); // If we overflow, then we do not want to restart. We instead // want to abort remark and do concurrent marking again. @@ -2507,8 +2552,8 @@ public: } } - CMRemarkTask(ConcurrentMark* cm, int active_workers) : - AbstractGangTask("Par Remark"), _cm(cm) { + CMRemarkTask(ConcurrentMark* cm, int active_workers, bool is_serial) : + AbstractGangTask("Par Remark"), _cm(cm), _is_serial(is_serial) { _cm->terminator()->reset_for_reuse(active_workers); } }; @@ -2529,43 +2574,42 @@ void ConcurrentMark::checkpointRootsFinalWork() { active_workers = (uint) ParallelGCThreads; g1h->workers()->set_active_workers(active_workers); } - set_phase(active_workers, false /* concurrent */); + set_concurrency_and_phase(active_workers, false /* concurrent */); // Leave _parallel_marking_threads at it's // value originally calculated in the ConcurrentMark // constructor and pass values of the active workers // through the gang in the task. - CMRemarkTask remarkTask(this, active_workers); + CMRemarkTask remarkTask(this, active_workers, false /* is_serial */); + // We will start all available threads, even if we decide that the + // active_workers will be fewer. The extra ones will just bail out + // immediately. g1h->set_par_threads(active_workers); g1h->workers()->run_task(&remarkTask); g1h->set_par_threads(0); } else { G1CollectedHeap::StrongRootsScope srs(g1h); - // this is remark, so we'll use up all available threads uint active_workers = 1; - set_phase(active_workers, false /* concurrent */); + set_concurrency_and_phase(active_workers, false /* concurrent */); - CMRemarkTask remarkTask(this, active_workers); - // We will start all available threads, even if we decide that the - // active_workers will be fewer. The extra ones will just bail out - // immediately. + // Note - if there's no work gang then the VMThread will be + // the thread to execute the remark - serially. We have + // to pass true for the is_serial parameter so that + // CMTask::do_marking_step() doesn't enter the sync + // barriers in the event of an overflow. Doing so will + // cause an assert that the current thread is not a + // concurrent GC thread. + CMRemarkTask remarkTask(this, active_workers, true /* is_serial*/); remarkTask.work(0); } SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); - guarantee(satb_mq_set.completed_buffers_num() == 0, "invariant"); + guarantee(has_overflown() || + satb_mq_set.completed_buffers_num() == 0, + err_msg("Invariant: has_overflown = %s, num buffers = %d", + BOOL_TO_STR(has_overflown()), + satb_mq_set.completed_buffers_num())); print_stats(); - -#if VERIFY_OBJS_PROCESSED - if (_scan_obj_cl.objs_processed != ThreadLocalObjQueue::objs_enqueued) { - gclog_or_tty->print_cr("Processed = %d, enqueued = %d.", - _scan_obj_cl.objs_processed, - ThreadLocalObjQueue::objs_enqueued); - guarantee(_scan_obj_cl.objs_processed == - ThreadLocalObjQueue::objs_enqueued, - "Different number of objs processed and enqueued."); - } -#endif } #ifndef PRODUCT @@ -3870,8 +3914,8 @@ void CMTask::print_stats() { /***************************************************************************** - The do_marking_step(time_target_ms) method is the building block - of the parallel marking framework. It can be called in parallel + The do_marking_step(time_target_ms, ...) method is the building + block of the parallel marking framework. It can be called in parallel with other invocations of do_marking_step() on different tasks (but only one per task, obviously) and concurrently with the mutator threads, or during remark, hence it eliminates the need @@ -3881,7 +3925,7 @@ void CMTask::print_stats() { pauses too, since do_marking_step() ensures that it aborts before it needs to yield. - The data structures that is uses to do marking work are the + The data structures that it uses to do marking work are the following: (1) Marking Bitmap. If there are gray objects that appear only @@ -3930,7 +3974,7 @@ void CMTask::print_stats() { (2) When a global overflow (on the global stack) has been triggered. Before the task aborts, it will actually sync up with the other tasks to ensure that all the marking data structures - (local queues, stacks, fingers etc.) are re-initialised so that + (local queues, stacks, fingers etc.) are re-initialized so that when do_marking_step() completes, the marking phase can immediately restart. @@ -3967,11 +4011,25 @@ void CMTask::print_stats() { place, it was natural to piggy-back all the other conditions on it too and not constantly check them throughout the code. + If do_termination is true then do_marking_step will enter its + termination protocol. + + The value of is_serial must be true when do_marking_step is being + called serially (i.e. by the VMThread) and do_marking_step should + skip any synchronization in the termination and overflow code. + Examples include the serial remark code and the serial reference + processing closures. + + The value of is_serial must be false when do_marking_step is + being called by any of the worker threads in a work gang. + Examples include the concurrent marking code (CMMarkingTask), + the MT remark code, and the MT reference processing closures. + *****************************************************************************/ void CMTask::do_marking_step(double time_target_ms, - bool do_stealing, - bool do_termination) { + bool do_termination, + bool is_serial) { assert(time_target_ms >= 1.0, "minimum granularity is 1ms"); assert(concurrent() == _cm->concurrent(), "they should be the same"); @@ -3992,6 +4050,12 @@ void CMTask::do_marking_step(double time_target_ms, _start_time_ms = os::elapsedVTime() * 1000.0; statsOnly( _interval_start_time_ms = _start_time_ms ); + // If do_stealing is true then do_marking_step will attempt to + // steal work from the other CMTasks. It only makes sense to + // enable stealing when the termination protocol is enabled + // and do_marking_step() is not being called serially. + bool do_stealing = do_termination && !is_serial; + double diff_prediction_ms = g1_policy->get_new_prediction(&_marking_step_diffs_ms); _time_target_ms = time_target_ms - diff_prediction_ms; @@ -4111,7 +4175,7 @@ void CMTask::do_marking_step(double time_target_ms, // bitmap knows by how much we need to move it as it knows its // granularity). assert(_finger < _region_limit, "invariant"); - HeapWord* new_finger = _nextMarkBitMap->nextWord(_finger); + HeapWord* new_finger = _nextMarkBitMap->nextObject(_finger); // Check if bitmap iteration was aborted while scanning the last object if (new_finger >= _region_limit) { giveup_current_region(); @@ -4253,10 +4317,12 @@ void CMTask::do_marking_step(double time_target_ms, } _termination_start_time_ms = os::elapsedVTime() * 1000.0; + // The CMTask class also extends the TerminatorTerminator class, // hence its should_exit_termination() method will also decide // whether to exit the termination protocol or not. - bool finished = _cm->terminator()->offer_termination(this); + bool finished = (is_serial || + _cm->terminator()->offer_termination(this)); double termination_end_time_ms = os::elapsedVTime() * 1000.0; _termination_time_ms += termination_end_time_ms - _termination_start_time_ms; @@ -4336,20 +4402,28 @@ void CMTask::do_marking_step(double time_target_ms, gclog_or_tty->print_cr("[%u] detected overflow", _worker_id); } - _cm->enter_first_sync_barrier(_worker_id); - // When we exit this sync barrier we know that all tasks have - // stopped doing marking work. So, it's now safe to - // re-initialise our data structures. At the end of this method, - // task 0 will clear the global data structures. + if (!is_serial) { + // We only need to enter the sync barrier if being called + // from a parallel context + _cm->enter_first_sync_barrier(_worker_id); + + // When we exit this sync barrier we know that all tasks have + // stopped doing marking work. So, it's now safe to + // re-initialise our data structures. At the end of this method, + // task 0 will clear the global data structures. + } statsOnly( ++_aborted_overflow ); // We clear the local state of this task... clear_region_fields(); - // ...and enter the second barrier. - _cm->enter_second_sync_barrier(_worker_id); - // At this point everything has bee re-initialised and we're + if (!is_serial) { + // ...and enter the second barrier. + _cm->enter_second_sync_barrier(_worker_id); + } + // At this point, if we're during the concurrent phase of + // marking, everything has been re-initialized and we're // ready to restart. } diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp index 6ec27c7d9fa..43554a5c991 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp @@ -97,7 +97,6 @@ class CMBitMapRO VALUE_OBJ_CLASS_SPEC { HeapWord* limit = NULL) const; // conversion utilities - // XXX Fix these so that offsets are size_t's... HeapWord* offsetToHeapWord(size_t offset) const { return _bmStartWord + (offset << _shifter); } @@ -105,8 +104,13 @@ class CMBitMapRO VALUE_OBJ_CLASS_SPEC { return pointer_delta(addr, _bmStartWord) >> _shifter; } int heapWordDiffToOffsetDiff(size_t diff) const; - HeapWord* nextWord(HeapWord* addr) { - return offsetToHeapWord(heapWordToOffset(addr) + 1); + + // The argument addr should be the start address of a valid object + HeapWord* nextObject(HeapWord* addr) { + oop obj = (oop) addr; + HeapWord* res = addr + obj->size(); + assert(offsetToHeapWord(heapWordToOffset(res)) == res, "sanity"); + return res; } // debugging @@ -162,7 +166,7 @@ class CMBitMap : public CMBitMapRO { class CMMarkStack VALUE_OBJ_CLASS_SPEC { VirtualSpace _virtual_space; // Underlying backing store for actual stack ConcurrentMark* _cm; - oop* _base; // bottom of stack + oop* _base; // bottom of stack jint _index; // one more than last occupied index jint _capacity; // max #elements jint _saved_index; // value of _index saved at start of GC @@ -487,9 +491,12 @@ protected: // structures are initialised to a sensible and predictable state. void set_non_marking_state(); + // Called to indicate how many threads are currently active. + void set_concurrency(uint active_tasks); + // It should be called to indicate which phase we're in (concurrent // mark or remark) and how many threads are currently active. - void set_phase(uint active_tasks, bool concurrent); + void set_concurrency_and_phase(uint active_tasks, bool concurrent); // prints all gathered CM-related statistics void print_stats(); @@ -1142,7 +1149,9 @@ public: // trying not to exceed the given duration. However, it might exit // prematurely, according to some conditions (i.e. SATB buffers are // available for processing). - void do_marking_step(double target_ms, bool do_stealing, bool do_termination); + void do_marking_step(double target_ms, + bool do_termination, + bool is_serial); // These two calls start and stop the timer void record_start_time() { diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp index f084bca5a77..d962842b39a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -252,12 +252,10 @@ inline bool CMBitMapRO::iterate(BitMapClosure* cl, MemRegion mr) { start_offset = _bm.get_next_one_offset(start_offset, end_offset); while (start_offset < end_offset) { - HeapWord* obj_addr = offsetToHeapWord(start_offset); - oop obj = (oop) obj_addr; if (!cl->do_bit(start_offset)) { return false; } - HeapWord* next_addr = MIN2(obj_addr + obj->size(), end_addr); + HeapWord* next_addr = MIN2(nextObject(offsetToHeapWord(start_offset)), end_addr); BitMap::idx_t next_offset = heapWordToOffset(next_addr); start_offset = _bm.get_next_one_offset(next_offset, end_offset); } diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp index cbd56f755c5..0c39e69e1be 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp @@ -409,7 +409,7 @@ HeapWord* ParallelScavengeHeap::mem_allocate( // heap remains parsable. const bool limit_exceeded = size_policy()->gc_overhead_limit_exceeded(); const bool softrefs_clear = collector_policy()->all_soft_refs_clear(); - assert(!limit_exceeded || softrefs_clear, "Should have been cleared"); + if (limit_exceeded && softrefs_clear) { *gc_overhead_limit_was_exceeded = true; size_policy()->set_gc_overhead_limit_exceeded(false); @@ -656,7 +656,7 @@ void ParallelScavengeHeap::print_tracing_info() const { tty->print_cr("[Accumulated GC generation 0 time %3.7f secs]", time); } if (TraceGen1Time) { - double time = PSMarkSweep::accumulated_time()->seconds(); + double time = UseParallelOldGC ? PSParallelCompact::accumulated_time()->seconds() : PSMarkSweep::accumulated_time()->seconds(); tty->print_cr("[Accumulated GC generation 1 time %3.7f secs]", time); } } diff --git a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp index 8de8b3a2983..d3d758b79bd 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp @@ -948,6 +948,8 @@ void MutableNUMASpace::LGRPSpace::scan_pages(size_t page_size, size_t page_count break; } if (e != scan_end) { + assert(e < scan_end, err_msg("e: " PTR_FORMAT " scan_end: " PTR_FORMAT, e, scan_end)); + if ((page_expected.size != page_size || page_expected.lgrp_id != lgrp_id()) && page_expected.size != 0) { os::free_memory(s, pointer_delta(e, s, sizeof(char)), page_size); diff --git a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp index 7cd621318f7..264d4fffbf6 100644 --- a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp @@ -186,7 +186,8 @@ class AbstractInterpreter: AllStatic { int caller_actual_parameters, int callee_params, int callee_locals, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { return layout_activation(method, temps, popframe_args, @@ -196,7 +197,8 @@ class AbstractInterpreter: AllStatic { callee_locals, (frame*)NULL, (frame*)NULL, - is_top_frame); + is_top_frame, + is_bottom_frame); } static int layout_activation(Method* method, @@ -208,7 +210,8 @@ class AbstractInterpreter: AllStatic { int callee_locals, frame* caller, frame* interpreter_frame, - bool is_top_frame); + bool is_top_frame, + bool is_bottom_frame); // Runtime support static bool is_not_reached( methodHandle method, int bci); diff --git a/hotspot/src/share/vm/interpreter/interpreter.cpp b/hotspot/src/share/vm/interpreter/interpreter.cpp index 24de109f39c..06554172bf1 100644 --- a/hotspot/src/share/vm/interpreter/interpreter.cpp +++ b/hotspot/src/share/vm/interpreter/interpreter.cpp @@ -76,7 +76,7 @@ void InterpreterCodelet::print_on(outputStream* st) const { if (PrintInterpreter) { st->cr(); - Disassembler::decode(code_begin(), code_end(), st, DEBUG_ONLY(_comments) NOT_DEBUG(CodeComments())); + Disassembler::decode(code_begin(), code_end(), st, DEBUG_ONLY(_strings) NOT_DEBUG(CodeStrings())); } } diff --git a/hotspot/src/share/vm/interpreter/interpreter.hpp b/hotspot/src/share/vm/interpreter/interpreter.hpp index 346af856a04..1fb4ac5c8ce 100644 --- a/hotspot/src/share/vm/interpreter/interpreter.hpp +++ b/hotspot/src/share/vm/interpreter/interpreter.hpp @@ -48,12 +48,12 @@ class InterpreterCodelet: public Stub { int _size; // the size in bytes const char* _description; // a description of the codelet, for debugging & printing Bytecodes::Code _bytecode; // associated bytecode if any - DEBUG_ONLY(CodeComments _comments;) // Comments for annotating assembler output. + DEBUG_ONLY(CodeStrings _strings;) // Comments for annotating assembler output. public: // Initialization/finalization void initialize(int size, - CodeComments& comments) { _size = size; DEBUG_ONLY(_comments.assign(comments);) } + CodeStrings& strings) { _size = size; DEBUG_ONLY(_strings.assign(strings);) } void finalize() { ShouldNotCallThis(); } // General info/converters @@ -131,7 +131,7 @@ class CodeletMark: ResourceMark { // commit Codelet - AbstractInterpreter::code()->commit((*_masm)->code()->pure_insts_size(), (*_masm)->code()->comments()); + AbstractInterpreter::code()->commit((*_masm)->code()->pure_insts_size(), (*_masm)->code()->strings()); // make sure nobody can use _masm outside a CodeletMark lifespan *_masm = NULL; } diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp index 1a1a235210f..f5639a55b4b 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp @@ -803,7 +803,7 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result, methodHandle if (!direct_calling_default_method && check_access && // a) check if ACC_SUPER flag is set for the current class - current_klass->is_super() && + (current_klass->is_super() || !AllowNonVirtualCalls) && // b) check if the method class is a superclass of the current class (superclass relation is not reflexive!) current_klass->is_subtype_of(method_klass()) && current_klass() != method_klass() && diff --git a/hotspot/src/share/vm/interpreter/rewriter.cpp b/hotspot/src/share/vm/interpreter/rewriter.cpp index 0b5d2513925..249fca33afe 100644 --- a/hotspot/src/share/vm/interpreter/rewriter.cpp +++ b/hotspot/src/share/vm/interpreter/rewriter.cpp @@ -84,15 +84,13 @@ void Rewriter::make_constant_pool_cache(TRAPS) { const int length = _cp_cache_map.length(); ClassLoaderData* loader_data = _pool->pool_holder()->class_loader_data(); ConstantPoolCache* cache = - ConstantPoolCache::allocate(loader_data, length, CHECK); + ConstantPoolCache::allocate(loader_data, length, _cp_cache_map, + _invokedynamic_references_map, CHECK); // initialize object cache in constant pool _pool->initialize_resolved_references(loader_data, _resolved_references_map, _resolved_reference_limit, CHECK); - - No_Safepoint_Verifier nsv; - cache->initialize(_cp_cache_map, _invokedynamic_references_map); _pool->set_cache(cache); cache->set_constant_pool(_pool()); } diff --git a/hotspot/src/share/vm/memory/collectorPolicy.cpp b/hotspot/src/share/vm/memory/collectorPolicy.cpp index ab8f2ca7fc0..d5eb387a04c 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.cpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp @@ -620,7 +620,7 @@ HeapWord* GenCollectorPolicy::mem_allocate_work(size_t size, const bool limit_exceeded = size_policy()->gc_overhead_limit_exceeded(); const bool softrefs_clear = all_soft_refs_clear(); - assert(!limit_exceeded || softrefs_clear, "Should have been cleared"); + if (limit_exceeded && softrefs_clear) { *gc_overhead_limit_was_exceeded = true; size_policy()->set_gc_overhead_limit_exceeded(false); diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp index 75f01d0510a..a11914b9c01 100644 --- a/hotspot/src/share/vm/memory/filemap.hpp +++ b/hotspot/src/share/vm/memory/filemap.hpp @@ -112,12 +112,19 @@ public: char* region_base(int i) { return _header._space[i]._base; } struct FileMapHeader* header() { return &_header; } - static void set_current_info(FileMapInfo* info) { _current_info = info; } - static FileMapInfo* current_info() { return _current_info; } + static void set_current_info(FileMapInfo* info) { + CDS_ONLY(_current_info = info;) + } + + static FileMapInfo* current_info() { + CDS_ONLY(return _current_info;) + NOT_CDS(return NULL;) + } + static void assert_mark(bool check); // File manipulation. - bool initialize(); + bool initialize() NOT_CDS_RETURN_(false); bool open_for_read(); void open_for_write(); void write_header(); @@ -141,7 +148,7 @@ public: void fail_continue(const char *msg, ...); // Return true if given address is in the mapped shared space. - bool is_in_shared_space(const void* p); + bool is_in_shared_space(const void* p) NOT_CDS_RETURN_(false); }; #endif // SHARE_VM_MEMORY_FILEMAP_HPP diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index 9d65cc15701..6b7402c8203 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -554,6 +554,8 @@ void GenCollectedHeap::do_collection(bool full, } if (complete) { + // Delete metaspaces for unloaded class loaders and clean up loader_data graph + ClassLoaderDataGraph::purge(); // Resize the metaspace capacity after full collections MetaspaceGC::compute_new_size(); update_full_collections_completed(); @@ -564,11 +566,6 @@ void GenCollectedHeap::do_collection(bool full, gc_epilogue(complete); - // Delete metaspaces for unloaded class loaders and clean up loader_data graph - if (complete) { - ClassLoaderDataGraph::purge(); - } - if (must_restore_marks_for_biased_locking) { BiasedLocking::restore_marks(); } diff --git a/hotspot/src/share/vm/memory/metablock.cpp b/hotspot/src/share/vm/memory/metablock.cpp index 8aa6a9f8372..450d2c3193d 100644 --- a/hotspot/src/share/vm/memory/metablock.cpp +++ b/hotspot/src/share/vm/memory/metablock.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index b0891150d9c..f5b37bbe7be 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,6 @@ const bool metaspace_slow_verify = false; const uint metadata_deallocate_a_lot_block = 10; const uint metadata_deallocate_a_lock_chunk = 3; size_t const allocation_from_dictionary_limit = 64 * K; -const size_t metadata_deallocate = 0xf5f5f5f5; MetaWord* last_allocated = 0; @@ -335,6 +334,9 @@ class VirtualSpaceNode : public CHeapObj { // byte_size is the size of the associated virtualspace. VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(0) { + // align up to vm allocation granularity + byte_size = align_size_up(byte_size, os::vm_allocation_granularity()); + // This allocates memory with mmap. For DumpSharedspaces, allocate the // space at low memory so that other shared images don't conflict. // This is the same address as memory needed for UseCompressedOops but @@ -1101,25 +1103,24 @@ size_t MetaspaceGC::delta_capacity_until_GC(size_t word_size) { } bool MetaspaceGC::should_expand(VirtualSpaceList* vsl, size_t word_size) { + // If the user wants a limit, impose one. + if (!FLAG_IS_DEFAULT(MaxMetaspaceSize) && + MetaspaceAux::reserved_in_bytes() >= MaxMetaspaceSize) { + return false; + } // Class virtual space should always be expanded. Call GC for the other // metadata virtual space. if (vsl == Metaspace::class_space_list()) return true; - // If the user wants a limit, impose one. - size_t max_metaspace_size_words = MaxMetaspaceSize / BytesPerWord; - size_t metaspace_size_words = MetaspaceSize / BytesPerWord; - if (!FLAG_IS_DEFAULT(MaxMetaspaceSize) && - vsl->capacity_words_sum() >= max_metaspace_size_words) { - return false; - } - // If this is part of an allocation after a GC, expand // unconditionally. if(MetaspaceGC::expand_after_GC()) { return true; } + size_t metaspace_size_words = MetaspaceSize / BytesPerWord; + // If the capacity is below the minimum capacity, allow the // expansion. Also set the high-water-mark (capacity_until_GC) // to that minimum capacity so that a GC will not be induced @@ -1309,8 +1310,7 @@ void MetaspaceGC::compute_new_size() { gclog_or_tty->print_cr(" metaspace HWM: %.1fK", new_capacity_until_GC / (double) K); } } - assert(vsl->used_bytes_sum() == used_after_gc && - used_after_gc <= vsl->capacity_bytes_sum(), + assert(used_after_gc <= vsl->capacity_bytes_sum(), "sanity check"); } @@ -1970,6 +1970,9 @@ void SpaceManager::initialize() { } SpaceManager::~SpaceManager() { + // This call this->_lock which can't be done while holding expand_lock() + const size_t in_use_before = sum_capacity_in_chunks_in_use(); + MutexLockerEx fcl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); @@ -1987,7 +1990,7 @@ SpaceManager::~SpaceManager() { // Have to update before the chunks_in_use lists are emptied // below. - chunk_manager->inc_free_chunks_total(sum_capacity_in_chunks_in_use(), + chunk_manager->inc_free_chunks_total(in_use_before, sum_count_in_chunks_in_use()); // Add all the chunks in use by this space manager @@ -2440,7 +2443,8 @@ void MetaspaceAux::print_on(outputStream* out, Metaspace::MetadataType mdtype) { free_chunks_capacity_bytes / K, used_and_free / K, capacity_bytes / K); - assert(used_and_free == capacity_bytes, "Accounting is wrong"); + // Accounting can only be correct if we got the values during a safepoint + assert(!SafepointSynchronize::is_at_safepoint() || used_and_free == capacity_bytes, "Accounting is wrong"); } // Print total fragmentation for class and data metaspaces separately diff --git a/hotspot/src/share/vm/memory/sharedHeap.cpp b/hotspot/src/share/vm/memory/sharedHeap.cpp index be641d304ba..caef7ac7ad0 100644 --- a/hotspot/src/share/vm/memory/sharedHeap.cpp +++ b/hotspot/src/share/vm/memory/sharedHeap.cpp @@ -178,7 +178,7 @@ void SharedHeap::process_strong_roots(bool activate_scope, SystemDictionary::always_strong_oops_do(roots); ClassLoaderDataGraph::always_strong_oops_do(roots, klass_closure, !is_scavenging); } else { - ShouldNotReachHere2("We should always have selected either SO_AllClasses or SO_SystemClasses"); + fatal("We should always have selected either SO_AllClasses or SO_SystemClasses"); } } diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index a7a6c24bfd2..79e092a3b19 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -885,6 +885,8 @@ ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) { // the actual alignment depends on its size. Universe::set_class_metaspace_size(align_size_up(ClassMetaspaceSize, alignment)); size_t total_reserved = align_size_up(heap_size + Universe::class_metaspace_size(), alignment); + assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())), + "heap size is too big for compressed oops"); char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); ReservedHeapSpace total_rs(total_reserved, alignment, UseLargePages, addr); diff --git a/hotspot/src/share/vm/oops/constMethod.cpp b/hotspot/src/share/vm/oops/constMethod.cpp index 35b7be24fc9..98a29a2e1dc 100644 --- a/hotspot/src/share/vm/oops/constMethod.cpp +++ b/hotspot/src/share/vm/oops/constMethod.cpp @@ -55,11 +55,24 @@ ConstMethod::ConstMethod(int byte_code_size, set_stackmap_data(NULL); set_code_size(byte_code_size); set_constMethod_size(size); - set_inlined_tables_length(sizes); + set_inlined_tables_length(sizes); // sets _flags set_method_type(method_type); assert(this->size() == size, "wrong size for object"); + set_name_index(0); + set_signature_index(0); + set_constants(NULL); + set_max_stack(0); + set_max_locals(0); + set_method_idnum(0); + set_size_of_parameters(0); } +// Accessor that copies to metadata. +void ConstMethod::copy_stackmap_data(ClassLoaderData* loader_data, + u1* sd, int length, TRAPS) { + _stackmap_data = MetadataFactory::new_array(loader_data, length, CHECK); + memcpy((void*)_stackmap_data->adr_at(0), (void*)sd, length); +} // Deallocate metadata fields associated with ConstMethod* void ConstMethod::deallocate_contents(ClassLoaderData* loader_data) { diff --git a/hotspot/src/share/vm/oops/constMethod.hpp b/hotspot/src/share/vm/oops/constMethod.hpp index 21fa344bc9d..0c4212564b0 100644 --- a/hotspot/src/share/vm/oops/constMethod.hpp +++ b/hotspot/src/share/vm/oops/constMethod.hpp @@ -280,6 +280,7 @@ public: // stackmap table data Array* stackmap_data() const { return _stackmap_data; } void set_stackmap_data(Array* sd) { _stackmap_data = sd; } + void copy_stackmap_data(ClassLoaderData* loader_data, u1* sd, int length, TRAPS); bool has_stackmap_table() const { return _stackmap_data != NULL; } void init_fingerprint() { diff --git a/hotspot/src/share/vm/oops/constantPool.cpp b/hotspot/src/share/vm/oops/constantPool.cpp index c025730bbb4..ba7ec439e4f 100644 --- a/hotspot/src/share/vm/oops/constantPool.cpp +++ b/hotspot/src/share/vm/oops/constantPool.cpp @@ -1852,6 +1852,7 @@ void ConstantPool::print_entry_on(const int index, outputStream* st) { switch (tag_at(index).value()) { case JVM_CONSTANT_Class : { Klass* k = klass_at(index, CATCH); + guarantee(k != NULL, "need klass"); k->print_value_on(st); st->print(" {0x%lx}", (address)k); } diff --git a/hotspot/src/share/vm/oops/cpCache.cpp b/hotspot/src/share/vm/oops/cpCache.cpp index 11ab856e1ca..c2175ca81ff 100644 --- a/hotspot/src/share/vm/oops/cpCache.cpp +++ b/hotspot/src/share/vm/oops/cpCache.cpp @@ -44,6 +44,8 @@ void ConstantPoolCacheEntry::initialize_entry(int index) { assert(0 < index && index < 0x10000, "sanity check"); _indices = index; + _f1 = NULL; + _f2 = _flags = 0; assert(constant_pool_index() == index, ""); } @@ -533,13 +535,17 @@ void ConstantPoolCacheEntry::verify(outputStream* st) const { // Implementation of ConstantPoolCache -ConstantPoolCache* ConstantPoolCache::allocate(ClassLoaderData* loader_data, int length, TRAPS) { +ConstantPoolCache* ConstantPoolCache::allocate(ClassLoaderData* loader_data, + int length, + const intStack& index_map, + const intStack& invokedynamic_map, TRAPS) { int size = ConstantPoolCache::size(length); - return new (loader_data, size, false, THREAD) ConstantPoolCache(length); + return new (loader_data, size, false, THREAD) ConstantPoolCache(length, index_map, invokedynamic_map); } -void ConstantPoolCache::initialize(intArray& inverse_index_map, intArray& invokedynamic_references_map) { +void ConstantPoolCache::initialize(const intArray& inverse_index_map, + const intArray& invokedynamic_references_map) { assert(inverse_index_map.length() == length(), "inverse index map must have same length as cache"); for (int i = 0; i < length(); i++) { ConstantPoolCacheEntry* e = entry_at(i); diff --git a/hotspot/src/share/vm/oops/cpCache.hpp b/hotspot/src/share/vm/oops/cpCache.hpp index c1e058d81db..27ca7980c07 100644 --- a/hotspot/src/share/vm/oops/cpCache.hpp +++ b/hotspot/src/share/vm/oops/cpCache.hpp @@ -377,14 +377,21 @@ class ConstantPoolCache: public MetaspaceObj { debug_only(friend class ClassVerifier;) // Constructor - ConstantPoolCache(int length) : _length(length), _constant_pool(NULL) { + ConstantPoolCache(int length, const intStack& inverse_index_map, + const intStack& invokedynamic_references_map) : + _length(length), _constant_pool(NULL) { + initialize(inverse_index_map, invokedynamic_references_map); for (int i = 0; i < length; i++) { assert(entry_at(i)->is_f1_null(), "Failed to clear?"); } } + // Initialization + void initialize(const intArray& inverse_index_map, const intArray& invokedynamic_references_map); public: - static ConstantPoolCache* allocate(ClassLoaderData* loader_data, int length, TRAPS); + static ConstantPoolCache* allocate(ClassLoaderData* loader_data, int length, + const intStack& inverse_index_map, + const intStack& invokedynamic_references_map, TRAPS); bool is_constantPoolCache() const { return true; } int length() const { return _length; } @@ -405,9 +412,6 @@ class ConstantPoolCache: public MetaspaceObj { friend class ConstantPoolCacheEntry; public: - // Initialization - void initialize(intArray& inverse_index_map, intArray& invokedynamic_references_map); - // Accessors void set_constant_pool(ConstantPool* pool) { _constant_pool = pool; } ConstantPool* constant_pool() const { return _constant_pool; } diff --git a/hotspot/src/share/vm/oops/fieldInfo.hpp b/hotspot/src/share/vm/oops/fieldInfo.hpp index 331dc05f37c..5da8ed9628a 100644 --- a/hotspot/src/share/vm/oops/fieldInfo.hpp +++ b/hotspot/src/share/vm/oops/fieldInfo.hpp @@ -108,11 +108,11 @@ class FieldInfo VALUE_OBJ_CLASS_SPEC { return build_int_from_shorts(_shorts[low_packed_offset], _shorts[high_packed_offset]) >> FIELDINFO_TAG_SIZE; #ifndef PRODUCT case FIELDINFO_TAG_TYPE_PLAIN: - ShouldNotReachHere2("Asking offset for the plain type field"); + fatal("Asking offset for the plain type field"); case FIELDINFO_TAG_TYPE_CONTENDED: - ShouldNotReachHere2("Asking offset for the contended type field"); + fatal("Asking offset for the contended type field"); case FIELDINFO_TAG_BLANK: - ShouldNotReachHere2("Asking offset for the blank field"); + fatal("Asking offset for the blank field"); #endif } ShouldNotReachHere(); @@ -128,9 +128,9 @@ class FieldInfo VALUE_OBJ_CLASS_SPEC { return true; #ifndef PRODUCT case FIELDINFO_TAG_OFFSET: - ShouldNotReachHere2("Asking contended flag for the field with offset"); + fatal("Asking contended flag for the field with offset"); case FIELDINFO_TAG_BLANK: - ShouldNotReachHere2("Asking contended flag for the blank field"); + fatal("Asking contended flag for the blank field"); #endif } ShouldNotReachHere(); @@ -146,9 +146,9 @@ class FieldInfo VALUE_OBJ_CLASS_SPEC { return _shorts[high_packed_offset]; #ifndef PRODUCT case FIELDINFO_TAG_OFFSET: - ShouldNotReachHere2("Asking the contended group for the field with offset"); + fatal("Asking the contended group for the field with offset"); case FIELDINFO_TAG_BLANK: - ShouldNotReachHere2("Asking the contended group for the blank field"); + fatal("Asking the contended group for the blank field"); #endif } ShouldNotReachHere(); @@ -163,9 +163,9 @@ class FieldInfo VALUE_OBJ_CLASS_SPEC { return (lo >> FIELDINFO_TAG_SIZE); #ifndef PRODUCT case FIELDINFO_TAG_OFFSET: - ShouldNotReachHere2("Asking the field type for field with offset"); + fatal("Asking the field type for field with offset"); case FIELDINFO_TAG_BLANK: - ShouldNotReachHere2("Asking the field type for the blank field"); + fatal("Asking the field type for the blank field"); #endif } ShouldNotReachHere(); @@ -211,7 +211,7 @@ class FieldInfo VALUE_OBJ_CLASS_SPEC { case FIELDINFO_TAG_TYPE_PLAIN: case FIELDINFO_TAG_TYPE_CONTENDED: case FIELDINFO_TAG_OFFSET: - ShouldNotReachHere2("Setting the field type with overwriting"); + fatal("Setting the field type with overwriting"); #endif } ShouldNotReachHere(); @@ -226,11 +226,11 @@ class FieldInfo VALUE_OBJ_CLASS_SPEC { return; #ifndef PRODUCT case FIELDINFO_TAG_TYPE_CONTENDED: - ShouldNotReachHere2("Overwriting contended group"); + fatal("Overwriting contended group"); case FIELDINFO_TAG_BLANK: - ShouldNotReachHere2("Setting contended group for the blank field"); + fatal("Setting contended group for the blank field"); case FIELDINFO_TAG_OFFSET: - ShouldNotReachHere2("Setting contended group for field with offset"); + fatal("Setting contended group for field with offset"); #endif } ShouldNotReachHere(); diff --git a/hotspot/src/share/vm/oops/generateOopMap.cpp b/hotspot/src/share/vm/oops/generateOopMap.cpp index 96572a64e23..8c12b7ac77d 100644 --- a/hotspot/src/share/vm/oops/generateOopMap.cpp +++ b/hotspot/src/share/vm/oops/generateOopMap.cpp @@ -762,6 +762,7 @@ void GenerateOopMap::copy_state(CellTypeState *dst, CellTypeState *src) { // monitor matching is purely informational and doesn't say anything // about the correctness of the code. void GenerateOopMap::merge_state_into_bb(BasicBlock *bb) { + guarantee(bb != NULL, "null basicblock"); assert(bb->is_alive(), "merging state into a dead basicblock"); if (_stack_top == bb->_stack_top) { @@ -1189,6 +1190,7 @@ void GenerateOopMap::do_exception_edge(BytecodeStream* itr) { if (start_pc <= bci && bci < end_pc) { BasicBlock *excBB = get_basic_block_at(handler_pc); + guarantee(excBB != NULL, "no basic block for exception"); CellTypeState *excStk = excBB->stack(); CellTypeState *cOpStck = stack(); CellTypeState cOpStck_0 = cOpStck[0]; @@ -1803,6 +1805,7 @@ void GenerateOopMap::do_monitorexit(int bci) { // possibility that this bytecode will throw an // exception. BasicBlock* bb = get_basic_block_containing(bci); + guarantee(bb != NULL, "no basic block for bci"); bb->set_changed(true); bb->_monitor_top = bad_monitors; @@ -2190,6 +2193,7 @@ void GenerateOopMap::result_for_basicblock(int bci) { // Find basicblock and report results BasicBlock* bb = get_basic_block_containing(bci); + guarantee(bb != NULL, "no basic block for bci"); assert(bb->is_reachable(), "getting result from unreachable basicblock"); bb->set_changed(true); interp_bb(bb); diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index fd66a276c8c..e296c501ccb 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -165,7 +165,8 @@ HS_DTRACE_PROBE_DECL5(hotspot, class__initialization__end, volatile int InstanceKlass::_total_instanceKlass_count = 0; -Klass* InstanceKlass::allocate_instance_klass(ClassLoaderData* loader_data, +InstanceKlass* InstanceKlass::allocate_instance_klass( + ClassLoaderData* loader_data, int vtable_len, int itable_len, int static_field_size, @@ -207,10 +208,35 @@ Klass* InstanceKlass::allocate_instance_klass(ClassLoaderData* loader_data, access_flags, is_anonymous); } + // Check for pending exception before adding to the loader data and incrementing + // class count. Can get OOM here. + if (HAS_PENDING_EXCEPTION) { + return NULL; + } + + // Add all classes to our internal class loader list here, + // including classes in the bootstrap (NULL) class loader. + loader_data->add_class(ik); + Atomic::inc(&_total_instanceKlass_count); return ik; } + +// copy method ordering from resource area to Metaspace +void InstanceKlass::copy_method_ordering(intArray* m, TRAPS) { + if (m != NULL) { + // allocate a new array and copy contents (memcpy?) + _method_ordering = MetadataFactory::new_array(class_loader_data(), m->length(), CHECK); + for (int i = 0; i < m->length(); i++) { + _method_ordering->at_put(i, m->at(i)); + } + } else { + _method_ordering = Universe::the_empty_int_array(); + } +} + + InstanceKlass::InstanceKlass(int vtable_len, int itable_len, int static_field_size, @@ -220,72 +246,116 @@ InstanceKlass::InstanceKlass(int vtable_len, bool is_anonymous) { No_Safepoint_Verifier no_safepoint; // until k becomes parsable - int size = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size, - access_flags.is_interface(), is_anonymous); + int iksize = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size, + access_flags.is_interface(), is_anonymous); - // The sizes of these these three variables are used for determining the - // size of the instanceKlassOop. It is critical that these are set to the right - // sizes before the first GC, i.e., when we allocate the mirror. - this->set_vtable_length(vtable_len); - this->set_itable_length(itable_len); - this->set_static_field_size(static_field_size); - this->set_nonstatic_oop_map_size(nonstatic_oop_map_size); - this->set_access_flags(access_flags); - this->set_is_anonymous(is_anonymous); - assert(this->size() == size, "wrong size for object"); + set_vtable_length(vtable_len); + set_itable_length(itable_len); + set_static_field_size(static_field_size); + set_nonstatic_oop_map_size(nonstatic_oop_map_size); + set_access_flags(access_flags); + _misc_flags = 0; // initialize to zero + set_is_anonymous(is_anonymous); + assert(size() == iksize, "wrong size for object"); - this->set_array_klasses(NULL); - this->set_methods(NULL); - this->set_method_ordering(NULL); - this->set_local_interfaces(NULL); - this->set_transitive_interfaces(NULL); - this->init_implementor(); - this->set_fields(NULL, 0); - this->set_constants(NULL); - this->set_class_loader_data(NULL); - this->set_protection_domain(NULL); - this->set_signers(NULL); - this->set_source_file_name(NULL); - this->set_source_debug_extension(NULL, 0); - this->set_array_name(NULL); - this->set_inner_classes(NULL); - this->set_static_oop_field_count(0); - this->set_nonstatic_field_size(0); - this->set_is_marked_dependent(false); - this->set_init_state(InstanceKlass::allocated); - this->set_init_thread(NULL); - this->set_init_lock(NULL); - this->set_reference_type(rt); - this->set_oop_map_cache(NULL); - this->set_jni_ids(NULL); - this->set_osr_nmethods_head(NULL); - this->set_breakpoints(NULL); - this->init_previous_versions(); - this->set_generic_signature(NULL); - this->release_set_methods_jmethod_ids(NULL); - this->release_set_methods_cached_itable_indices(NULL); - this->set_annotations(NULL); - this->set_jvmti_cached_class_field_map(NULL); - this->set_initial_method_idnum(0); + set_array_klasses(NULL); + set_methods(NULL); + set_method_ordering(NULL); + set_local_interfaces(NULL); + set_transitive_interfaces(NULL); + init_implementor(); + set_fields(NULL, 0); + set_constants(NULL); + set_class_loader_data(NULL); + set_protection_domain(NULL); + set_signers(NULL); + set_source_file_name(NULL); + set_source_debug_extension(NULL, 0); + set_array_name(NULL); + set_inner_classes(NULL); + set_static_oop_field_count(0); + set_nonstatic_field_size(0); + set_is_marked_dependent(false); + set_init_state(InstanceKlass::allocated); + set_init_thread(NULL); + set_init_lock(NULL); + set_reference_type(rt); + set_oop_map_cache(NULL); + set_jni_ids(NULL); + set_osr_nmethods_head(NULL); + set_breakpoints(NULL); + init_previous_versions(); + set_generic_signature(NULL); + release_set_methods_jmethod_ids(NULL); + release_set_methods_cached_itable_indices(NULL); + set_annotations(NULL); + set_jvmti_cached_class_field_map(NULL); + set_initial_method_idnum(0); + _dependencies = NULL; + set_jvmti_cached_class_field_map(NULL); + set_cached_class_file(NULL, 0); + set_initial_method_idnum(0); + set_minor_version(0); + set_major_version(0); + NOT_PRODUCT(_verify_count = 0;) // initialize the non-header words to zero intptr_t* p = (intptr_t*)this; - for (int index = InstanceKlass::header_size(); index < size; index++) { + for (int index = InstanceKlass::header_size(); index < iksize; index++) { p[index] = NULL_WORD; } // Set temporary value until parseClassFile updates it with the real instance // size. - this->set_layout_helper(Klass::instance_layout_helper(0, true)); + set_layout_helper(Klass::instance_layout_helper(0, true)); } +void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data, + Array* methods) { + if (methods != NULL && methods != Universe::the_empty_method_array()) { + for (int i = 0; i < methods->length(); i++) { + Method* method = methods->at(i); + if (method == NULL) continue; // maybe null if error processing + // Only want to delete methods that are not executing for RedefineClasses. + // The previous version will point to them so they're not totally dangling + assert (!method->on_stack(), "shouldn't be called with methods on stack"); + MetadataFactory::free_metadata(loader_data, method); + } + MetadataFactory::free_array(loader_data, methods); + } +} + +void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data, + Klass* super_klass, + Array* local_interfaces, + Array* transitive_interfaces) { + // Only deallocate transitive interfaces if not empty, same as super class + // or same as local interfaces. See code in parseClassFile. + Array* ti = transitive_interfaces; + if (ti != Universe::the_empty_klass_array() && ti != local_interfaces) { + // check that the interfaces don't come from super class + Array* sti = (super_klass == NULL) ? NULL : + InstanceKlass::cast(super_klass)->transitive_interfaces(); + if (ti != sti) { + MetadataFactory::free_array(loader_data, ti); + } + } + + // local interfaces can be empty + if (local_interfaces != Universe::the_empty_klass_array()) { + MetadataFactory::free_array(loader_data, local_interfaces); + } +} + // This function deallocates the metadata and C heap pointers that the // InstanceKlass points to. void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { // Orphan the mirror first, CMS thinks it's still live. - java_lang_Class::set_klass(java_mirror(), NULL); + if (java_mirror() != NULL) { + java_lang_Class::set_klass(java_mirror(), NULL); + } // Need to take this class off the class loader data list. loader_data->remove_class(this); @@ -300,17 +370,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { // reference counting symbol names. release_C_heap_structures(); - Array* ms = methods(); - if (ms != Universe::the_empty_method_array()) { - for (int i = 0; i <= methods()->length() -1 ; i++) { - Method* method = methods()->at(i); - // Only want to delete methods that are not executing for RedefineClasses. - // The previous version will point to them so they're not totally dangling - assert (!method->on_stack(), "shouldn't be called with methods on stack"); - MetadataFactory::free_metadata(loader_data, method); - } - MetadataFactory::free_array(loader_data, methods()); - } + deallocate_methods(loader_data, methods()); set_methods(NULL); if (method_ordering() != Universe::the_empty_int_array()) { @@ -327,24 +387,8 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { } set_secondary_supers(NULL); - // Only deallocate transitive interfaces if not empty, same as super class - // or same as local interfaces. See code in parseClassFile. - Array* ti = transitive_interfaces(); - if (ti != Universe::the_empty_klass_array() && ti != local_interfaces()) { - // check that the interfaces don't come from super class - Array* sti = (super() == NULL) ? NULL : - InstanceKlass::cast(super())->transitive_interfaces(); - if (ti != sti) { - MetadataFactory::free_array(loader_data, ti); - } - } + deallocate_interfaces(loader_data, super(), local_interfaces(), transitive_interfaces()); set_transitive_interfaces(NULL); - - // local interfaces can be empty - Array* li = local_interfaces(); - if (li != Universe::the_empty_klass_array()) { - MetadataFactory::free_array(loader_data, li); - } set_local_interfaces(NULL); MetadataFactory::free_array(loader_data, fields()); @@ -352,9 +396,11 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { // If a method from a redefined class is using this constant pool, don't // delete it, yet. The new class's previous version will point to this. - assert (!constants()->on_stack(), "shouldn't be called if anything is onstack"); - MetadataFactory::free_metadata(loader_data, constants()); - set_constants(NULL); + if (constants() != NULL) { + assert (!constants()->on_stack(), "shouldn't be called if anything is onstack"); + MetadataFactory::free_metadata(loader_data, constants()); + set_constants(NULL); + } if (inner_classes() != Universe::the_empty_short_array()) { MetadataFactory::free_array(loader_data, inner_classes()); @@ -2785,7 +2831,7 @@ void InstanceKlass::print_on(outputStream* st) const { st->print(BULLET"protection domain: "); ((InstanceKlass*)this)->protection_domain()->print_value_on(st); st->cr(); st->print(BULLET"host class: "); host_klass()->print_value_on_maybe_null(st); st->cr(); st->print(BULLET"signers: "); signers()->print_value_on(st); st->cr(); - st->print(BULLET"init_lock: "); ((oop)init_lock())->print_value_on(st); st->cr(); + st->print(BULLET"init_lock: "); ((oop)_init_lock)->print_value_on(st); st->cr(); if (source_file_name() != NULL) { st->print(BULLET"source file: "); source_file_name()->print_value_on(st); diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index ef2f446d14f..9d94b2436d9 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -147,7 +147,8 @@ class InstanceKlass: public Klass { AccessFlags access_flags, bool is_anonymous); public: - static Klass* allocate_instance_klass(ClassLoaderData* loader_data, + static InstanceKlass* allocate_instance_klass( + ClassLoaderData* loader_data, int vtable_len, int itable_len, int static_field_size, @@ -266,9 +267,10 @@ class InstanceKlass: public Klass { u1 _init_state; // state of class u1 _reference_type; // reference type - JvmtiCachedClassFieldMap* _jvmti_cached_class_field_map; // JVMTI: used during heap iteration + NOT_PRODUCT(int _verify_count;) // to avoid redundant verifies + // Method array. Array* _methods; // Interface (Klass*s) this class declares locally to implement. @@ -356,16 +358,19 @@ class InstanceKlass: public Klass { // method ordering Array* method_ordering() const { return _method_ordering; } void set_method_ordering(Array* m) { _method_ordering = m; } + void copy_method_ordering(intArray* m, TRAPS); // interfaces Array* local_interfaces() const { return _local_interfaces; } void set_local_interfaces(Array* a) { guarantee(_local_interfaces == NULL || a == NULL, "Just checking"); _local_interfaces = a; } + Array* transitive_interfaces() const { return _transitive_interfaces; } void set_transitive_interfaces(Array* a) { guarantee(_transitive_interfaces == NULL || a == NULL, "Just checking"); - _transitive_interfaces = a; } + _transitive_interfaces = a; + } private: friend class fieldDescriptor; @@ -381,10 +386,9 @@ class InstanceKlass: public Klass { int java_fields_count() const { return (int)_java_fields_count; } Array* fields() const { return _fields; } - void set_fields(Array* f, u2 java_fields_count) { guarantee(_fields == NULL || f == NULL, "Just checking"); - _fields = f; + _fields = f; _java_fields_count = java_fields_count; } @@ -588,7 +592,7 @@ class InstanceKlass: public Klass { // symbol unloading support (refcount already added) Symbol* array_name() { return _array_name; } - void set_array_name(Symbol* name) { assert(_array_name == NULL, "name already created"); _array_name = name; } + void set_array_name(Symbol* name) { assert(_array_name == NULL || name == NULL, "name already created"); _array_name = name; } // nonstatic oop-map blocks static int nonstatic_oop_map_size(unsigned int oop_map_count) { @@ -914,8 +918,15 @@ class InstanceKlass: public Klass { void clean_method_data(BoolObjectClosure* is_alive); // Explicit metaspace deallocation of fields - // For RedefineClasses, we need to deallocate instanceKlasses + // For RedefineClasses and class file parsing errors, we need to deallocate + // instanceKlasses and the metadata they point to. void deallocate_contents(ClassLoaderData* loader_data); + static void deallocate_methods(ClassLoaderData* loader_data, + Array* methods); + void static deallocate_interfaces(ClassLoaderData* loader_data, + Klass* super_klass, + Array* local_interfaces, + Array* transitive_interfaces); // The constant pool is on stack if any of the methods are executing or // referenced by handles. diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp index 341f60c3fe8..06c644c3478 100644 --- a/hotspot/src/share/vm/oops/klass.cpp +++ b/hotspot/src/share/vm/oops/klass.cpp @@ -146,16 +146,16 @@ void* Klass::operator new(size_t size, ClassLoaderData* loader_data, size_t word Klass::Klass() { Klass* k = this; - { // Preinitialize supertype information. - // A later call to initialize_supers() may update these settings: - set_super(NULL); - for (juint i = 0; i < Klass::primary_super_limit(); i++) { - _primary_supers[i] = NULL; - } - set_secondary_supers(NULL); - _primary_supers[0] = k; - set_super_check_offset(in_bytes(primary_supers_offset())); + // Preinitialize supertype information. + // A later call to initialize_supers() may update these settings: + set_super(NULL); + for (juint i = 0; i < Klass::primary_super_limit(); i++) { + _primary_supers[i] = NULL; } + set_secondary_supers(NULL); + set_secondary_super_cache(NULL); + _primary_supers[0] = k; + set_super_check_offset(in_bytes(primary_supers_offset())); set_java_mirror(NULL); set_modifier_flags(0); @@ -486,6 +486,12 @@ void Klass::oops_do(OopClosure* cl) { } void Klass::remove_unshareable_info() { + if (!DumpSharedSpaces) { + // Clean up after OOM during class loading + if (class_loader_data() != NULL) { + class_loader_data()->remove_class(this); + } + } set_subklass(NULL); set_next_sibling(NULL); // Clear the java mirror diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index 803f4da2737..d2a41914653 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.hpp @@ -79,7 +79,6 @@ // [last_biased_lock_bulk_revocation_time] (64 bits) // [prototype_header] // [biased_lock_revocation_count] -// [verify_count ] - not in product // [alloc_count ] // [_modified_oops] // [_accumulated_modified_oops] @@ -172,10 +171,6 @@ class Klass : public Metadata { markOop _prototype_header; // Used when biased locking is both enabled and disabled for this type jint _biased_lock_revocation_count; -#ifndef PRODUCT - int _verify_count; // to avoid redundant verifies -#endif - juint _alloc_count; // allocation profiling support TRACE_DEFINE_KLASS_TRACE_ID; diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index bb9a5115693..11ddd21f1f6 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -77,22 +77,19 @@ Method* Method::allocate(ClassLoaderData* loader_data, return new (loader_data, size, false, THREAD) Method(cm, access_flags, size); } -Method::Method(ConstMethod* xconst, - AccessFlags access_flags, int size) { +Method::Method(ConstMethod* xconst, AccessFlags access_flags, int size) { No_Safepoint_Verifier no_safepoint; set_constMethod(xconst); set_access_flags(access_flags); set_method_size(size); - set_name_index(0); - set_signature_index(0); #ifdef CC_INTERP set_result_index(T_VOID); #endif - set_constants(NULL); - set_max_stack(0); - set_max_locals(0); set_intrinsic_id(vmIntrinsics::_none); set_jfr_towrite(false); + set_force_inline(false); + set_hidden(false); + set_dont_inline(false); set_method_data(NULL); set_interpreter_throwout_count(0); set_vtable_index(Method::garbage_vtable_index); @@ -801,7 +798,15 @@ void Method::unlink_method() { backedge_counter()->reset(); _adapter = NULL; _from_compiled_entry = NULL; - assert(_method_data == NULL, "unexpected method data?"); + + // In case of DumpSharedSpaces, _method_data should always be NULL. + // + // During runtime (!DumpSharedSpaces), when we are cleaning a + // shared class that failed to load, this->link_method() may + // have already been called (before an exception happened), so + // this->_method_data may not be NULL. + assert(!DumpSharedSpaces || _method_data == NULL, "unexpected method data?"); + set_method_data(NULL); set_interpreter_throwout_count(0); set_interpreter_invocation_count(0); diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp index c7a200f9e47..c9687fb32b6 100644 --- a/hotspot/src/share/vm/oops/methodData.cpp +++ b/hotspot/src/share/vm/oops/methodData.cpp @@ -652,23 +652,25 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) { // Set the method back-pointer. _method = method(); - if (TieredCompilation) { - _invocation_counter.init(); - _backedge_counter.init(); - _invocation_counter_start = 0; - _backedge_counter_start = 0; - _num_loops = 0; - _num_blocks = 0; - _highest_comp_level = 0; - _highest_osr_comp_level = 0; - _would_profile = true; - } + _invocation_counter.init(); + _backedge_counter.init(); + _invocation_counter_start = 0; + _backedge_counter_start = 0; + _num_loops = 0; + _num_blocks = 0; + _highest_comp_level = 0; + _highest_osr_comp_level = 0; + _would_profile = true; set_creation_mileage(mileage_of(method())); // Initialize flags and trap history. _nof_decompiles = 0; _nof_overflow_recompiles = 0; _nof_overflow_traps = 0; + _eflags = 0; + _arg_local = 0; + _arg_stack = 0; + _arg_returned = 0; assert(sizeof(_trap_hist) % sizeof(HeapWord) == 0, "align"); Copy::zero_to_words((HeapWord*) &_trap_hist, sizeof(_trap_hist) / sizeof(HeapWord)); @@ -677,6 +679,7 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) { // corresponding data cells. int data_size = 0; int empty_bc_count = 0; // number of bytecodes lacking data + _data[0] = 0; // apparently not set below. BytecodeStream stream(method); Bytecodes::Code c; while ((c = stream.next()) >= 0) { @@ -710,6 +713,7 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) { post_initialize(&stream); set_size(object_size); + } // Get a measure of how much mileage the method has on it. diff --git a/hotspot/src/share/vm/opto/bytecodeInfo.cpp b/hotspot/src/share/vm/opto/bytecodeInfo.cpp index 155bc47e9cf..6d8f1b3da91 100644 --- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp +++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp @@ -157,9 +157,10 @@ bool InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_method, } else { // Not hot. Check for medium-sized pre-existing nmethod at cold sites. if (callee_method->has_compiled_code() && - callee_method->instructions_size() > inline_small_code_size) + callee_method->instructions_size() > inline_small_code_size) { set_msg("already compiled into a medium method"); return false; + } } if (size > max_inline_size) { if (max_inline_size > default_max_inline_size) { diff --git a/hotspot/src/share/vm/opto/chaitin.hpp b/hotspot/src/share/vm/opto/chaitin.hpp index 340e46d49b1..fc8010b851e 100644 --- a/hotspot/src/share/vm/opto/chaitin.hpp +++ b/hotspot/src/share/vm/opto/chaitin.hpp @@ -187,31 +187,6 @@ public: #endif }; -//------------------------------LRG_List--------------------------------------- -// Map Node indices to Live RanGe indices. -// Array lookup in the optimized case. -class LRG_List : public ResourceObj { - friend class VMStructs; - uint _cnt, _max; - uint* _lidxs; - ReallocMark _nesting; // assertion check for reallocations -public: - LRG_List( uint max ); - - uint lookup( uint nidx ) const { - return _lidxs[nidx]; - } - uint operator[] (uint nidx) const { return lookup(nidx); } - - void map( uint nidx, uint lidx ) { - assert( nidx < _cnt, "oob" ); - _lidxs[nidx] = lidx; - } - void extend( uint nidx, uint lidx ); - - uint Size() const { return _cnt; } -}; - //------------------------------IFG-------------------------------------------- // InterFerence Graph // An undirected graph implementation. Created with a fixed number of diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 568af91f127..a4657819c44 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -892,7 +892,7 @@ Compile::Compile( ciEnv* ci_env, : Phase(Compiler), _env(ci_env), _log(ci_env->log()), - _compile_id(-1), + _compile_id(0), _save_argument_registers(save_arg_registers), _method(NULL), _stub_name(stub_name), diff --git a/hotspot/src/share/vm/opto/live.hpp b/hotspot/src/share/vm/opto/live.hpp index c7714fecc4f..8a266c19067 100644 --- a/hotspot/src/share/vm/opto/live.hpp +++ b/hotspot/src/share/vm/opto/live.hpp @@ -33,11 +33,35 @@ #include "opto/regmask.hpp" class Block; -class LRG_List; class PhaseCFG; class VectorSet; class IndexSet; +//------------------------------LRG_List--------------------------------------- +// Map Node indices to Live RanGe indices. +// Array lookup in the optimized case. +class LRG_List : public ResourceObj { + friend class VMStructs; + uint _cnt, _max; + uint* _lidxs; + ReallocMark _nesting; // assertion check for reallocations +public: + LRG_List( uint max ); + + uint lookup( uint nidx ) const { + return _lidxs[nidx]; + } + uint operator[] (uint nidx) const { return lookup(nidx); } + + void map( uint nidx, uint lidx ) { + assert( nidx < _cnt, "oob" ); + _lidxs[nidx] = lidx; + } + void extend( uint nidx, uint lidx ); + + uint Size() const { return _cnt; } +}; + //------------------------------PhaseLive-------------------------------------- // Compute live-in/live-out class PhaseLive : public Phase { diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index b405bbcf6ba..c438cf9b880 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -888,6 +888,7 @@ void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_ CountedLoopNode *main_head = loop->_head->as_CountedLoop(); assert( main_head->is_normal_loop(), "" ); CountedLoopEndNode *main_end = main_head->loopexit(); + guarantee(main_end != NULL, "no loop exit node"); assert( main_end->outcnt() == 2, "1 true, 1 false path only" ); uint dd_main_head = dom_depth(main_head); uint max = main_head->outcnt(); @@ -2554,13 +2555,16 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st ok.set(store->_idx); ok.set(store->in(MemNode::Memory)->_idx); + CountedLoopEndNode* loop_exit = head->loopexit(); + guarantee(loop_exit != NULL, "no loop exit node"); + // Loop structure is ok ok.set(head->_idx); - ok.set(head->loopexit()->_idx); + ok.set(loop_exit->_idx); ok.set(head->phi()->_idx); ok.set(head->incr()->_idx); - ok.set(head->loopexit()->cmp_node()->_idx); - ok.set(head->loopexit()->in(1)->_idx); + ok.set(loop_exit->cmp_node()->_idx); + ok.set(loop_exit->in(1)->_idx); // Address elements are ok if (con) ok.set(con->_idx); @@ -2572,7 +2576,7 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st if (n->outcnt() == 0) continue; // Ignore dead if (ok.test(n->_idx)) continue; // Backedge projection is ok - if (n->is_IfTrue() && n->in(0) == head->loopexit()) continue; + if (n->is_IfTrue() && n->in(0) == loop_exit) continue; if (!n->is_AddP()) { msg = "unhandled node"; msg_node = n; @@ -2585,7 +2589,7 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st Node* n = lpt->_body.at(i); // These values can be replaced with other nodes if they are used // outside the loop. - if (n == store || n == head->loopexit() || n == head->incr() || n == store->in(MemNode::Memory)) continue; + if (n == store || n == loop_exit || n == head->incr() || n == store->in(MemNode::Memory)) continue; for (SimpleDUIterator iter(n); iter.has_next(); iter.next()) { Node* use = iter.get(); if (!lpt->_body.contains(use)) { diff --git a/hotspot/src/share/vm/opto/loopnode.hpp b/hotspot/src/share/vm/opto/loopnode.hpp index 104d7b78722..c45ea8421f1 100644 --- a/hotspot/src/share/vm/opto/loopnode.hpp +++ b/hotspot/src/share/vm/opto/loopnode.hpp @@ -603,7 +603,10 @@ class PhaseIdealLoop : public PhaseTransform { } public: - bool has_node( Node* n ) const { return _nodes[n->_idx] != NULL; } + bool has_node( Node* n ) const { + guarantee(n != NULL, "No Node."); + return _nodes[n->_idx] != NULL; + } // check if transform created new nodes that need _ctrl recorded Node *get_late_ctrl( Node *n, Node *early ); Node *get_early_ctrl( Node *n ); @@ -737,7 +740,8 @@ private: return n; } uint dom_depth(Node* d) const { - assert(d->_idx < _idom_size, ""); + guarantee(d != NULL, "Null dominator info."); + guarantee(d->_idx < _idom_size, ""); return _dom_depth[d->_idx]; } void set_idom(Node* d, Node* n, uint dom_depth); diff --git a/hotspot/src/share/vm/opto/loopopts.cpp b/hotspot/src/share/vm/opto/loopopts.cpp index 31f080dbf7b..1db82d4ceb1 100644 --- a/hotspot/src/share/vm/opto/loopopts.cpp +++ b/hotspot/src/share/vm/opto/loopopts.cpp @@ -232,7 +232,11 @@ void PhaseIdealLoop::dominated_by( Node *prevdom, Node *iff, bool flip, bool exc // Loop predicates may have depending checks which should not // be skipped. For example, range check predicate has two checks // for lower and upper bounds. - ProjNode* unc_proj = iff->as_If()->proj_out(1 - dp->as_Proj()->_con)->as_Proj(); + if (dp == NULL) + return; + + ProjNode* dp_proj = dp->as_Proj(); + ProjNode* unc_proj = iff->as_If()->proj_out(1 - dp_proj->_con)->as_Proj(); if (exclude_loop_predicate && is_uncommon_trap_proj(unc_proj, Deoptimization::Reason_predicate)) return; // Let IGVN transformation change control dependence. @@ -866,8 +870,11 @@ void PhaseIdealLoop::split_if_with_blocks_post( Node *n ) { // Now split the bool up thru the phi Node *bolphi = split_thru_phi( bol, n_ctrl, -1 ); + guarantee(bolphi != NULL, "null boolean phi node"); + _igvn.replace_node( bol, bolphi ); assert( iff->in(1) == bolphi, "" ); + if( bolphi->Value(&_igvn)->singleton() ) return; @@ -1628,6 +1635,7 @@ ProjNode* PhaseIdealLoop::proj_clone(ProjNode* p, IfNode* iff) { //------------------------------ short_circuit_if ------------------------------------- // Force the iff control output to be the live_proj Node* PhaseIdealLoop::short_circuit_if(IfNode* iff, ProjNode* live_proj) { + guarantee(live_proj != NULL, "null projection"); int proj_con = live_proj->_con; assert(proj_con == 0 || proj_con == 1, "false or true projection"); Node *con = _igvn.intcon(proj_con); @@ -1686,6 +1694,7 @@ ProjNode* PhaseIdealLoop::insert_if_before_proj(Node* left, bool Signed, BoolTes set_idom(proj, new_if, ddepth); ProjNode* new_exit = proj_clone(other_proj, new_if)->as_Proj(); + guarantee(new_exit != NULL, "null exit node"); register_node(new_exit, get_loop(other_proj), new_if, ddepth); return new_exit; @@ -1793,7 +1802,10 @@ IfNode* PhaseIdealLoop::insert_cmpi_loop_exit(IfNode* if_cmpu, IdealLoopTree *lo int stride = stride_of_possible_iv(if_cmpu); if (stride == 0) return NULL; - ProjNode* lp_continue = stay_in_loop(if_cmpu, loop)->as_Proj(); + Node* lp_proj = stay_in_loop(if_cmpu, loop); + guarantee(lp_proj != NULL, "null loop node"); + + ProjNode* lp_continue = lp_proj->as_Proj(); ProjNode* lp_exit = if_cmpu->proj_out(!lp_continue->is_IfTrue())->as_Proj(); Node* limit = NULL; @@ -1805,6 +1817,7 @@ IfNode* PhaseIdealLoop::insert_cmpi_loop_exit(IfNode* if_cmpu, IdealLoopTree *lo } // Create a new region on the exit path RegionNode* reg = insert_region_before_proj(lp_exit); + guarantee(reg != NULL, "null region node"); // Clone the if-cmpu-true-false using a signed compare BoolTest::mask rel_i = stride > 0 ? bol->_test._test : BoolTest::ge; diff --git a/hotspot/src/share/vm/opto/output.cpp b/hotspot/src/share/vm/opto/output.cpp index b0d7a9948ea..c77b9f60c5e 100644 --- a/hotspot/src/share/vm/opto/output.cpp +++ b/hotspot/src/share/vm/opto/output.cpp @@ -2518,6 +2518,7 @@ void Scheduling::DoScheduling() { // Schedule the remaining instructions in the block while ( _available.size() > 0 ) { Node *n = ChooseNodeToBundle(); + guarantee(n != NULL, "no nodes available"); AddNodeToBundle(n,bb); } diff --git a/hotspot/src/share/vm/opto/type.cpp b/hotspot/src/share/vm/opto/type.cpp index 3928c23aff3..68f681342d9 100644 --- a/hotspot/src/share/vm/opto/type.cpp +++ b/hotspot/src/share/vm/opto/type.cpp @@ -4193,6 +4193,7 @@ const TypeOopPtr* TypeKlassPtr::as_instance_type() const { bool xk = klass_is_exact(); //return TypeInstPtr::make(TypePtr::NotNull, k, xk, NULL, 0); const TypeOopPtr* toop = TypeOopPtr::make_from_klass_raw(k); + guarantee(toop != NULL, "need type for given klass"); toop = toop->cast_to_ptr_type(TypePtr::NotNull)->is_oopptr(); return toop->cast_to_exactness(xk)->is_oopptr(); } diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index f45568a7ca7..22716c400c2 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -92,7 +92,7 @@ # include "os_bsd.inline.hpp" #endif -static jint CurrentVersion = JNI_VERSION_1_6; +static jint CurrentVersion = JNI_VERSION_1_8; // The DT_RETURN_MARK macros create a scoped object to fire the dtrace diff --git a/hotspot/src/share/vm/prims/jni.h b/hotspot/src/share/vm/prims/jni.h index a67c2e540f3..582f2c97024 100644 --- a/hotspot/src/share/vm/prims/jni.h +++ b/hotspot/src/share/vm/prims/jni.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1951,6 +1951,7 @@ JNI_OnUnload(JavaVM *vm, void *reserved); #define JNI_VERSION_1_2 0x00010002 #define JNI_VERSION_1_4 0x00010004 #define JNI_VERSION_1_6 0x00010006 +#define JNI_VERSION_1_8 0x00010008 #ifdef __cplusplus } /* extern "C" */ diff --git a/hotspot/src/share/vm/prims/jvmtiImpl.cpp b/hotspot/src/share/vm/prims/jvmtiImpl.cpp index 4a1747e1bd2..c569b8fdcb4 100644 --- a/hotspot/src/share/vm/prims/jvmtiImpl.cpp +++ b/hotspot/src/share/vm/prims/jvmtiImpl.cpp @@ -890,7 +890,7 @@ void JvmtiSuspendControl::print() { tty->print("Suspended Threads: ["); for (JavaThread *thread = Threads::first(); thread != NULL; thread = thread->next()) { -#if JVMTI_TRACE +#ifdef JVMTI_TRACE const char *name = JvmtiTrace::safe_get_thread_name(thread); #else const char *name = ""; diff --git a/hotspot/src/share/vm/prims/jvmtiTrace.hpp b/hotspot/src/share/vm/prims/jvmtiTrace.hpp index b6d42249776..6be50d8ade8 100644 --- a/hotspot/src/share/vm/prims/jvmtiTrace.hpp +++ b/hotspot/src/share/vm/prims/jvmtiTrace.hpp @@ -43,10 +43,10 @@ // Support tracing except in product build on the client compiler #ifndef PRODUCT -#define JVMTI_TRACE 1 +#define JVMTI_TRACE #else #ifdef COMPILER2 -#define JVMTI_TRACE 1 +#define JVMTI_TRACE #endif #endif diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index db634c621b3..a2bcb956249 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1381,6 +1381,40 @@ bool Arguments::should_auto_select_low_pause_collector() { return false; } +void Arguments::set_use_compressed_oops() { +#ifndef ZERO +#ifdef _LP64 + // MaxHeapSize is not set up properly at this point, but + // the only value that can override MaxHeapSize if we are + // to use UseCompressedOops is InitialHeapSize. + size_t max_heap_size = MAX2(MaxHeapSize, InitialHeapSize); + + if (max_heap_size <= max_heap_for_compressed_oops()) { +#if !defined(COMPILER1) || defined(TIERED) + if (FLAG_IS_DEFAULT(UseCompressedOops)) { + FLAG_SET_ERGO(bool, UseCompressedOops, true); + } +#endif +#ifdef _WIN64 + if (UseLargePages && UseCompressedOops) { + // Cannot allocate guard pages for implicit checks in indexed addressing + // mode, when large pages are specified on windows. + // This flag could be switched ON if narrow oop base address is set to 0, + // see code in Universe::initialize_heap(). + Universe::set_narrow_oop_use_implicit_null_checks(false); + } +#endif // _WIN64 + } else { + if (UseCompressedOops && !FLAG_IS_DEFAULT(UseCompressedOops)) { + warning("Max heap size too large for Compressed Oops"); + FLAG_SET_DEFAULT(UseCompressedOops, false); + FLAG_SET_DEFAULT(UseCompressedKlassPointers, false); + } + } +#endif // _LP64 +#endif // ZERO +} + void Arguments::set_ergonomics_flags() { if (os::is_server_class_machine()) { @@ -1410,30 +1444,7 @@ void Arguments::set_ergonomics_flags() { #ifndef ZERO #ifdef _LP64 - // Check that UseCompressedOops can be set with the max heap size allocated - // by ergonomics. - if (MaxHeapSize <= max_heap_for_compressed_oops()) { -#if !defined(COMPILER1) || defined(TIERED) - if (FLAG_IS_DEFAULT(UseCompressedOops)) { - FLAG_SET_ERGO(bool, UseCompressedOops, true); - } -#endif -#ifdef _WIN64 - if (UseLargePages && UseCompressedOops) { - // Cannot allocate guard pages for implicit checks in indexed addressing - // mode, when large pages are specified on windows. - // This flag could be switched ON if narrow oop base address is set to 0, - // see code in Universe::initialize_heap(). - Universe::set_narrow_oop_use_implicit_null_checks(false); - } -#endif // _WIN64 - } else { - if (UseCompressedOops && !FLAG_IS_DEFAULT(UseCompressedOops)) { - warning("Max heap size too large for Compressed Oops"); - FLAG_SET_DEFAULT(UseCompressedOops, false); - FLAG_SET_DEFAULT(UseCompressedKlassPointers, false); - } - } + set_use_compressed_oops(); // UseCompressedOops must be on for UseCompressedKlassPointers to be on. if (!UseCompressedOops) { if (UseCompressedKlassPointers) { @@ -1813,6 +1824,13 @@ void Arguments::check_deprecated_gcs() { } } +void Arguments::check_deprecated_gc_flags() { + if (FLAG_IS_CMDLINE(MaxGCMinorPauseMillis)) { + warning("Using MaxGCMinorPauseMillis as minor pause goal is deprecated" + "and will likely be removed in future release"); + } +} + // Check stack pages settings bool Arguments::check_stack_pages() { @@ -2273,10 +2291,12 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, } #if !INCLUDE_JVMTI if ((strcmp(name, "hprof") == 0) || (strcmp(name, "jdwp") == 0)) { - warning("profiling and debugging agents are not supported in this VM"); - } else + jio_fprintf(defaultStream::error_stream(), + "Profiling and debugging agents are not supported in this VM\n"); + return JNI_ERR; + } #endif // !INCLUDE_JVMTI - add_init_library(name, options); + add_init_library(name, options); } // -agentlib and -agentpath } else if (match_option(option, "-agentlib:", &tail) || @@ -2293,16 +2313,19 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, } #if !INCLUDE_JVMTI if ((strcmp(name, "hprof") == 0) || (strcmp(name, "jdwp") == 0)) { - warning("profiling and debugging agents are not supported in this VM"); - } else + jio_fprintf(defaultStream::error_stream(), + "Profiling and debugging agents are not supported in this VM\n"); + return JNI_ERR; + } #endif // !INCLUDE_JVMTI add_init_agent(name, options, is_absolute_path); - } // -javaagent } else if (match_option(option, "-javaagent:", &tail)) { #if !INCLUDE_JVMTI - warning("Instrumentation agents are not supported in this VM"); + jio_fprintf(defaultStream::error_stream(), + "Instrumentation agents are not supported in this VM\n"); + return JNI_ERR; #else if(tail != NULL) { char *options = strcpy(NEW_C_HEAP_ARRAY(char, strlen(tail) + 1, mtInternal), tail); @@ -2443,8 +2466,9 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, #if INCLUDE_FPROF _has_profile = true; #else // INCLUDE_FPROF - // do we have to exit? - warning("Flat profiling is not supported in this VM."); + jio_fprintf(defaultStream::error_stream(), + "Flat profiling is not supported in this VM.\n"); + return JNI_ERR; #endif // INCLUDE_FPROF // -Xaprof } else if (match_option(option, "-Xaprof", &tail)) { @@ -2478,8 +2502,9 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, #if INCLUDE_MANAGEMENT FLAG_SET_CMDLINE(bool, ManagementServer, true); #else - vm_exit_during_initialization( - "-Dcom.sun.management is not supported in this VM.", NULL); + jio_fprintf(defaultStream::output_stream(), + "-Dcom.sun.management is not supported in this VM.\n"); + return JNI_ERR; #endif } // -Xint @@ -2492,16 +2517,10 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, } else if (match_option(option, "-Xcomp", &tail)) { // for testing the compiler; turn off all flags that inhibit compilation set_mode_flags(_comp); - // -Xshare:dump } else if (match_option(option, "-Xshare:dump", &tail)) { -#if !INCLUDE_CDS - vm_exit_during_initialization( - "Dumping a shared archive is not supported in this VM.", NULL); -#else FLAG_SET_CMDLINE(bool, DumpSharedSpaces, true); set_mode_flags(_int); // Prevent compilation, which creates objects -#endif // -Xshare:on } else if (match_option(option, "-Xshare:on", &tail)) { FLAG_SET_CMDLINE(bool, UseSharedSpaces, true); @@ -2514,7 +2533,6 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, } else if (match_option(option, "-Xshare:off", &tail)) { FLAG_SET_CMDLINE(bool, UseSharedSpaces, false); FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false); - // -Xverify } else if (match_option(option, "-Xverify", &tail)) { if (strcmp(tail, ":all") == 0 || strcmp(tail, "") == 0) { @@ -2828,8 +2846,9 @@ SOLARIS_ONLY( FLAG_SET_CMDLINE(bool, UseVMInterruptibleIO, true); #if !INCLUDE_MANAGEMENT } else if (match_option(option, "-XX:+ManagementServer", &tail)) { - vm_exit_during_initialization( - "ManagementServer is not supported in this VM.", NULL); + jio_fprintf(defaultStream::error_stream(), + "ManagementServer is not supported in this VM.\n"); + return JNI_ERR; #endif // INCLUDE_MANAGEMENT } else if (match_option(option, "-XX:", &tail)) { // -XX:xxxx // Skip -XX:Flags= since that case has already been handled @@ -3135,7 +3154,9 @@ jint Arguments::parse(const JavaVMInitArgs* args) { #if INCLUDE_NMT MemTracker::init_tracking_options(tail); #else - warning("Native Memory Tracking is not supported in this VM"); + jio_fprintf(defaultStream::error_stream(), + "Native Memory Tracking is not supported in this VM\n"); + return JNI_ERR; #endif } @@ -3254,6 +3275,16 @@ jint Arguments::parse(const JavaVMInitArgs* args) { force_serial_gc(); #endif // INCLUDE_ALL_GCS #if !INCLUDE_CDS + if (DumpSharedSpaces || RequireSharedSpaces) { + jio_fprintf(defaultStream::error_stream(), + "Shared spaces are not supported in this VM\n"); + return JNI_ERR; + } + if ((UseSharedSpaces && FLAG_IS_CMDLINE(UseSharedSpaces)) || PrintSharedSpaces) { + warning("Shared spaces are not supported in this VM"); + FLAG_SET_DEFAULT(UseSharedSpaces, false); + FLAG_SET_DEFAULT(PrintSharedSpaces, false); + } no_shared_spaces(); #endif // INCLUDE_CDS @@ -3292,6 +3323,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) { set_g1_gc_flags(); } check_deprecated_gcs(); + check_deprecated_gc_flags(); #else // INCLUDE_ALL_GCS assert(verify_serial_gc_flags(), "SerialGC unset"); #endif // INCLUDE_ALL_GCS diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index c116e2028bb..d75fc9a82bd 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -309,6 +309,7 @@ class Arguments : AllStatic { // Garbage-First (UseG1GC) static void set_g1_gc_flags(); // GC ergonomics + static void set_use_compressed_oops(); static void set_ergonomics_flags(); static void set_shared_spaces_flags(); // Setup heap size @@ -414,6 +415,7 @@ class Arguments : AllStatic { // Check for consistency in the selection of the garbage collector. static bool check_gc_consistency(); static void check_deprecated_gcs(); + static void check_deprecated_gc_flags(); // Check consistecy or otherwise of VM argument settings static bool check_vm_args_consistency(); // Check stack pages settings diff --git a/hotspot/src/share/vm/runtime/deoptimization.cpp b/hotspot/src/share/vm/runtime/deoptimization.cpp index 8f735b7d6fb..4a8d52b1284 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.cpp +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp @@ -425,6 +425,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread callee_parameters, callee_locals, index == 0, + index == array->frames() - 1, popframe_extra_args); // This pc doesn't have to be perfect just good enough to identify the frame // as interpreted so the skeleton frame will be walkable diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index ef41b35090b..9645f625a85 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -3644,7 +3644,10 @@ class CommandLineFlags { "Enable internal testing APIs") \ \ product(bool, PrintGCCause, true, \ - "Include GC cause in GC logging") + "Include GC cause in GC logging") \ + \ + product(bool, AllowNonVirtualCalls, false, \ + "Obey the ACC_SUPER flag and allow invokenonvirtual calls") /* * Macros for factoring of globals diff --git a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp index 2ba8e159fec..127b5e3169f 100644 --- a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp +++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp @@ -87,7 +87,7 @@ StubCodeGenerator::~StubCodeGenerator() { CodeBuffer* cbuf = _masm->code(); CodeBlob* blob = CodeCache::find_blob_unsafe(cbuf->insts()->start()); if (blob != NULL) { - blob->set_comments(cbuf->comments()); + blob->set_strings(cbuf->strings()); } bool saw_first = false; StubCodeDesc* toprint[1000]; diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index cb883c5d821..322597fe4cc 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -4061,6 +4061,7 @@ jboolean Threads::is_supported_jni_version(jint version) { if (version == JNI_VERSION_1_2) return JNI_TRUE; if (version == JNI_VERSION_1_4) return JNI_TRUE; if (version == JNI_VERSION_1_6) return JNI_TRUE; + if (version == JNI_VERSION_1_8) return JNI_TRUE; return JNI_FALSE; } diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index 98f8d254545..259a4765cf4 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1289,6 +1289,7 @@ class JavaThread: public Thread { void enable_stack_red_zone(); void disable_stack_red_zone(); + inline bool stack_guard_zone_unused(); inline bool stack_yellow_zone_disabled(); inline bool stack_yellow_zone_enabled(); @@ -1759,6 +1760,10 @@ inline CompilerThread* JavaThread::as_CompilerThread() { return (CompilerThread*)this; } +inline bool JavaThread::stack_guard_zone_unused() { + return _stack_guard_state == stack_guard_unused; +} + inline bool JavaThread::stack_yellow_zone_disabled() { return _stack_guard_state == stack_guard_yellow_disabled; } diff --git a/hotspot/src/share/vm/runtime/vframeArray.cpp b/hotspot/src/share/vm/runtime/vframeArray.cpp index d00e9f00954..3fda9e6dc1d 100644 --- a/hotspot/src/share/vm/runtime/vframeArray.cpp +++ b/hotspot/src/share/vm/runtime/vframeArray.cpp @@ -160,6 +160,7 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, int callee_locals, frame* caller, bool is_top_frame, + bool is_bottom_frame, int exec_mode) { JavaThread* thread = (JavaThread*) Thread::current(); @@ -275,7 +276,8 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, callee_locals, caller, iframe(), - is_top_frame); + is_top_frame, + is_bottom_frame); // Update the pc in the frame object and overwrite the temporary pc // we placed in the skeletal frame now that we finally know the @@ -420,6 +422,7 @@ int vframeArrayElement::on_stack_size(int caller_actual_parameters, int callee_parameters, int callee_locals, bool is_top_frame, + bool is_bottom_frame, int popframe_extra_stack_expression_els) const { assert(method()->max_locals() == locals()->size(), "just checking"); int locks = monitors() == NULL ? 0 : monitors()->number_of_monitors(); @@ -431,7 +434,8 @@ int vframeArrayElement::on_stack_size(int caller_actual_parameters, caller_actual_parameters, callee_parameters, callee_locals, - is_top_frame); + is_top_frame, + is_bottom_frame); } @@ -522,7 +526,7 @@ void vframeArray::unpack_to_stack(frame &unpack_frame, int exec_mode, int caller // Do the unpacking of interpreter frames; the frame at index 0 represents the top activation, so it has no callee // Unpack the frames from the oldest (frames() -1) to the youngest (0) - frame caller_frame = me; + frame* caller_frame = &me; for (index = frames() - 1; index >= 0 ; index--) { vframeArrayElement* elem = element(index); // caller int callee_parameters, callee_locals; @@ -542,13 +546,14 @@ void vframeArray::unpack_to_stack(frame &unpack_frame, int exec_mode, int caller elem->unpack_on_stack(caller_actual_parameters, callee_parameters, callee_locals, - &caller_frame, + caller_frame, index == 0, + index == frames() - 1, exec_mode); if (index == frames() - 1) { Deoptimization::unwind_callee_save_values(elem->iframe(), this); } - caller_frame = *elem->iframe(); + caller_frame = elem->iframe(); caller_actual_parameters = callee_parameters; } deallocate_monitor_chunks(); diff --git a/hotspot/src/share/vm/runtime/vframeArray.hpp b/hotspot/src/share/vm/runtime/vframeArray.hpp index b505c35712f..5ebe7b897eb 100644 --- a/hotspot/src/share/vm/runtime/vframeArray.hpp +++ b/hotspot/src/share/vm/runtime/vframeArray.hpp @@ -88,6 +88,7 @@ class vframeArrayElement : public _ValueObj { int on_stack_size(int caller_actual_parameters, int callee_parameters, int callee_locals, + bool is_bottom_frame, bool is_top_frame, int popframe_extra_stack_expression_els) const; @@ -97,6 +98,7 @@ class vframeArrayElement : public _ValueObj { int callee_locals, frame* caller, bool is_top_frame, + bool is_bottom_frame, int exec_mode); #ifndef PRODUCT diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 158060b6958..b3e445f3d9e 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -336,7 +336,6 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; nonstatic_field(Klass, _access_flags, AccessFlags) \ nonstatic_field(Klass, _subklass, Klass*) \ nonstatic_field(Klass, _next_sibling, Klass*) \ - nonproduct_nonstatic_field(Klass, _verify_count, int) \ nonstatic_field(Klass, _alloc_count, juint) \ nonstatic_field(MethodData, _size, int) \ nonstatic_field(MethodData, _method, Method*) \ diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index 949fa2d34f7..ec3e8519968 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp @@ -94,6 +94,7 @@ template(ReportJavaOutOfMemory) \ template(JFRCheckpoint) \ template(Exit) \ + template(LinuxDllLoad) \ class VM_Operation: public CHeapObj { public: diff --git a/hotspot/src/share/vm/runtime/vm_version.cpp b/hotspot/src/share/vm/runtime/vm_version.cpp index ef03c76f62b..322a5b6c03a 100644 --- a/hotspot/src/share/vm/runtime/vm_version.cpp +++ b/hotspot/src/share/vm/runtime/vm_version.cpp @@ -211,6 +211,10 @@ const char* Abstract_VM_Version::internal_vm_info_string() { #define HOTSPOT_BUILD_COMPILER "MS VC++ 8.0 (VS2005)" #elif _MSC_VER == 1500 #define HOTSPOT_BUILD_COMPILER "MS VC++ 9.0 (VS2008)" + #elif _MSC_VER == 1600 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 10.0 (VS2010)" + #elif _MSC_VER == 1700 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 11.0 (VS2012)" #else #define HOTSPOT_BUILD_COMPILER "unknown MS VC++:" XSTR(_MSC_VER) #endif diff --git a/hotspot/src/share/vm/services/memoryService.cpp b/hotspot/src/share/vm/services/memoryService.cpp index 0040f9d96fc..75693dbcf69 100644 --- a/hotspot/src/share/vm/services/memoryService.cpp +++ b/hotspot/src/share/vm/services/memoryService.cpp @@ -240,6 +240,7 @@ MemoryPool* MemoryService::add_cms_space(CompactibleFreeListSpace* space, void MemoryService::add_generation_memory_pool(Generation* gen, MemoryManager* major_mgr, MemoryManager* minor_mgr) { + guarantee(gen != NULL, "No generation for memory pool"); Generation::Name kind = gen->kind(); int index = _pools_list->length(); diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp index 131f08d44bd..e74475fc3c9 100644 --- a/hotspot/src/share/vm/utilities/debug.cpp +++ b/hotspot/src/share/vm/utilities/debug.cpp @@ -248,10 +248,6 @@ void report_should_not_reach_here(const char* file, int line) { report_vm_error(file, line, "ShouldNotReachHere()"); } -void report_should_not_reach_here2(const char* file, int line, const char* message) { - report_vm_error(file, line, "ShouldNotReachHere()", message); -} - void report_unimplemented(const char* file, int line) { report_vm_error(file, line, "Unimplemented()"); } diff --git a/hotspot/src/share/vm/utilities/debug.hpp b/hotspot/src/share/vm/utilities/debug.hpp index 515b1286b98..0c718a2fe2f 100644 --- a/hotspot/src/share/vm/utilities/debug.hpp +++ b/hotspot/src/share/vm/utilities/debug.hpp @@ -192,12 +192,6 @@ do { \ BREAKPOINT; \ } while (0) -#define ShouldNotReachHere2(message) \ -do { \ - report_should_not_reach_here2(__FILE__, __LINE__, message); \ - BREAKPOINT; \ -} while (0) - #define Unimplemented() \ do { \ report_unimplemented(__FILE__, __LINE__); \ @@ -218,7 +212,6 @@ void report_vm_out_of_memory(const char* file, int line, size_t size, const char* message); void report_should_not_call(const char* file, int line); void report_should_not_reach_here(const char* file, int line); -void report_should_not_reach_here2(const char* file, int line, const char* message); void report_unimplemented(const char* file, int line); void report_untested(const char* file, int line, const char* message); diff --git a/hotspot/src/share/vm/utilities/elfFile.cpp b/hotspot/src/share/vm/utilities/elfFile.cpp index 155a78f5d04..9fba1c39cc2 100644 --- a/hotspot/src/share/vm/utilities/elfFile.cpp +++ b/hotspot/src/share/vm/utilities/elfFile.cpp @@ -197,4 +197,28 @@ ElfStringTable* ElfFile::get_string_table(int index) { return NULL; } +#ifdef LINUX +bool ElfFile::specifies_noexecstack() { + Elf_Phdr phdr; + if (!m_file) return true; + + if (!fseek(m_file, m_elfHdr.e_phoff, SEEK_SET)) { + for (int index = 0; index < m_elfHdr.e_phnum; index ++) { + if (fread((void*)&phdr, sizeof(Elf_Phdr), 1, m_file) != 1) { + m_status = NullDecoder::file_invalid; + return false; + } + if (phdr.p_type == PT_GNU_STACK) { + if (phdr.p_flags == (PF_R | PF_W)) { + return true; + } else { + return false; + } + } + } + } + return false; +} +#endif + #endif // _WINDOWS diff --git a/hotspot/src/share/vm/utilities/elfFile.hpp b/hotspot/src/share/vm/utilities/elfFile.hpp index 60f2a880482..d6aa886bbbb 100644 --- a/hotspot/src/share/vm/utilities/elfFile.hpp +++ b/hotspot/src/share/vm/utilities/elfFile.hpp @@ -43,6 +43,7 @@ typedef Elf64_Addr Elf_Addr; typedef Elf64_Ehdr Elf_Ehdr; typedef Elf64_Shdr Elf_Shdr; +typedef Elf64_Phdr Elf_Phdr; typedef Elf64_Sym Elf_Sym; #if !defined(_ALLBSD_SOURCE) || defined(__APPLE__) @@ -59,6 +60,7 @@ typedef Elf32_Addr Elf_Addr; typedef Elf32_Ehdr Elf_Ehdr; typedef Elf32_Shdr Elf_Shdr; +typedef Elf32_Phdr Elf_Phdr; typedef Elf32_Sym Elf_Sym; #if !defined(_ALLBSD_SOURCE) || defined(__APPLE__) @@ -123,6 +125,14 @@ protected: ElfFile* next() const { return m_next; } void set_next(ElfFile* file) { m_next = file; } + public: + // Returns true if the elf file is marked NOT to require an executable stack, + // or if the file could not be opened. + // Returns false if the elf file requires an executable stack, the stack flag + // is not set at all, or if the file can not be read. + // On systems other than linux it always returns false. + bool specifies_noexecstack() NOT_LINUX({ return false; }); + protected: ElfFile* m_next; diff --git a/hotspot/test/compiler/8009761/Test8009761.java b/hotspot/test/compiler/8009761/Test8009761.java new file mode 100644 index 00000000000..c897ab40069 --- /dev/null +++ b/hotspot/test/compiler/8009761/Test8009761.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8009761 + * @summary Deoptimization on sparc doesn't set Llast_SP correctly in the interpreter frames it creates + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation Test8009761 + * + */ + +public class Test8009761 { + + static class UnloadedClass { + volatile int i; + } + + static Object m1(boolean deopt) { + // When running interpreted, on sparc, the caller's stack is + // extended for the locals and the caller's frame is restored + // on return. + long l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, + l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, + l25, l26, l27, l28, l29, l30, l31, l32, l33, l34, l35, l36, + l37, l38, l39, l40, l41, l42, l43, l44, l45, l46, l47, l48, + l49, l50, l51, l52, l53, l54, l55, l56, l57, l58, l59, l60, + l61, l62, l63, l64, l65, l66, l67, l68, l69, l70, l71, l72, + l73, l74, l75, l76, l77, l78, l79, l80, l81, l82, l83, l84, + l85, l86, l87, l88, l89, l90, l91, l92, l93, l94, l95, l96, + l97, l98, l99, l100, l101, l102, l103, l104, l105, l106, l107, + l108, l109, l110, l111, l112, l113, l114, l115, l116, l117, + l118, l119, l120, l121, l122, l123, l124, l125, l126, l127, + l128, l129, l130, l131, l132, l133, l134, l135, l136, l137, + l138, l139, l140, l141, l142, l143, l144, l145, l146, l147, + l148, l149, l150, l151, l152, l153, l154, l155, l156, l157, + l158, l159, l160, l161, l162, l163, l164, l165, l166, l167, + l168, l169, l170, l171, l172, l173, l174, l175, l176, l177, + l178, l179, l180, l181, l182, l183, l184, l185, l186, l187, + l188, l189, l190, l191, l192, l193, l194, l195, l196, l197, + l198, l199, l200, l201, l202, l203, l204, l205, l206, l207, + l208, l209, l210, l211, l212, l213, l214, l215, l216, l217, + l218, l219, l220, l221, l222, l223, l224, l225, l226, l227, + l228, l229, l230, l231, l232, l233, l234, l235, l236, l237, + l238, l239, l240, l241, l242, l243, l244, l245, l246, l247, + l248, l249, l250, l251, l252, l253, l254, l255, l256, l257, + l258, l259, l260, l261, l262, l263, l264, l265, l266, l267, + l268, l269, l270, l271, l272, l273, l274, l275, l276, l277, + l278, l279, l280, l281, l282, l283, l284, l285, l286, l287, + l288, l289, l290, l291, l292, l293, l294, l295, l296, l297, + l298, l299, l300, l301, l302, l303, l304, l305, l306, l307, + l308, l309, l310, l311, l312, l313, l314, l315, l316, l317, + l318, l319, l320, l321, l322, l323, l324, l325, l326, l327, + l328, l329, l330, l331, l332, l333, l334, l335, l336, l337, + l338, l339, l340, l341, l342, l343, l344, l345, l346, l347, + l348, l349, l350, l351, l352, l353, l354, l355, l356, l357, + l358, l359, l360, l361, l362, l363, l364, l365, l366, l367, + l368, l369, l370, l371, l372, l373, l374, l375, l376, l377, + l378, l379, l380, l381, l382, l383, l384, l385, l386, l387, + l388, l389, l390, l391, l392, l393, l394, l395, l396, l397, + l398, l399, l400, l401, l402, l403, l404, l405, l406, l407, + l408, l409, l410, l411, l412, l413, l414, l415, l416, l417, + l418, l419, l420, l421, l422, l423, l424, l425, l426, l427, + l428, l429, l430, l431, l432, l433, l434, l435, l436, l437, + l438, l439, l440, l441, l442, l443, l444, l445, l446, l447, + l448, l449, l450, l451, l452, l453, l454, l455, l456, l457, + l458, l459, l460, l461, l462, l463, l464, l465, l466, l467, + l468, l469, l470, l471, l472, l473, l474, l475, l476, l477, + l478, l479, l480, l481, l482, l483, l484, l485, l486, l487, + l488, l489, l490, l491, l492, l493, l494, l495, l496, l497, + l498, l499, l500, l501, l502, l503, l504, l505, l506, l507, + l508, l509, l510, l511; + + long ll0, ll1, ll2, ll3, ll4, ll5, ll6, ll7, ll8, ll9, ll10, ll11, ll12, + ll13, ll14, ll15, ll16, ll17, ll18, ll19, ll20, ll21, ll22, ll23, ll24, + ll25, ll26, ll27, ll28, ll29, ll30, ll31, ll32, ll33, ll34, ll35, ll36, + ll37, ll38, ll39, ll40, ll41, ll42, ll43, ll44, ll45, ll46, ll47, ll48, + ll49, ll50, ll51, ll52, ll53, ll54, ll55, ll56, ll57, ll58, ll59, ll60, + ll61, ll62, ll63, ll64, ll65, ll66, ll67, ll68, ll69, ll70, ll71, ll72, + ll73, ll74, ll75, ll76, ll77, ll78, ll79, ll80, ll81, ll82, ll83, ll84, + ll85, ll86, ll87, ll88, ll89, ll90, ll91, ll92, ll93, ll94, ll95, ll96, + ll97, ll98, ll99, ll100, ll101, ll102, ll103, ll104, ll105, ll106, ll107, + ll108, ll109, ll110, ll111, ll112, ll113, ll114, ll115, ll116, ll117, + ll118, ll119, ll120, ll121, ll122, ll123, ll124, ll125, ll126, ll127, + ll128, ll129, ll130, ll131, ll132, ll133, ll134, ll135, ll136, ll137, + ll138, ll139, ll140, ll141, ll142, ll143, ll144, ll145, ll146, ll147, + ll148, ll149, ll150, ll151, ll152, ll153, ll154, ll155, ll156, ll157, + ll158, ll159, ll160, ll161, ll162, ll163, ll164, ll165, ll166, ll167, + ll168, ll169, ll170, ll171, ll172, ll173, ll174, ll175, ll176, ll177, + ll178, ll179, ll180, ll181, ll182, ll183, ll184, ll185, ll186, ll187, + ll188, ll189, ll190, ll191, ll192, ll193, ll194, ll195, ll196, ll197, + ll198, ll199, ll200, ll201, ll202, ll203, ll204, ll205, ll206, ll207, + ll208, ll209, ll210, ll211, ll212, ll213, ll214, ll215, ll216, ll217, + ll218, ll219, ll220, ll221, ll222, ll223, ll224, ll225, ll226, ll227, + ll228, ll229, ll230, ll231, ll232, ll233, ll234, ll235, ll236, ll237, + ll238, ll239, ll240, ll241, ll242, ll243, ll244, ll245, ll246, ll247, + ll248, ll249, ll250, ll251, ll252, ll253, ll254, ll255, ll256, ll257, + ll258, ll259, ll260, ll261, ll262, ll263, ll264, ll265, ll266, ll267, + ll268, ll269, ll270, ll271, ll272, ll273, ll274, ll275, ll276, ll277, + ll278, ll279, ll280, ll281, ll282, ll283, ll284, ll285, ll286, ll287, + ll288, ll289, ll290, ll291, ll292, ll293, ll294, ll295, ll296, ll297, + ll298, ll299, ll300, ll301, ll302, ll303, ll304, ll305, ll306, ll307, + ll308, ll309, ll310, ll311, ll312, ll313, ll314, ll315, ll316, ll317, + ll318, ll319, ll320, ll321, ll322, ll323, ll324, ll325, ll326, ll327, + ll328, ll329, ll330, ll331, ll332, ll333, ll334, ll335, ll336, ll337, + ll338, ll339, ll340, ll341, ll342, ll343, ll344, ll345, ll346, ll347, + ll348, ll349, ll350, ll351, ll352, ll353, ll354, ll355, ll356, ll357, + ll358, ll359, ll360, ll361, ll362, ll363, ll364, ll365, ll366, ll367, + ll368, ll369, ll370, ll371, ll372, ll373, ll374, ll375, ll376, ll377, + ll378, ll379, ll380, ll381, ll382, ll383, ll384, ll385, ll386, ll387, + ll388, ll389, ll390, ll391, ll392, ll393, ll394, ll395, ll396, ll397, + ll398, ll399, ll400, ll401, ll402, ll403, ll404, ll405, ll406, ll407, + ll408, ll409, ll410, ll411, ll412, ll413, ll414, ll415, ll416, ll417, + ll418, ll419, ll420, ll421, ll422, ll423, ll424, ll425, ll426, ll427, + ll428, ll429, ll430, ll431, ll432, ll433, ll434, ll435, ll436, ll437, + ll438, ll439, ll440, ll441, ll442, ll443, ll444, ll445, ll446, ll447, + ll448, ll449, ll450, ll451, ll452, ll453, ll454, ll455, ll456, ll457, + ll458, ll459, ll460, ll461, ll462, ll463, ll464, ll465, ll466, ll467, + ll468, ll469, ll470, ll471, ll472, ll473, ll474, ll475, ll476, ll477, + ll478, ll479, ll480, ll481, ll482, ll483, ll484, ll485, ll486, ll487, + ll488, ll489, ll490, ll491, ll492, ll493, ll494, ll495, ll496, ll497, + ll498, ll499, ll500, ll501, ll502, ll503, ll504, ll505, ll506, ll507, + ll508, ll509, ll510, ll511; + + if (deopt) { + UnloadedClass res = new UnloadedClass(); // sufficient to force deopt with c2 but not c1 + res.i = 0; // forces deopt with c1 + return res; + } + return null; + } + + static int count = 0; + + static void m2() { + // Will be called recursively until a stack overflow + // exception. Makes sure it has a lot of locals so that it's + // not called a sufficient number of times to trigger + // compilation. + + long l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, + l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, + l25, l26, l27, l28, l29, l30, l31, l32, l33, l34, l35, l36, + l37, l38, l39, l40, l41, l42, l43, l44, l45, l46, l47, l48, + l49, l50, l51, l52, l53, l54, l55, l56, l57, l58, l59, l60, + l61, l62, l63, l64, l65, l66, l67, l68, l69, l70, l71, l72, + l73, l74, l75, l76, l77, l78, l79, l80, l81, l82, l83, l84, + l85, l86, l87, l88, l89, l90, l91, l92, l93, l94, l95, l96, + l97, l98, l99, l100, l101, l102, l103, l104, l105, l106, l107, + l108, l109, l110, l111, l112, l113, l114, l115, l116, l117, + l118, l119, l120, l121, l122, l123, l124, l125, l126, l127, + l128, l129, l130, l131, l132, l133, l134, l135, l136, l137, + l138, l139, l140, l141, l142, l143, l144, l145, l146, l147, + l148, l149, l150, l151, l152, l153, l154, l155, l156, l157, + l158, l159, l160, l161, l162, l163, l164, l165, l166, l167, + l168, l169, l170, l171, l172, l173, l174, l175, l176, l177, + l178, l179, l180, l181, l182, l183, l184, l185, l186, l187, + l188, l189, l190, l191, l192, l193, l194, l195, l196, l197, + l198, l199, l200, l201, l202, l203, l204, l205, l206, l207, + l208, l209, l210, l211, l212, l213, l214, l215, l216, l217, + l218, l219, l220, l221, l222, l223, l224, l225, l226, l227, + l228, l229, l230, l231, l232, l233, l234, l235, l236, l237, + l238, l239, l240, l241, l242, l243, l244, l245, l246, l247, + l248, l249, l250, l251, l252, l253, l254, l255, l256, l257, + l258, l259, l260, l261, l262, l263, l264, l265, l266, l267, + l268, l269, l270, l271, l272, l273, l274, l275, l276, l277, + l278, l279, l280, l281, l282, l283, l284, l285, l286, l287, + l288, l289, l290, l291, l292, l293, l294, l295, l296, l297, + l298, l299, l300, l301, l302, l303, l304, l305, l306, l307, + l308, l309, l310, l311, l312, l313, l314, l315, l316, l317, + l318, l319, l320, l321, l322, l323, l324, l325, l326, l327, + l328, l329, l330, l331, l332, l333, l334, l335, l336, l337, + l338, l339, l340, l341, l342, l343, l344, l345, l346, l347, + l348, l349, l350, l351, l352, l353, l354, l355, l356, l357, + l358, l359, l360, l361, l362, l363, l364, l365, l366, l367, + l368, l369, l370, l371, l372, l373, l374, l375, l376, l377, + l378, l379, l380, l381, l382, l383, l384, l385, l386, l387, + l388, l389, l390, l391, l392, l393, l394, l395, l396, l397, + l398, l399, l400, l401, l402, l403, l404, l405, l406, l407, + l408, l409, l410, l411, l412, l413, l414, l415, l416, l417, + l418, l419, l420, l421, l422, l423, l424, l425, l426, l427, + l428, l429, l430, l431, l432, l433, l434, l435, l436, l437, + l438, l439, l440, l441, l442, l443, l444, l445, l446, l447, + l448, l449, l450, l451, l452, l453, l454, l455, l456, l457, + l458, l459, l460, l461, l462, l463, l464, l465, l466, l467, + l468, l469, l470, l471, l472, l473, l474, l475, l476, l477, + l478, l479, l480, l481, l482, l483, l484, l485, l486, l487, + l488, l489, l490, l491, l492, l493, l494, l495, l496, l497, + l498, l499, l500, l501, l502, l503, l504, l505, l506, l507, + l508, l509, l510, l511; + + count++; + m2(); + } + + static Object m3(boolean overflow_stack, boolean deopt) { + if (overflow_stack) { + m2(); + return null; + } + Object o = m1(deopt); + if (deopt) { + m2(); + } + return o; + } + + static public void main(String[] args) { + int c1; + // Call m2 from m3 recursively until stack overflow. Count the number of recursive calls. + try { + m3(true, false); + } catch(StackOverflowError soe) { + } + c1 = count; + // Force the compilation of m3() that will inline m1() + for (int i = 0; i < 20000; i++) { + m3(false, false); + } + count = 0; + // Force deoptimization of m3() in m1(), then return from m1() + // to m3(), call recursively m2(). If deoptimization correctly + // built the interpreter stack for m3()/m1() then we should be + // able to call m2() recursively as many times as before. + try { + m3(false, true); + } catch(StackOverflowError soe) { + } + if (c1 != count) { + System.out.println("Failed: init recursive calls: " + c1 + ". After deopt " + count); + System.exit(97); + } else { + System.out.println("PASSED"); + } + } +} diff --git a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java index ebd5a9af45f..02b92815825 100644 --- a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java +++ b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java @@ -35,6 +35,8 @@ public abstract class CompilerWhiteBoxTest { protected static final Method METHOD = getMethod("method"); protected static final int COMPILE_THRESHOLD = Integer.parseInt(getVMOption("CompileThreshold", "10000")); + protected static final boolean BACKGROUND_COMPILATION + = Boolean.valueOf(getVMOption("BackgroundCompilation", "true")); protected static Method getMethod(String name) { try { @@ -45,11 +47,16 @@ public abstract class CompilerWhiteBoxTest { } } - protected static String getVMOption(String name, String defaultValue) { + protected static String getVMOption(String name) { String result; HotSpotDiagnosticMXBean diagnostic = ManagementFactoryHelper.getDiagnosticMXBean(); result = diagnostic.getVMOption(name).getValue(); + return result; + } + + protected static String getVMOption(String name, String defaultValue) { + String result = getVMOption(name); return result == null ? defaultValue : result; } @@ -66,6 +73,7 @@ public abstract class CompilerWhiteBoxTest { } catch (Exception e) { System.out.printf("on exception '%s':", e.getMessage()); printInfo(METHOD); + e.printStackTrace(); throw new RuntimeException(e); } System.out.println("at test's end:"); @@ -100,6 +108,9 @@ public abstract class CompilerWhiteBoxTest { protected static void waitBackgroundCompilation(Method method) throws InterruptedException { + if (!BACKGROUND_COMPILATION) { + return; + } final Object obj = new Object(); synchronized (obj) { for (int i = 0; i < 10; ++i) { @@ -129,13 +140,14 @@ public abstract class CompilerWhiteBoxTest { protected final int compile() { int result = 0; - for (int i = 0; i < COMPILE_THRESHOLD; ++i) { + int count = Math.max(COMPILE_THRESHOLD, 150000); + for (int i = 0; i < count; ++i) { result += method(); } + System.out.println("method was invoked " + count + " times"); return result; } - protected int method() { return 42; } diff --git a/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java b/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java index 7690e6a9071..fdf498c31b4 100644 --- a/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java +++ b/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java @@ -32,12 +32,12 @@ public class DeoptimizeAllTest extends CompilerWhiteBoxTest { public static void main(String[] args) throws Exception { + // to prevent inlining #method into #compile() + WHITE_BOX.setDontInlineMethod(METHOD, true); new DeoptimizeAllTest().runTest(); } protected void test() throws Exception { - // to prevent inlining #method into #compile() - WHITE_BOX.setDontInlineMethod(METHOD, true); compile(); checkCompiled(METHOD); WHITE_BOX.deoptimizeAll(); diff --git a/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java b/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java index bc1c9d67962..7894c524ffa 100644 --- a/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java +++ b/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java @@ -32,12 +32,12 @@ public class DeoptimizeMethodTest extends CompilerWhiteBoxTest { public static void main(String[] args) throws Exception { + // to prevent inlining #method into #compile() + WHITE_BOX.setDontInlineMethod(METHOD, true); new DeoptimizeMethodTest().runTest(); } protected void test() throws Exception { - // to prevent inlining #method into #compile() - WHITE_BOX.setDontInlineMethod(METHOD, true); compile(); checkCompiled(METHOD); WHITE_BOX.deoptimizeMethod(METHOD); diff --git a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java index d0c102f54f0..374d48402fc 100644 --- a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java +++ b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java @@ -44,6 +44,8 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest { } public static void main(String[] args) throws Exception { + // to prevent inlining #method into #compile() + WHITE_BOX.setDontInlineMethod(METHOD, true); new IsMethodCompilableTest().runTest(); } @@ -58,8 +60,6 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest { "Warning: test is not applicable if PerMethodRecompilationCutoff == Inf"); return; } - // to prevent inlining #method into #compile() - WHITE_BOX.setDontInlineMethod(METHOD, true); boolean madeNotCompilable = false; for (long i = 0; i < PER_METHOD_RECOMPILATION_CUTOFF; ++i) { diff --git a/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java b/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java index ad4930b6426..0b9144c407c 100644 --- a/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java +++ b/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java @@ -32,6 +32,8 @@ public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest { public static void main(String[] args) throws Exception { + // to prevent inlining #method into #compile() + WHITE_BOX.setDontInlineMethod(METHOD, true); new MakeMethodNotCompilableTest().runTest(); } diff --git a/hotspot/test/runtime/7107135/Test.java b/hotspot/test/runtime/7107135/Test.java new file mode 100644 index 00000000000..84f3ab3393f --- /dev/null +++ b/hotspot/test/runtime/7107135/Test.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2002-2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 SAP AG. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +class Test { + + static boolean loadLib(String libName){ + try { + System.loadLibrary(libName); + System.out.println("Loaded library "+ libName + "."); + return true; + } catch (SecurityException e) { + System.out.println("loadLibrary(\"" + libName + "\") throws: " + e + "\n"); + } catch (UnsatisfiedLinkError e) { + System.out.println("loadLibrary(\"" + libName + "\") throws: " + e + "\n"); + } + return false; + } + + public static int counter = 1; + + static int Runner() { + counter = counter * -1; + int i = counter; + if(counter < 2) counter += Runner(); + return i; + } + + public static int run() { + try{ + Runner(); + } catch (StackOverflowError e) { + System.out.println("Caught stack overflow error."); + return 0; + } catch (OutOfMemoryError e) { + return 0; + } + return 2; + } + + public static void main(String argv[]) { + loadLib(argv[0]); + System.exit(run()); + } +} diff --git a/hotspot/test/runtime/7107135/Test7107135.sh b/hotspot/test/runtime/7107135/Test7107135.sh new file mode 100644 index 00000000000..6dc91a3039c --- /dev/null +++ b/hotspot/test/runtime/7107135/Test7107135.sh @@ -0,0 +1,98 @@ +#!/bin/sh + +# +# Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011 SAP AG. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +## +## @test Test7107135.sh +## @bug 7107135 +## @summary Stack guard pages lost after loading library with executable stack. +## @run shell Test7107135.sh +## + +if [ "${TESTSRC}" = "" ] +then TESTSRC=. +fi + +if [ "${TESTJAVA}" = "" ] +then + PARENT=`dirname \`which java\`` + TESTJAVA=`dirname ${PARENT}` + echo "TESTJAVA not set, selecting " ${TESTJAVA} + echo "If this is incorrect, try setting the variable manually." +fi + +BIT_FLAG="" + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Linux) + NULL=/dev/null + PS=":" + FS="/" + ;; + *) + NULL=NUL + PS=";" + FS="\\" + echo "Test passed; only valid for Linux" + exit 0; + ;; +esac + +ARCH=`uname -m` + +THIS_DIR=`pwd` + +cp ${TESTSRC}${FS}*.java ${THIS_DIR} +${TESTJAVA}${FS}bin${FS}javac *.java + +gcc -fPIC -shared -c -o test.o -I${TESTJAVA}${FS}include -I${TESTJAVA}${FS}include${FS}linux ${TESTSRC}${FS}test.c +ld -shared -z execstack -o libtest-rwx.so test.o +ld -shared -z noexecstack -o libtest-rw.so test.o + + +LD_LIBRARY_PATH=${THIS_DIR} +echo LD_LIBRARY_PATH = ${LD_LIBRARY_PATH} +export LD_LIBRARY_PATH + +# This should not fail. +echo Check testprogram. Expected to pass: +echo ${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} Test test-rw +${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} Test test-rw + +echo +echo Test changing of stack protection: +echo ${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} Test test-rw +${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} Test test-rwx + +if [ "$?" == "0" ] +then + echo + echo ${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} TestMT test-rwx + ${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} TestMT test-rwx +fi + +exit $? diff --git a/hotspot/test/runtime/7107135/TestMT.java b/hotspot/test/runtime/7107135/TestMT.java new file mode 100644 index 00000000000..edea698ac8c --- /dev/null +++ b/hotspot/test/runtime/7107135/TestMT.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2002-2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 SAP AG. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +class TestMT { + + static boolean loadLib(String libName) { + try { + System.loadLibrary(libName); + System.out.println("Loaded library "+ libName + "."); + return true; + } catch (SecurityException e) { + System.out.println("loadLibrary(\"" + libName + "\") throws: " + e + "\n"); + } catch (UnsatisfiedLinkError e) { + System.out.println("loadLibrary(\"" + libName + "\") throws: " + e + "\n"); + } + return false; + } + + public static int counter = 1; + static int Runner() { + counter = counter * -1; + int i = counter; + if (counter < 2) counter += Runner(); + return i; + } + + public static int run(String msg) { + try { + Runner(); + } catch (StackOverflowError e) { + System.out.println(msg + " caught stack overflow error."); + return 0; + } catch (OutOfMemoryError e) { + return 0; + } + return 2; + } + + public static void main(String argv[]) { + try { + for (int i = 0; i < 20; i++) { + Thread t = new DoStackOverflow("SpawnedThread " + i); + t.start(); + } + run("Main thread"); + loadLib("test-rwx"); + run("Main thread"); + } catch (Exception e) { + System.out.println(e); + } + } + + static class DoStackOverflow extends Thread { + public DoStackOverflow(String name) { + super(name); + } + public void run() { + for (int i = 0; i < 10; ++i) { + TestMT.run(getName()); + yield(); + } + } + } +} diff --git a/hotspot/test/runtime/7107135/test.c b/hotspot/test/runtime/7107135/test.c new file mode 100644 index 00000000000..602063f640e --- /dev/null +++ b/hotspot/test/runtime/7107135/test.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2002-2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 SAP AG. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include +#include "jni.h" +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT jint JNICALL Java_Test_someMethod(JNIEnv *env, jobject mainObject) { + return 3; +} + +#ifdef __cplusplus +} +#endif diff --git a/hotspot/test/runtime/8003985/Test8003985.java b/hotspot/test/runtime/8003985/Test8003985.java new file mode 100644 index 00000000000..5e30f670257 --- /dev/null +++ b/hotspot/test/runtime/8003985/Test8003985.java @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.lang.Class; +import java.lang.String; +import java.lang.System; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CyclicBarrier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import sun.misc.Unsafe; +import sun.misc.Contended; + +/* + * @test + * @bug 8003985 + * @summary Support Contended Annotation - JEP 142 + * + * @run main/othervm -XX:-RestrictContended Test8003985 + */ +public class Test8003985 { + + private static final Unsafe U; + private static int ADDRESS_SIZE; + private static int HEADER_SIZE; + + static { + // steal Unsafe + try { + Field unsafe = Unsafe.class.getDeclaredField("theUnsafe"); + unsafe.setAccessible(true); + U = (Unsafe) unsafe.get(null); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new IllegalStateException(e); + } + + // When running with CompressedOops on 64-bit platform, the address size + // reported by Unsafe is still 8, while the real reference fields are 4 bytes long. + // Try to guess the reference field size with this naive trick. + try { + long off1 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj1")); + long off2 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj2")); + ADDRESS_SIZE = (int) Math.abs(off2 - off1); + HEADER_SIZE = (int) Math.min(off1, off2); + } catch (NoSuchFieldException e) { + ADDRESS_SIZE = -1; + } + } + + static class CompressedOopsClass { + public Object obj1; + public Object obj2; + } + + public static boolean arePaddedPairwise(Class klass, String field1, String field2) throws Exception { + Field f1 = klass.getDeclaredField(field1); + Field f2 = klass.getDeclaredField(field2); + + if (isStatic(f1) != isStatic(f2)) { + return true; // these guys are in naturally disjoint locations + } + + int diff = offset(f1) - offset(f2); + if (diff < 0) { + // f1 is first + return (offset(f2) - (offset(f1) + getSize(f1))) > 64; + } else { + // f2 is first + return (offset(f1) - (offset(f2) + getSize(f2))) > 64; + } + } + + public static boolean isPadded(Class klass, String field1) throws Exception { + Field f1 = klass.getDeclaredField(field1); + + if (isStatic(f1)) { + return offset(f1) > 128 + 64; + } + + return offset(f1) > 64; + } + + public static boolean sameLayout(Class klass1, Class klass2) throws Exception { + for (Field f1 : klass1.getDeclaredFields()) { + Field f2 = klass2.getDeclaredField(f1.getName()); + if (offset(f1) != offset(f2)) { + return false; + } + } + + for (Field f2 : klass1.getDeclaredFields()) { + Field f1 = klass2.getDeclaredField(f2.getName()); + if (offset(f1) != offset(f2)) { + return false; + } + } + + return true; + } + + public static boolean isStatic(Field field) { + return Modifier.isStatic(field.getModifiers()); + } + + public static int offset(Field field) { + if (isStatic(field)) { + return (int) U.staticFieldOffset(field); + } else { + return (int) U.objectFieldOffset(field); + } + } + + public static int getSize(Field field) { + Class type = field.getType(); + if (type == byte.class) { return 1; } + if (type == boolean.class) { return 1; } + if (type == short.class) { return 2; } + if (type == char.class) { return 2; } + if (type == int.class) { return 4; } + if (type == float.class) { return 4; } + if (type == long.class) { return 8; } + if (type == double.class) { return 8; } + return ADDRESS_SIZE; + } + + public static void main(String[] args) throws Exception { + boolean endResult = true; + + // --------------- INSTANCE FIELDS --------------------- + + if (arePaddedPairwise(Test1.class, "int1", "int2") || + isPadded(Test1.class, "int1") || + isPadded(Test1.class, "int2")) { + System.err.println("Test1 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test2.class, "int1", "int2") || + !isPadded(Test2.class, "int1") || + isPadded(Test2.class, "int2")) { + System.err.println("Test2 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test3.class, "int1", "int2") || + !isPadded(Test3.class, "int1") || + !isPadded(Test3.class, "int2")) { + System.err.println("Test3 failed"); + endResult &= false; + } + + if (arePaddedPairwise(Test4.class, "int1", "int2") || + !isPadded(Test4.class, "int1") || + !isPadded(Test4.class, "int2")) { + System.err.println("Test4 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test5.class, "int1", "int2") || + !isPadded(Test5.class, "int1") || + !isPadded(Test5.class, "int2")) { + System.err.println("Test5 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test6.class, "int1", "int2") || + !isPadded(Test6.class, "int1") || + !isPadded(Test6.class, "int2")) { + System.err.println("Test6 failed"); + endResult &= false; + } + + if (arePaddedPairwise(Test7.class, "int1", "int2") || + !isPadded(Test7.class, "int1") || + !isPadded(Test7.class, "int2")) { + System.err.println("Test7 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test8.class, "int1", "int2") || + !isPadded(Test8.class, "int1") || + !isPadded(Test8.class, "int2")) { + System.err.println("Test8 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test9.class, "int1", "int2") || + !isPadded(Test9.class, "int1") || + !isPadded(Test9.class, "int2")) { + System.err.println("Test9 failed"); + endResult &= false; + } + + if (!sameLayout(Test4.class, Test7.class)) { + System.err.println("Test4 and Test7 have different layouts"); + endResult &= false; + } + + if (!sameLayout(Test5.class, Test6.class)) { + System.err.println("Test5 and Test6 have different layouts"); + endResult &= false; + } + + if (!sameLayout(Test8.class, Test9.class)) { + System.err.println("Test8 and Test9 have different layouts"); + endResult &= false; + } + + System.out.println(endResult ? "Test PASSES" : "Test FAILS"); + if (!endResult) { + throw new Error("Test failed"); + } + } + + // ----------------------------------- INSTANCE FIELDS ----------------------------------------- + + // naturally packed + public static class Test1 { + private int int1; + private int int2; + } + + // int1 is padded + public static class Test2 { + @Contended private int int1; + private int int2; + } + + // both fields are padded + public static class Test3 { + @Contended private int int1; + @Contended private int int2; + } + + // fields are padded in the singular group + public static class Test4 { + @Contended("sameGroup") private int int1; + @Contended("sameGroup") private int int2; + } + + // fields are padded in disjoint groups + public static class Test5 { + @Contended("diffGroup1") private int int1; + @Contended("diffGroup2") private int int2; + } + + // fields are padded in disjoint groups + public static class Test6 { + @Contended private int int1; + @Contended("diffGroup2") private int int2; + } + + // fields are padded in the singular group + @Contended + public static class Test7 { + private int int1; + private int int2; + } + + // all fields are padded as the group, and one field is padded specifically + @Contended + public static class Test8 { + @Contended private int int1; + private int int2; + } + + // all fields are padded as the group, and one field is padded specifically + @Contended + public static class Test9 { + @Contended("group") private int int1; + private int int2; + } + +} + diff --git a/jaxp/.hgtags b/jaxp/.hgtags index fa256974249..0c78beb6716 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -202,3 +202,5 @@ ff0b73a6b3f6cea644d37d56d746a37743419fa7 jdk8-b75 00958c5a7070bd578aa8b70773cb3f204a9c1be1 jdk8-b78 58fa065dd5d663d62f85402461388fb7a92656fa jdk8-b79 4873a0499bc3bd263b7dd3b551a2b4e275ab5a0b jdk8-b80 +ef3495555a4c6e706a3058c18aa229b14220de0b jdk8-b81 +d5a58291f09a5081eaf22c2a6ab2f9ced4b78882 jdk8-b82 diff --git a/jaxp/src/com/sun/org/apache/xpath/internal/functions/FuncSystemProperty.java b/jaxp/src/com/sun/org/apache/xpath/internal/functions/FuncSystemProperty.java index 316e2a1b3af..1fbcc878c6a 100644 --- a/jaxp/src/com/sun/org/apache/xpath/internal/functions/FuncSystemProperty.java +++ b/jaxp/src/com/sun/org/apache/xpath/internal/functions/FuncSystemProperty.java @@ -165,7 +165,7 @@ public class FuncSystemProperty extends FunctionOneArg * should already be fully qualified as path/filename * @param target The target property bag the file will be placed into. */ - public void loadPropertyFile(String file, Properties target) + private void loadPropertyFile(String file, Properties target) { try { diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 06142f221c5..e02bdee2151 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -202,3 +202,5 @@ c4853f3f0e89ac60aa5b517f5f224f0f60e08577 jdk8-b76 391de4c992d1960a09cdd340362ff936bac69323 jdk8-b78 70d8658d2a3063bc13127f3452af017d838f1362 jdk8-b79 b0224010e2f0c2474055ac592c8d3f37b9264690 jdk8-b80 +c88bb21560ccf1a9e6d2a2ba08ed2045a002676f jdk8-b81 +d8d8032d02d77fbf5f9b3bb8df73663f42fd4dd0 jdk8-b82 diff --git a/jdk/.hgtags b/jdk/.hgtags index 92fe10a1d9a..787670c7d60 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -203,3 +203,5 @@ b2fc8e31cecc35b76188e821d4c5dc0e0b74ac24 jdk8-b77 c933505d75c2a0a671f06d6dac5d2237a9228d2d jdk8-b79 dfb40f066c6ce129822f0f5dc2ac89173808781a jdk8-b80 c0f8022eba536dcdc8aae659005b33f3982b9368 jdk8-b81 +624bcb4800065c6656171948e31ebb2925f25c7a jdk8-b82 +ac519af51769e92c51b597a730974e8607357709 jdk8-b83 diff --git a/jdk/make/com/sun/org/apache/xml/Makefile b/jdk/make/com/sun/org/apache/xml/Makefile index f00135d8d1e..b3568e40482 100644 --- a/jdk/make/com/sun/org/apache/xml/Makefile +++ b/jdk/make/com/sun/org/apache/xml/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,8 @@ JAVAC_MAX_WARNINGS = true JAVAC_WARNINGS_FATAL = true include $(BUILDDIR)/common/Defs.gmk +JAVAC_LINT_OPTIONS += -Xlint:-overrides + # # Files to compile # diff --git a/jdk/make/javax/others/Makefile b/jdk/make/javax/others/Makefile index b122c2063f5..7ee115142f4 100644 --- a/jdk/make/javax/others/Makefile +++ b/jdk/make/javax/others/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,8 @@ JAVAC_WARNINGS_FATAL = true include $(BUILDDIR)/common/Defs.gmk +JAVAC_LINT_OPTIONS += -Xlint:-deprecation + # # Files to compile # diff --git a/jdk/make/sun/xawt/FILES_c_unix.gmk b/jdk/make/sun/xawt/FILES_c_unix.gmk index 0ce8bdd11f5..74ea1cd2ced 100644 --- a/jdk/make/sun/xawt/FILES_c_unix.gmk +++ b/jdk/make/sun/xawt/FILES_c_unix.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -76,6 +76,7 @@ FILES_c = \ debug_trace.c \ debug_util.c \ awt_Plugin.c \ + gnome_interface.c \ gtk2_interface.c \ swing_GTKEngine.c \ swing_GTKStyle.c \ diff --git a/jdk/makefiles/CompileNativeLibraries.gmk b/jdk/makefiles/CompileNativeLibraries.gmk index 790a456ab98..3bcf2fd6a9b 100644 --- a/jdk/makefiles/CompileNativeLibraries.gmk +++ b/jdk/makefiles/CompileNativeLibraries.gmk @@ -843,6 +843,7 @@ LIBAWT_XAWT_FILES:=\ debug_trace.c \ debug_util.c \ awt_Plugin.c \ + gnome_interface.c \ gtk2_interface.c \ swing_GTKEngine.c \ swing_GTKStyle.c \ @@ -2663,11 +2664,8 @@ BUILD_LIBRARIES += $(BUILD_LIBJ2PKCS11) ########################################################################################## -ifndef DISABLE_INTREE_EC -# -# TODO Set DISABLE_INTREE_EC in configure if src/share/native/sun/security/ec/impl -# is not present -# +ifeq ($(ENABLE_INTREE_EC),yes) + BUILD_LIBSUNEC_FLAGS:= -I$(JDK_TOPDIR)/src/share/native/sun/security/ec \ -I$(JDK_TOPDIR)/src/share/native/sun/security/ec/impl diff --git a/jdk/src/macosx/classes/com/apple/laf/AquaButtonBorder.java b/jdk/src/macosx/classes/com/apple/laf/AquaButtonBorder.java index b45b0ce6b98..80ccd72a00b 100644 --- a/jdk/src/macosx/classes/com/apple/laf/AquaButtonBorder.java +++ b/jdk/src/macosx/classes/com/apple/laf/AquaButtonBorder.java @@ -83,14 +83,19 @@ public abstract class AquaButtonBorder extends AquaBorder implements Border, UIR painter.state.set(state); painter.state.set((state != State.DISABLED && state != State.INACTIVE) && b.isFocusPainted() && isFocused(b) ? Focused.YES : Focused.NO); + // Full border size of the component. + // g.setColor(new Color(0, 255, 0, 70)); + // g.drawRect(x, y, width - 1, height - 1); + final Insets subInsets = sizeVariant.insets; x += subInsets.left; y += subInsets.top; width -= (subInsets.left + subInsets.right); height -= (subInsets.top + subInsets.bottom); -// g.setColor(Color.magenta); -// g.drawRect(x, y, width - 1, height - 1); + // Where the native border should start to paint. + // g.setColor(new Color(255, 0, 255, 70)); + // g.drawRect(x, y, width - 1, height - 1); doButtonPaint(b, model, g, x, y, width, height); } diff --git a/jdk/src/macosx/classes/com/apple/laf/AquaButtonExtendedTypes.java b/jdk/src/macosx/classes/com/apple/laf/AquaButtonExtendedTypes.java index 14350ada2a1..a370dc59932 100644 --- a/jdk/src/macosx/classes/com/apple/laf/AquaButtonExtendedTypes.java +++ b/jdk/src/macosx/classes/com/apple/laf/AquaButtonExtendedTypes.java @@ -184,30 +184,30 @@ public class AquaButtonExtendedTypes { new BorderDefinedTypeSpecifier("round", Widget.BUTTON_ROUND, new SizeVariant().alterInsets(2, 0, 0, 0).alterMinSize(28, 28), -3, -3, -3, -3), new BorderDefinedTypeSpecifier("texturedRound", Widget.BUTTON_ROUND_INSET, new SizeVariant().alterInsets(0, 0, 0, 0).alterMinSize(26, 26), -2, -2, 0, 0), - new SegmentedBorderDefinedTypeSpecifier("segmented-first", Widget.BUTTON_SEGMENTED, SegmentPosition.FIRST, new SizeVariant().alterMargins(6, 16, 6, 10).alterInsets(5, 3, 5, 0).alterMinSize(0, 28), 0, -3, 0, -3), - new SegmentedBorderDefinedTypeSpecifier("segmented-middle", Widget.BUTTON_SEGMENTED, SegmentPosition.MIDDLE, new SizeVariant().alterMargins(6, 9, 6, 10).alterInsets(5, 0, 5, 0).alterMinSize(0, 28), 0, -3, 0, -3), - new SegmentedBorderDefinedTypeSpecifier("segmented-last", Widget.BUTTON_SEGMENTED, SegmentPosition.LAST, new SizeVariant().alterMargins(6, 9, 6, 16).alterInsets(5, 0, 5, 3).alterMinSize(0, 28), 0, -3, 0, -3), - new SegmentedBorderDefinedTypeSpecifier("segmented-only", Widget.BUTTON_SEGMENTED, SegmentPosition.ONLY, new SizeVariant().alterMargins(6, 16, 6, 16).alterInsets(5, 3, 5, 3).alterMinSize(34, 28), 0, -3, 0, -3), + new SegmentedBorderDefinedTypeSpecifier("segmented-first", Widget.BUTTON_SEGMENTED, SegmentPosition.FIRST, new SizeVariant().alterMargins(6, 16, 6, 10).alterInsets(2, 3, 2, 0).alterMinSize(0, 28), 0, -3, 0, -3), + new SegmentedBorderDefinedTypeSpecifier("segmented-middle", Widget.BUTTON_SEGMENTED, SegmentPosition.MIDDLE, new SizeVariant().alterMargins(6, 9, 6, 10).alterInsets(2, 0, 2, 0).alterMinSize(0, 28), 0, -3, 0, -3), + new SegmentedBorderDefinedTypeSpecifier("segmented-last", Widget.BUTTON_SEGMENTED, SegmentPosition.LAST, new SizeVariant().alterMargins(6, 9, 6, 16).alterInsets(2, 0, 2, 3).alterMinSize(0, 28), 0, -3, 0, -3), + new SegmentedBorderDefinedTypeSpecifier("segmented-only", Widget.BUTTON_SEGMENTED, SegmentPosition.ONLY, new SizeVariant().alterMargins(6, 16, 6, 16).alterInsets(2, 3, 2, 3).alterMinSize(34, 28), 0, -3, 0, -3), - new SegmentedBorderDefinedTypeSpecifier("segmentedRoundRect-first", Widget.BUTTON_SEGMENTED_INSET, SegmentPosition.FIRST, new SizeVariant().alterMargins(6, 12, 6, 8).alterInsets(5, 2, 5, 0).alterMinSize(0, 28), 0, -3, 0, -3), - new SegmentedBorderDefinedTypeSpecifier("segmentedRoundRect-middle", Widget.BUTTON_SEGMENTED_INSET, SegmentPosition.MIDDLE, new SizeVariant().alterMargins(6, 8, 6, 8).alterInsets(5, 0, 5, 0).alterMinSize(0, 28), 0, -3, 0, -3), - new SegmentedBorderDefinedTypeSpecifier("segmentedRoundRect-last", Widget.BUTTON_SEGMENTED_INSET, SegmentPosition.LAST, new SizeVariant().alterMargins(6, 8, 6, 12).alterInsets(5, 0, 5, 2).alterMinSize(0, 28), 0, -3, 0, -3), - new SegmentedBorderDefinedTypeSpecifier("segmentedRoundRect-only", Widget.BUTTON_SEGMENTED_INSET, SegmentPosition.ONLY, new SizeVariant().alterMargins(6, 12, 6, 12).alterInsets(5, 2, 5, 2).alterMinSize(0, 28), 0, -3, 0, -3), + new SegmentedBorderDefinedTypeSpecifier("segmentedRoundRect-first", Widget.BUTTON_SEGMENTED_INSET, SegmentPosition.FIRST, new SizeVariant().alterMargins(6, 12, 6, 8).alterInsets(2, 2, 2, 0).alterMinSize(0, 28), 0, -3, 0, -3), + new SegmentedBorderDefinedTypeSpecifier("segmentedRoundRect-middle", Widget.BUTTON_SEGMENTED_INSET, SegmentPosition.MIDDLE, new SizeVariant().alterMargins(6, 8, 6, 8).alterInsets(2, 0, 2, 0).alterMinSize(0, 28), 0, -3, 0, -3), + new SegmentedBorderDefinedTypeSpecifier("segmentedRoundRect-last", Widget.BUTTON_SEGMENTED_INSET, SegmentPosition.LAST, new SizeVariant().alterMargins(6, 8, 6, 12).alterInsets(2, 0, 2, 2).alterMinSize(0, 28), 0, -3, 0, -3), + new SegmentedBorderDefinedTypeSpecifier("segmentedRoundRect-only", Widget.BUTTON_SEGMENTED_INSET, SegmentPosition.ONLY, new SizeVariant().alterMargins(6, 12, 6, 12).alterInsets(2, 2, 2, 2).alterMinSize(0, 28), 0, -3, 0, -3), - new SegmentedBorderDefinedTypeSpecifier("segmentedTexturedRounded-first", Widget.BUTTON_SEGMENTED_SCURVE, SegmentPosition.FIRST, new SizeVariant().alterMargins(6, 12, 6, 8).alterInsets(5, 2, 5, 0).alterMinSize(0, 28), 0, -3, 0, -3), - new SegmentedBorderDefinedTypeSpecifier("segmentedTexturedRounded-middle", Widget.BUTTON_SEGMENTED_SCURVE, SegmentPosition.MIDDLE, new SizeVariant().alterMargins(6, 8, 6, 8).alterInsets(5, 0, 5, 0).alterMinSize(0, 28), 0, -3, 0, -3), - new SegmentedBorderDefinedTypeSpecifier("segmentedTexturedRounded-last", Widget.BUTTON_SEGMENTED_SCURVE, SegmentPosition.LAST, new SizeVariant().alterMargins(6, 8, 6, 12).alterInsets(5, 0, 5, 2).alterMinSize(0, 28), 0, -3, 0, -3), - new SegmentedBorderDefinedTypeSpecifier("segmentedTexturedRounded-only", Widget.BUTTON_SEGMENTED_SCURVE, SegmentPosition.ONLY, new SizeVariant().alterMargins(6, 12, 6, 12).alterInsets(5, 2, 5, 2).alterMinSize(0, 28), 0, -3, 0, -3), + new SegmentedBorderDefinedTypeSpecifier("segmentedTexturedRounded-first", Widget.BUTTON_SEGMENTED_SCURVE, SegmentPosition.FIRST, new SizeVariant().alterMargins(6, 12, 6, 8).alterInsets(2, 2, 2, 0).alterMinSize(0, 28), 0, -3, 0, -3), + new SegmentedBorderDefinedTypeSpecifier("segmentedTexturedRounded-middle", Widget.BUTTON_SEGMENTED_SCURVE, SegmentPosition.MIDDLE, new SizeVariant().alterMargins(6, 8, 6, 8).alterInsets(2, 0, 2, 0).alterMinSize(0, 28), 0, -3, 0, -3), + new SegmentedBorderDefinedTypeSpecifier("segmentedTexturedRounded-last", Widget.BUTTON_SEGMENTED_SCURVE, SegmentPosition.LAST, new SizeVariant().alterMargins(6, 8, 6, 12).alterInsets(2, 0, 2, 2).alterMinSize(0, 28), 0, -3, 0, -3), + new SegmentedBorderDefinedTypeSpecifier("segmentedTexturedRounded-only", Widget.BUTTON_SEGMENTED_SCURVE, SegmentPosition.ONLY, new SizeVariant().alterMargins(6, 12, 6, 12).alterInsets(2, 2, 2, 2).alterMinSize(0, 28), 0, -3, 0, -3), - new SegmentedBorderDefinedTypeSpecifier("segmentedTextured-first", Widget.BUTTON_SEGMENTED_TEXTURED, SegmentPosition.FIRST, new SizeVariant().alterMargins(6, 12, 6, 8).alterInsets(6, 3, 6, 0).alterMinSize(0, 28), 0, -3, 0, -3), - new SegmentedBorderDefinedTypeSpecifier("segmentedTextured-middle", Widget.BUTTON_SEGMENTED_TEXTURED, SegmentPosition.MIDDLE, new SizeVariant().alterMargins(6, 8, 6, 8).alterInsets(6, 0, 6, 0).alterMinSize(0, 28), 0, -3, 0, -3), - new SegmentedBorderDefinedTypeSpecifier("segmentedTextured-last", Widget.BUTTON_SEGMENTED_TEXTURED, SegmentPosition.LAST, new SizeVariant().alterMargins(6, 8, 6, 12).alterInsets(6, 0, 6, 3).alterMinSize(0, 28), 0, -3, 0, -3), - new SegmentedBorderDefinedTypeSpecifier("segmentedTextured-only", Widget.BUTTON_SEGMENTED_TEXTURED, SegmentPosition.ONLY, new SizeVariant().alterMargins(6, 12, 6, 12).alterInsets(6, 3, 6, 3).alterMinSize(0, 28), 0, -3, 0, -3), + new SegmentedBorderDefinedTypeSpecifier("segmentedTextured-first", Widget.BUTTON_SEGMENTED_TEXTURED, SegmentPosition.FIRST, new SizeVariant().alterMargins(6, 12, 6, 8).alterInsets(2, 3, 2, 0).alterMinSize(0, 28), 0, -3, 0, -3), + new SegmentedBorderDefinedTypeSpecifier("segmentedTextured-middle", Widget.BUTTON_SEGMENTED_TEXTURED, SegmentPosition.MIDDLE, new SizeVariant().alterMargins(6, 8, 6, 8).alterInsets(2, 0, 2, 0).alterMinSize(0, 28), 0, -3, 0, -3), + new SegmentedBorderDefinedTypeSpecifier("segmentedTextured-last", Widget.BUTTON_SEGMENTED_TEXTURED, SegmentPosition.LAST, new SizeVariant().alterMargins(6, 8, 6, 12).alterInsets(2, 0, 2, 3).alterMinSize(0, 28), 0, -3, 0, -3), + new SegmentedBorderDefinedTypeSpecifier("segmentedTextured-only", Widget.BUTTON_SEGMENTED_TEXTURED, SegmentPosition.ONLY, new SizeVariant().alterMargins(6, 12, 6, 12).alterInsets(2, 3, 2, 3).alterMinSize(0, 28), 0, -3, 0, -3), - new SegmentedBorderDefinedTypeSpecifier("segmentedCapsule-first", Widget.BUTTON_SEGMENTED_TOOLBAR, SegmentPosition.FIRST, new SizeVariant().alterMargins(6, 12, 6, 8).alterInsets(5, 2, 5, 0).alterMinSize(0, 28), 0, 0, 0, 0), - new SegmentedBorderDefinedTypeSpecifier("segmentedCapsule-middle", Widget.BUTTON_SEGMENTED_TOOLBAR, SegmentPosition.MIDDLE, new SizeVariant().alterMargins(6, 8, 6, 8).alterInsets(5, 0, 5, 0).alterMinSize(0, 28), 0, 0, 0, 0), - new SegmentedBorderDefinedTypeSpecifier("segmentedCapsule-last", Widget.BUTTON_SEGMENTED_TOOLBAR, SegmentPosition.LAST, new SizeVariant().alterMargins(6, 8, 6, 12).alterInsets(5, 0, 5, 2).alterMinSize(0, 28), 0, 0, 0, 0), - new SegmentedBorderDefinedTypeSpecifier("segmentedCapsule-only", Widget.BUTTON_SEGMENTED_TOOLBAR, SegmentPosition.ONLY, new SizeVariant().alterMargins(6, 12, 6, 12).alterInsets(5, 2, 5, 2).alterMinSize(34, 28), 0, 0, 0, 0), + new SegmentedBorderDefinedTypeSpecifier("segmentedCapsule-first", Widget.BUTTON_SEGMENTED_TOOLBAR, SegmentPosition.FIRST, new SizeVariant().alterMargins(6, 12, 6, 8).alterInsets(2, 2, 2, 0).alterMinSize(0, 28), 0, 0, 0, 0), + new SegmentedBorderDefinedTypeSpecifier("segmentedCapsule-middle", Widget.BUTTON_SEGMENTED_TOOLBAR, SegmentPosition.MIDDLE, new SizeVariant().alterMargins(6, 8, 6, 8).alterInsets(2, 0, 2, 0).alterMinSize(0, 28), 0, 0, 0, 0), + new SegmentedBorderDefinedTypeSpecifier("segmentedCapsule-last", Widget.BUTTON_SEGMENTED_TOOLBAR, SegmentPosition.LAST, new SizeVariant().alterMargins(6, 8, 6, 12).alterInsets(2, 0, 2, 2).alterMinSize(0, 28), 0, 0, 0, 0), + new SegmentedBorderDefinedTypeSpecifier("segmentedCapsule-only", Widget.BUTTON_SEGMENTED_TOOLBAR, SegmentPosition.ONLY, new SizeVariant().alterMargins(6, 12, 6, 12).alterInsets(2, 2, 2, 2).alterMinSize(34, 28), 0, 0, 0, 0), new BorderDefinedTypeSpecifier("segmentedGradient-first", Widget.BUTTON_BEVEL_INSET, new SizeVariant(18, 18).alterMargins(4, 5, 4, 5).replaceInsets(new Insets(-2,-0,-2,-0))), new BorderDefinedTypeSpecifier("segmentedGradient-middle", Widget.BUTTON_BEVEL_INSET, new SizeVariant(18, 18).alterMargins(4, 5, 4, 5).replaceInsets(new Insets(-2,-1,-2,-0))), diff --git a/jdk/src/macosx/native/sun/awt/CGraphicsDevice.m b/jdk/src/macosx/native/sun/awt/CGraphicsDevice.m index 1e2df28dd56..230569dbafd 100644 --- a/jdk/src/macosx/native/sun/awt/CGraphicsDevice.m +++ b/jdk/src/macosx/native/sun/awt/CGraphicsDevice.m @@ -49,6 +49,42 @@ static int getBPPFromModeString(CFStringRef mode) return 0; } +static BOOL isValidDisplayMode(CGDisplayModeRef mode){ + return (1 < CGDisplayModeGetWidth(mode) && 1 < CGDisplayModeGetHeight(mode)); +} + +static CFMutableArrayRef getAllValidDisplayModes(jint displayID){ + CFArrayRef allModes = CGDisplayCopyAllDisplayModes(displayID, NULL); + + CFIndex numModes = CFArrayGetCount(allModes); + CFMutableArrayRef validModes = CFArrayCreateMutable(kCFAllocatorDefault, numModes + 1, NULL); + + CFIndex n; + for (n=0; n < numModes; n++) { + CGDisplayModeRef cRef = (CGDisplayModeRef) CFArrayGetValueAtIndex(allModes, n); + if (cRef != NULL && isValidDisplayMode(cRef)) { + CFArrayAppendValue(validModes, cRef); + } + } + + CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(displayID); + + BOOL containsCurrentMode = NO; + numModes = CFArrayGetCount(validModes); + for (n=0; n < numModes; n++) { + if(CFArrayGetValueAtIndex(validModes, n) == currentMode){ + containsCurrentMode = YES; + break; + } + } + + if (!containsCurrentMode) { + CFArrayAppendValue(validModes, currentMode); + } + + return validModes; +} + /* * Find the best possible match in the list of display modes that we can switch to based on * the provided parameters. @@ -198,28 +234,30 @@ Java_sun_awt_CGraphicsDevice_nativeSetDisplayMode (JNIEnv *env, jclass class, jint displayID, jint w, jint h, jint bpp, jint refrate) { JNF_COCOA_ENTER(env); - CFArrayRef allModes = CGDisplayCopyAllDisplayModes(displayID, NULL); + CFArrayRef allModes = getAllValidDisplayModes(displayID); + CGDisplayModeRef closestMatch = getBestModeForParameters(allModes, (int)w, (int)h, (int)bpp, (int)refrate); + __block CGError retCode = kCGErrorSuccess; if (closestMatch != NULL) { [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ CGDisplayConfigRef config; - CGError retCode = CGBeginDisplayConfiguration(&config); + retCode = CGBeginDisplayConfiguration(&config); if (retCode == kCGErrorSuccess) { CGConfigureDisplayWithDisplayMode(config, displayID, closestMatch, NULL); - CGCompleteDisplayConfiguration(config, kCGConfigureForAppOnly); - if (config != NULL) { - CFRelease(config); - } + retCode = CGCompleteDisplayConfiguration(config, kCGConfigureForAppOnly); } }]; } else { [JNFException raise:env as:kIllegalArgumentException reason:"Invalid display mode"]; } + if (retCode != kCGErrorSuccess){ + [JNFException raise:env as:kIllegalArgumentException reason:"Unable to set display mode!"]; + } + CFRelease(allModes); JNF_COCOA_EXIT(env); } - /* * Class: sun_awt_CGraphicsDevice * Method: nativeGetDisplayMode @@ -247,7 +285,8 @@ Java_sun_awt_CGraphicsDevice_nativeGetDisplayModes { jobjectArray jreturnArray = NULL; JNF_COCOA_ENTER(env); - CFArrayRef allModes = CGDisplayCopyAllDisplayModes(displayID, NULL); + CFArrayRef allModes = getAllValidDisplayModes(displayID); + CFIndex numModes = CFArrayGetCount(allModes); static JNF_CLASS_CACHE(jc_DisplayMode, "java/awt/DisplayMode"); diff --git a/jdk/src/share/classes/javax/swing/plaf/synth/SynthScrollBarUI.java b/jdk/src/share/classes/javax/swing/plaf/synth/SynthScrollBarUI.java index 093aeaee5f8..fa631ed5cb8 100644 --- a/jdk/src/share/classes/javax/swing/plaf/synth/SynthScrollBarUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/synth/SynthScrollBarUI.java @@ -57,6 +57,7 @@ public class SynthScrollBarUI extends BasicScrollBarUI */ @Override protected void installDefaults() { + super.installDefaults(); trackHighlight = NO_HIGHLIGHT; if (scrollbar.getLayout() == null || (scrollbar.getLayout() instanceof UIResource)) { diff --git a/jdk/src/solaris/native/sun/awt/gtk2_interface.c b/jdk/src/solaris/native/sun/awt/gtk2_interface.c index cb93366be69..daca810e5a5 100644 --- a/jdk/src/solaris/native/sun/awt/gtk2_interface.c +++ b/jdk/src/solaris/native/sun/awt/gtk2_interface.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -437,6 +437,39 @@ gboolean gtk2_check_version() } } +/** + * Functions for awt_Desktop.c + */ +gboolean gtk2_show_uri_load() { + gboolean success = FALSE; + dlerror(); + const char *gtk_version = fp_gtk_check_version(2, 14, 0); + if (gtk_version != NULL) { + // The gtk_show_uri is available from GTK+ 2.14 +#ifdef INTERNAL_BUILD + fprintf (stderr, "The version of GTK is %s. " + "The gtk_show_uri function is supported " + "since GTK+ 2.14.\n", gtk_version); +#endif /* INTERNAL_BUILD */ + } else { + // Loading symbols only if the GTK version is 2.14 and higher + fp_gtk_show_uri = dl_symbol("gtk_show_uri"); + const char *dlsym_error = dlerror(); + if (dlsym_error) { +#ifdef INTERNAL_BUILD + fprintf (stderr, "Cannot load symbol: %s \n", dlsym_error); +#endif /* INTERNAL_BUILD */ + } else if (fp_gtk_show_uri == NULL) { +#ifdef INTERNAL_BUILD + fprintf(stderr, "dlsym(gtk_show_uri) returned NULL\n"); +#endif /* INTERNAL_BUILD */ + } else { + success = TRUE; + } + } + return success; +} + /** * Functions for sun_awt_X11_GtkFileDialogPeer.c */ diff --git a/jdk/src/solaris/native/sun/awt/gtk2_interface.h b/jdk/src/solaris/native/sun/awt/gtk2_interface.h index 1b46920a534..22ba24a49ae 100644 --- a/jdk/src/solaris/native/sun/awt/gtk2_interface.h +++ b/jdk/src/solaris/native/sun/awt/gtk2_interface.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,7 @@ #define GTK_STOCK_CANCEL "gtk-cancel" #define GTK_STOCK_SAVE "gtk-save" #define GTK_STOCK_OPEN "gtk-open" +#define GDK_CURRENT_TIME 0L typedef enum _WidgetType { @@ -280,6 +281,7 @@ struct _GSList typedef void GdkColormap; typedef void GdkDrawable; typedef void GdkGC; +typedef void GdkScreen; typedef void GdkPixbuf; typedef void GdkPixmap; typedef void GdkWindow; @@ -663,6 +665,15 @@ gchar* (*fp_gtk_check_version)(guint required_major, guint required_minor, */ gboolean gtk2_load(); +/* + * Loads fp_gtk_show_uri function pointer. This initialization is + * separated because the function is required only + * for java.awt.Desktop API. The function relies on initialization in + * gtk2_load, so it must be invoked only after a successful gtk2_load + * invocation + */ +gboolean gtk2_show_uri_load(); + /* * Unload the gtk2 library. If the library is already unloaded this method has * no effect and returns success. @@ -795,4 +806,7 @@ void (*fp_gdk_threads_init)(void); void (*fp_gdk_threads_enter)(void); void (*fp_gdk_threads_leave)(void); +gboolean (*fp_gtk_show_uri)(GdkScreen *screen, const gchar *uri, + guint32 timestamp, GError **error); + #endif /* !_GTK2_INTERFACE_H */ diff --git a/jdk/src/solaris/native/sun/xawt/awt_Desktop.c b/jdk/src/solaris/native/sun/xawt/awt_Desktop.c index b8b250beb18..317af3dfaa2 100644 --- a/jdk/src/solaris/native/sun/xawt/awt_Desktop.c +++ b/jdk/src/solaris/native/sun/xawt/awt_Desktop.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,71 +23,11 @@ * questions. */ -#include -#include -#include +#include "gtk2_interface.h" +#include "gnome_interface.h" -typedef int gboolean; - -typedef gboolean (GNOME_URL_SHOW_TYPE)(const char *, void **); -typedef gboolean (GNOME_VFS_INIT_TYPE)(void); - -GNOME_URL_SHOW_TYPE *gnome_url_show; -GNOME_VFS_INIT_TYPE *gnome_vfs_init; - -int init(){ - void *vfs_handle; - void *gnome_handle; - const char *errmsg; - - vfs_handle = dlopen(VERSIONED_JNI_LIB_NAME("gnomevfs-2", "0"), RTLD_LAZY); - if (vfs_handle == NULL) { - vfs_handle = dlopen(JNI_LIB_NAME("gnomevfs-2"), RTLD_LAZY); - if (vfs_handle == NULL) { -#ifdef INTERNAL_BUILD - fprintf(stderr, "can not load libgnomevfs-2.so\n"); -#endif - return 0; - } - } - dlerror(); /* Clear errors */ - gnome_vfs_init = (GNOME_VFS_INIT_TYPE*)dlsym(vfs_handle, "gnome_vfs_init"); - if (gnome_vfs_init == NULL){ -#ifdef INTERNAL_BUILD - fprintf(stderr, "dlsym( gnome_vfs_init) returned NULL\n"); -#endif - return 0; - } - if ((errmsg = dlerror()) != NULL) { -#ifdef INTERNAL_BUILD - fprintf(stderr, "can not find symbol gnome_vfs_init %s \n", errmsg); -#endif - return 0; - } - // call gonme_vfs_init() - (*gnome_vfs_init)(); - - gnome_handle = dlopen(VERSIONED_JNI_LIB_NAME("gnome-2", "0"), RTLD_LAZY); - if (gnome_handle == NULL) { - gnome_handle = dlopen(JNI_LIB_NAME("gnome-2"), RTLD_LAZY); - if (gnome_handle == NULL) { -#ifdef INTERNAL_BUILD - fprintf(stderr, "can not load libgnome-2.so\n"); -#endif - return 0; - } - } - dlerror(); /* Clear errors */ - gnome_url_show = (GNOME_URL_SHOW_TYPE*)dlsym(gnome_handle, "gnome_url_show"); - if ((errmsg = dlerror()) != NULL) { -#ifdef INTERNAL_BUILD - fprintf(stderr, "can not find symble gnome_url_show\n"); -#endif - return 0; - } - - return 1; -} +static gboolean gtk_has_been_loaded = FALSE; +static gboolean gnome_has_been_loaded = FALSE; /* * Class: sun_awt_X11_XDesktopPeer @@ -97,8 +37,20 @@ int init(){ JNIEXPORT jboolean JNICALL Java_sun_awt_X11_XDesktopPeer_init (JNIEnv *env, jclass cls) { - int init_ok = init(); - return init_ok ? JNI_TRUE : JNI_FALSE; + + if (gtk_has_been_loaded || gnome_has_been_loaded) { + return JNI_TRUE; + } + + if (gtk2_load() && gtk2_show_uri_load()) { + gtk_has_been_loaded = TRUE; + return JNI_TRUE; + } else if (gnome_load()) { + gnome_has_been_loaded = TRUE; + return JNI_TRUE; + } + + return JNI_FALSE; } /* @@ -109,16 +61,19 @@ JNIEXPORT jboolean JNICALL Java_sun_awt_X11_XDesktopPeer_init JNIEXPORT jboolean JNICALL Java_sun_awt_X11_XDesktopPeer_gnome_1url_1show (JNIEnv *env, jobject obj, jbyteArray url_j) { - gboolean success; - const char* url_c; - - if (gnome_url_show == NULL) { - return JNI_FALSE; - } + gboolean success = FALSE; + const gchar* url_c; url_c = (char*)(*env)->GetByteArrayElements(env, url_j, NULL); - // call gnome_url_show(const char* , GError**) - success = (*gnome_url_show)(url_c, NULL); + + if (gtk_has_been_loaded) { + fp_gdk_threads_enter(); + success = fp_gtk_show_uri(NULL, url_c, GDK_CURRENT_TIME, NULL); + fp_gdk_threads_leave(); + } else if (gnome_has_been_loaded) { + success = (*gnome_url_show)(url_c, NULL); + } + (*env)->ReleaseByteArrayElements(env, url_j, (signed char*)url_c, 0); return success ? JNI_TRUE : JNI_FALSE; diff --git a/jdk/src/solaris/native/sun/xawt/gnome_interface.c b/jdk/src/solaris/native/sun/xawt/gnome_interface.c new file mode 100644 index 00000000000..90d56de93d1 --- /dev/null +++ b/jdk/src/solaris/native/sun/xawt/gnome_interface.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "gnome_interface.h" + +GNOME_URL_SHOW_TYPE *gnome_url_show = NULL; + +gboolean gnome_load() { + void *vfs_handle; + void *gnome_handle; + const char *errmsg; + GNOME_VFS_INIT_TYPE *gnome_vfs_init; + + // trying to open the gnomevfs. VERSIONED_JNI_LIB_NAME + // macros formats the library name in a system specific manner + // see jdk/src/solaris/javavm/export/jvm_md.h for more details + vfs_handle = dlopen(VERSIONED_JNI_LIB_NAME("gnomevfs-2", "0"), RTLD_LAZY); + if (vfs_handle == NULL) { + // if we cannot load the library using a version assumed by JNI + // we are trying to load the library without a version suffix + vfs_handle = dlopen(JNI_LIB_NAME("gnomevfs-2"), RTLD_LAZY); + if (vfs_handle == NULL) { + #ifdef INTERNAL_BUILD + fprintf(stderr, "can not load libgnomevfs-2.so\n"); + #endif + return FALSE; + } + } + dlerror(); /* Clear errors */ + gnome_vfs_init = (GNOME_VFS_INIT_TYPE*)dlsym(vfs_handle, "gnome_vfs_init"); + if (gnome_vfs_init == NULL){ + #ifdef INTERNAL_BUILD + fprintf(stderr, "dlsym( gnome_vfs_init) returned NULL\n"); + #endif + return FALSE; + } + if ((errmsg = dlerror()) != NULL) { + #ifdef INTERNAL_BUILD + fprintf(stderr, "can not find symbol gnome_vfs_init %s \n", errmsg); + #endif + return FALSE; + } + // call gonme_vfs_init() + (*gnome_vfs_init)(); + + gnome_handle = dlopen(VERSIONED_JNI_LIB_NAME("gnome-2", "0"), RTLD_LAZY); + if (gnome_handle == NULL) { + gnome_handle = dlopen(JNI_LIB_NAME("gnome-2"), RTLD_LAZY); + if (gnome_handle == NULL) { + #ifdef INTERNAL_BUILD + fprintf(stderr, "can not load libgnome-2.so\n"); + #endif + return FALSE; + } + } + dlerror(); /* Clear errors */ + gnome_url_show = (GNOME_URL_SHOW_TYPE*)dlsym(gnome_handle, "gnome_url_show"); + if ((errmsg = dlerror()) != NULL) { + #ifdef INTERNAL_BUILD + fprintf(stderr, "can not find symble gnome_url_show\n"); + #endif + return FALSE; + } + return TRUE; +} diff --git a/jdk/src/solaris/native/sun/xawt/gnome_interface.h b/jdk/src/solaris/native/sun/xawt/gnome_interface.h new file mode 100644 index 00000000000..2ca444725e8 --- /dev/null +++ b/jdk/src/solaris/native/sun/xawt/gnome_interface.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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. + */ + +#ifndef _GNOME_INTERFACE_H +#define _GNOME_INTERFACE_H +#include "gtk2_interface.h" +#include +#include +#include + +typedef gboolean (GNOME_URL_SHOW_TYPE)(const char *, void **); +typedef gboolean (GNOME_VFS_INIT_TYPE)(void); + +extern GNOME_URL_SHOW_TYPE *gnome_url_show; +gboolean gnome_load(); + +#endif /* !_GNOME_INTERFACE_H */ diff --git a/jdk/src/windows/classes/sun/awt/windows/WDesktopPeer.java b/jdk/src/windows/classes/sun/awt/windows/WDesktopPeer.java index a7ddc1425ec..8661f61cc23 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WDesktopPeer.java +++ b/jdk/src/windows/classes/sun/awt/windows/WDesktopPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,15 +51,15 @@ public class WDesktopPeer implements DesktopPeer { } public void open(File file) throws IOException { - this.ShellExecute(file.toURI(), ACTION_OPEN_VERB); + this.ShellExecute(file, ACTION_OPEN_VERB); } public void edit(File file) throws IOException { - this.ShellExecute(file.toURI(), ACTION_EDIT_VERB); + this.ShellExecute(file, ACTION_EDIT_VERB); } public void print(File file) throws IOException { - this.ShellExecute(file.toURI(), ACTION_PRINT_VERB); + this.ShellExecute(file, ACTION_PRINT_VERB); } public void mail(URI uri) throws IOException { @@ -70,6 +70,13 @@ public class WDesktopPeer implements DesktopPeer { this.ShellExecute(uri, ACTION_OPEN_VERB); } + private void ShellExecute(File file, String verb) throws IOException { + String errMsg = ShellExecute(file.getAbsolutePath(), verb); + if (errMsg != null) { + throw new IOException("Failed to " + verb + " " + file + ". Error message: " + errMsg); + } + } + private void ShellExecute(URI uri, String verb) throws IOException { String errmsg = ShellExecute(uri.toString(), verb); @@ -79,6 +86,6 @@ public class WDesktopPeer implements DesktopPeer { } } - private static native String ShellExecute(String uri, String verb); + private static native String ShellExecute(String fileOrUri, String verb); } diff --git a/jdk/src/windows/native/sun/windows/awt_Desktop.cpp b/jdk/src/windows/native/sun/windows/awt_Desktop.cpp index 5db6c4bbcec..623718e42e1 100644 --- a/jdk/src/windows/native/sun/windows/awt_Desktop.cpp +++ b/jdk/src/windows/native/sun/windows/awt_Desktop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,17 +38,17 @@ extern "C" { * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_sun_awt_windows_WDesktopPeer_ShellExecute - (JNIEnv *env, jclass cls, jstring uri_j, jstring verb_j) + (JNIEnv *env, jclass cls, jstring fileOrUri_j, jstring verb_j) { - LPCWSTR uri_c = JNU_GetStringPlatformChars(env, uri_j, JNI_FALSE); + LPCWSTR fileOrUri_c = JNU_GetStringPlatformChars(env, fileOrUri_j, JNI_FALSE); LPCWSTR verb_c = JNU_GetStringPlatformChars(env, verb_j, JNI_FALSE); // 6457572: ShellExecute possibly changes FPU control word - saving it here unsigned oldcontrol87 = _control87(0, 0); - HINSTANCE retval = ::ShellExecute(NULL, verb_c, uri_c, NULL, NULL, SW_SHOWNORMAL); + HINSTANCE retval = ::ShellExecute(NULL, verb_c, fileOrUri_c, NULL, NULL, SW_SHOWNORMAL); _control87(oldcontrol87, 0xffffffff); - JNU_ReleaseStringPlatformChars(env, uri_j, uri_c); + JNU_ReleaseStringPlatformChars(env, fileOrUri_j, fileOrUri_c); JNU_ReleaseStringPlatformChars(env, verb_j, verb_c); if ((int)retval <= 32) { diff --git a/jdk/test/java/awt/Desktop/OpenByUNCPathNameTest/OpenByUNCPathNameTest.java b/jdk/test/java/awt/Desktop/OpenByUNCPathNameTest/OpenByUNCPathNameTest.java new file mode 100644 index 00000000000..052f36f7453 --- /dev/null +++ b/jdk/test/java/awt/Desktop/OpenByUNCPathNameTest/OpenByUNCPathNameTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 6550588 + @summary java.awt.Desktop cannot open file with Windows UNC filename + @author Anton Litvinov +*/ + +import java.awt.*; +import java.awt.event.*; +import java.io.*; + +public class OpenByUNCPathNameTest { + private static boolean validatePlatform() { + String osName = System.getProperty("os.name"); + if (osName == null) { + throw new RuntimeException("Name of the current OS could not be retrieved."); + } + return osName.startsWith("Windows"); + } + + private static void openFile() throws IOException { + if (!Desktop.isDesktopSupported()) { + System.out.println("java.awt.Desktop is not supported on this platform."); + } else { + Desktop desktop = Desktop.getDesktop(); + File file = File.createTempFile("Read Me File", ".txt"); + try { + // Test opening of the file with Windows local file path. + desktop.open(file); + Robot robot = null; + try { + Thread.sleep(5000); + robot = new Robot(); + } catch (Exception e) { + e.printStackTrace(); + } + pressAltF4Keys(robot); + + // Test opening of the file with Windows UNC pathname. + String uncFilePath = "\\\\127.0.0.1\\" + file.getAbsolutePath().replace(':', '$'); + File uncFile = new File(uncFilePath); + if (!uncFile.exists()) { + throw new RuntimeException(String.format( + "File with UNC pathname '%s' does not exist.", uncFilePath)); + } + desktop.open(uncFile); + try { + Thread.sleep(5000); + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + pressAltF4Keys(robot); + } finally { + file.delete(); + } + } + } + + private static void pressAltF4Keys(Robot robot) { + if (robot != null) { + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_F4); + robot.delay(50); + robot.keyRelease(KeyEvent.VK_F4); + robot.keyRelease(KeyEvent.VK_ALT); + } + } + + public static void main(String[] args) throws IOException { + if (!validatePlatform()) { + System.out.println("This test is only for MS Windows OS."); + } else { + openFile(); + } + } +} diff --git a/jdk/test/java/awt/GraphicsDevice/CheckDisplayModes.java b/jdk/test/java/awt/GraphicsDevice/CheckDisplayModes.java new file mode 100644 index 00000000000..bc8d8a50be6 --- /dev/null +++ b/jdk/test/java/awt/GraphicsDevice/CheckDisplayModes.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8007146 + * @summary [macosx] Setting a display mode crashes JDK under VNC + * @author Alexander Scherbatiy + * @run main CheckDisplayModes + */ +import java.awt.DisplayMode; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; + +public class CheckDisplayModes { + + public static void main(String[] args) { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice graphicDevice = ge.getDefaultScreenDevice(); + DisplayMode defaultDisplayMode = graphicDevice.getDisplayMode(); + checkDisplayMode(defaultDisplayMode); + graphicDevice.setDisplayMode(defaultDisplayMode); + + DisplayMode[] displayModes = graphicDevice.getDisplayModes(); + boolean isDefaultDisplayModeIncluded = false; + for (DisplayMode displayMode : displayModes) { + checkDisplayMode(displayMode); + graphicDevice.setDisplayMode(displayMode); + if (defaultDisplayMode.equals(displayMode)) { + isDefaultDisplayModeIncluded = true; + } + } + + if (!isDefaultDisplayModeIncluded) { + throw new RuntimeException("Default display mode is not included"); + } + } + + static void checkDisplayMode(DisplayMode displayMode) { + if (displayMode == null || displayMode.getWidth() <= 1 || displayMode.getHeight() <= 1) { + throw new RuntimeException("invalid display mode"); + } + } +} diff --git a/jdk/test/java/beans/Introspector/TestTypeResolver.java b/jdk/test/java/beans/Introspector/TestTypeResolver.java index e6915192776..1b4535f506d 100644 --- a/jdk/test/java/beans/Introspector/TestTypeResolver.java +++ b/jdk/test/java/beans/Introspector/TestTypeResolver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import com.sun.beans.TypeResolver; import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedType; import java.lang.reflect.Field; import java.lang.reflect.GenericDeclaration; import java.lang.reflect.Method; @@ -199,6 +200,19 @@ public class TestTypeResolver { public Annotation[] getDeclaredAnnotations() { return null; // not used } + + public AnnotatedType[] getAnnotatedBounds() { + return null; // not used + } + + public T[] getAnnotationsByType(Class annotationClass) { + return null; // not used + } + + public T[] getDeclaredAnnotationsByType(Class annotationClass) { + return null; // not used + } + } private static class ClassTypeVariable extends TypeVariableImpl> { diff --git a/jdk/test/javax/swing/JMenu/4515762/bug4515762.java b/jdk/test/javax/swing/JMenu/4515762/bug4515762.java new file mode 100644 index 00000000000..cb86ac168fa --- /dev/null +++ b/jdk/test/javax/swing/JMenu/4515762/bug4515762.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import sun.awt.SunToolkit; + +/** + * @test + * @bug 4515762 + * @author Mark Davidson + * @summary Tests the ability to support duplicate mnemonics + * @library ../../regtesthelpers + * @build Util + * @run main bug4515762 + */ +public class bug4515762 { + + private static volatile boolean actionExpected = false; + private static volatile boolean actionRecieved = false; + + /** + * @param str name of Menu + */ + private static JMenuBar createMenuBar() { + JMenuBar menubar = new JMenuBar(); + + // Duplicate menu item test for 4515762 + JMenu menu = new JMenu("Duplicate Menu"); + menu.setMnemonic('D'); + menu.add(createMenuItem("Sunday", 'S')); + menu.add(createMenuItem("Monday", 'M')); + + menu.add(createMenuItem("Tuesday", 'S')); + menu.add(createMenuItem("Wednesday", 'S')); + menu.add(createMenuItem("Thursday", 'S')); + menu.add(createMenuItem("Friday", 'F')); + menu.add(createMenuItem("Saturday", 'S')); + + // Control with unique menu + JMenu menu2 = new JMenu("Unique Menu"); + menu2.setMnemonic('U'); + menu2.add(createMenuItem("Sunday", 'S')); + menu2.add(createMenuItem("Monday", 'M')); + + menu2.add(createMenuItem("Tuesday", 'T')); + menu2.add(createMenuItem("Wednesday", 'W')); + menu2.add(createMenuItem("Thursday", 'U')); + menu2.add(createMenuItem("Friday", 'F')); + menu2.add(createMenuItem("Saturday", 'A')); + + menubar.add(menu); + menubar.add(menu2); + + return menubar; + } + + /** + * Creates and returns the menu item. + */ + private static JMenuItem createMenuItem(String name, char mnemonic) { + JMenuItem menuItem = new JMenuItem(name, mnemonic); + menuItem.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent evt) { + JMenuItem item = (JMenuItem) evt.getSource(); + if (actionExpected == false) { + throw new RuntimeException("Menu Action: " + + item.getText() + " should not be called"); + } else { + actionRecieved = true; + } + } + }); + + return menuItem; + } + + public static void checkAction() { + if (actionRecieved == true) { + actionRecieved = false; + } else { + throw new RuntimeException("Action has not been received"); + } + } + + public static void main(String[] args) throws Throwable { + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + Robot robot = new Robot(); + robot.setAutoDelay(250); + + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + JFrame frame = new JFrame("Test"); + frame.setJMenuBar(createMenuBar()); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.pack(); + frame.setVisible(true); + } + }); + + toolkit.realSync(); + + Util.hitMnemonics(robot, KeyEvent.VK_D); + toolkit.realSync(); + + // Press the S key many times (should not cause an action peformed) + int TIMES = 5; + for (int i = 0; i < TIMES; i++) { + Util.hitKeys(robot, KeyEvent.VK_S); + } + toolkit.realSync(); + + // Unique menu items. + actionExpected = true; + Util.hitMnemonics(robot, KeyEvent.VK_U); + + robot.keyPress(KeyEvent.VK_S); + robot.keyRelease(KeyEvent.VK_S); + toolkit.realSync(); + + checkAction(); + + Util.hitMnemonics(robot, KeyEvent.VK_U); + robot.keyPress(KeyEvent.VK_M); + robot.keyRelease(KeyEvent.VK_M); + toolkit.realSync(); + + checkAction(); + + Util.hitMnemonics(robot, KeyEvent.VK_U); + Util.hitKeys(robot, KeyEvent.VK_T); + toolkit.realSync(); + + checkAction(); + Util.hitMnemonics(robot, KeyEvent.VK_U); + Util.hitKeys(robot, KeyEvent.VK_W); + toolkit.realSync(); + + checkAction(); + + Util.hitMnemonics(robot, KeyEvent.VK_U); + Util.hitKeys(robot, KeyEvent.VK_U); + toolkit.realSync(); + + checkAction(); + } +} diff --git a/jdk/test/javax/swing/JRootPane/4670486/bug4670486.java b/jdk/test/javax/swing/JRootPane/4670486/bug4670486.java new file mode 100644 index 00000000000..6682f8afccf --- /dev/null +++ b/jdk/test/javax/swing/JRootPane/4670486/bug4670486.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import sun.awt.SunToolkit; + +/** + * @test + * @bug 4670486 + * @author Mark Davidson + * @summary Regression: Popup menu bindings doesn't work when a default button has been defined. + * @library ../../regtesthelpers + * @build Util + * @run main bug4670486 + */ +public class bug4670486 { + + public static volatile boolean actionExpected = false; + public static volatile boolean actionRecieved = false; + + private static JMenuBar createMenuBar() { + JMenuBar menubar = new JMenuBar(); + + // Control with unique menu + JMenu menu = new JMenu("Unique Menu"); + menu.setMnemonic('U'); + menu.add(createMenuItem("Sunday", 'S')); + menu.add(createMenuItem("Monday", 'M')); + + menu.add(createMenuItem("Tuesday", 'T')); + menu.add(createMenuItem("Wednesday", 'W')); + menu.add(createMenuItem("Thursday", 'U')); + menu.add(createMenuItem("Friday", 'F')); + menu.add(createMenuItem("Saturday", 'A')); + + menubar.add(menu); + + return menubar; + } + + private static JPanel createPanel(JFrame frame) { + JPanel panel = new JPanel(); + JButton button = new JButton("Button"); + JButton button2 = new JButton("Button 2"); + JButton button3 = new JButton("Button 3"); + + JRootPane root = frame.getRootPane(); + root.setDefaultButton(button); + + panel.add(button); + panel.add(button2); + panel.add(button3); + + return panel; + } + + /** + * Creates and returns the menu item. + */ + private static JMenuItem createMenuItem(String name, char mnemonic) { + JMenuItem menuItem = new JMenuItem(name, mnemonic); + menuItem.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent evt) { + actionRecieved = true; + } + }); + + return menuItem; + } + + public static void checkAction() { + if (actionRecieved == true) { + actionRecieved = false; + } else { + throw new RuntimeException("Action has not been received"); + } + } + + public static void main(String[] args) throws Throwable { + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + Robot robot = new Robot(); + robot.setAutoDelay(250); + + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + JFrame frame = new JFrame("Test"); + frame.setContentPane(createPanel(frame)); + frame.setJMenuBar(createMenuBar()); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.pack(); + frame.setVisible(true); + } + }); + + toolkit.realSync(); + + // Change the default button to + // force a call to BasicRootPaneUI.updateDefaultButtonBindings() + Util.hitKeys(robot, KeyEvent.VK_TAB); + + // If the bug exists, then as soon as the menu appears, + // the VK_ENTER, VK_DOWN, VK_UP and VK_ESC will have no + // effect. + Util.hitMnemonics(robot, KeyEvent.VK_U); + Util.hitKeys(robot, KeyEvent.VK_ENTER); + toolkit.realSync(); + + checkAction(); + + Util.hitMnemonics(robot, KeyEvent.VK_U); + Util.hitKeys(robot, KeyEvent.VK_DOWN); + Util.hitKeys(robot, KeyEvent.VK_ENTER); + toolkit.realSync(); + + checkAction(); + } +} diff --git a/jdk/test/javax/swing/JScrollBar/7163696/Test7163696.java b/jdk/test/javax/swing/JScrollBar/7163696/Test7163696.java new file mode 100644 index 00000000000..922bf2e4963 --- /dev/null +++ b/jdk/test/javax/swing/JScrollBar/7163696/Test7163696.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7163696 + * @summary Tests that JScrollBar scrolls to the left + * @author Sergey Malenkov + */ + +import sun.awt.SunToolkit; + +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.event.InputEvent; + +import javax.swing.JFrame; +import javax.swing.JScrollBar; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; + +public class Test7163696 implements Runnable { + + private static final boolean AUTO = null != System.getProperty("test.src", null); + + public static void main(String[] args) throws Exception { + new Test7163696().test(); + } + + private JScrollBar bar; + + private void test() throws Exception { + Robot robot = new Robot(); + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { + UIManager.setLookAndFeel(info.getClassName()); + + SwingUtilities.invokeAndWait(this); + toolkit.realSync(500); // after creation + + Point point = this.bar.getLocation(); + SwingUtilities.convertPointToScreen(point, this.bar); + point.x += this.bar.getWidth() >> 2; + point.y += this.bar.getHeight() >> 1; + robot.mouseMove(point.x, point.y); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + + toolkit.realSync(500); // before validation + SwingUtilities.invokeAndWait(this); + + if (this.bar != null) { + this.bar = null; // allows to reuse the instance + if (AUTO) { // error reporting only for automatic testing + throw new Error("TEST FAILED"); + } + } + } + } + + public void run() { + if (this.bar == null) { + this.bar = new JScrollBar(JScrollBar.HORIZONTAL, 50, 10, 0, 100); + this.bar.setPreferredSize(new Dimension(400, 20)); + + JFrame frame = new JFrame(); + frame.add(this.bar); + frame.pack(); + frame.setVisible(true); + } + else if (40 != this.bar.getValue()) { + System.out.println("name = " + UIManager.getLookAndFeel().getName()); + System.out.println("value = " + this.bar.getValue()); + } + else { + SwingUtilities.getWindowAncestor(this.bar).dispose(); + this.bar = null; + } + } +} diff --git a/jdk/test/javax/swing/JTree/8004298/bug8004298.java b/jdk/test/javax/swing/JTree/8004298/bug8004298.java index 3d0ca5c00bc..bafdee7d3e3 100644 --- a/jdk/test/javax/swing/JTree/8004298/bug8004298.java +++ b/jdk/test/javax/swing/JTree/8004298/bug8004298.java @@ -48,8 +48,13 @@ public class bug8004298 { Robot robot = new Robot(); robot.setAutoDelay(50); SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); - UIManager.setLookAndFeel(new WindowsLookAndFeel()); - + try { + UIManager.setLookAndFeel(new WindowsLookAndFeel()); + } catch (javax.swing.UnsupportedLookAndFeelException ulafe) { + System.out.println(ulafe.getMessage()); + System.out.println("The test is considered PASSED"); + return; + } SwingUtilities.invokeAndWait(new Runnable() { @Override @@ -113,4 +118,4 @@ public class bug8004298 { return super.getPathBounds(tree, path); } } -} \ No newline at end of file +} diff --git a/jdk/test/javax/swing/regtesthelpers/Util.java b/jdk/test/javax/swing/regtesthelpers/Util.java index df7ab7ade80..33460714003 100644 --- a/jdk/test/javax/swing/regtesthelpers/Util.java +++ b/jdk/test/javax/swing/regtesthelpers/Util.java @@ -145,6 +145,23 @@ public class Util { return null; } + /** + * Hits mnemonics by robot. + */ + public static void hitMnemonics(Robot robot, int... keys) { + + ArrayList mnemonicKeyCodes = getSystemMnemonicKeyCodes(); + for (Integer mnemonic : mnemonicKeyCodes) { + robot.keyPress(mnemonic); + } + + hitKeys(robot, keys); + + for (Integer mnemonic : mnemonicKeyCodes) { + robot.keyRelease(mnemonic); + } + } + /** * Hits keys by robot. */ diff --git a/langtools/.hgtags b/langtools/.hgtags index 0d946930fa4..4f56fa54e99 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -202,3 +202,5 @@ e81839b3233792415daaab051698edc6067f1a16 jdk8-b76 af8417e590f4e76e0dfed09e71239fb102ef0d43 jdk8-b78 56dfafbb9e1ad7548a4415316dc003296fb498cb jdk8-b79 a8227c61768499dac847ea718af6719027c949f2 jdk8-b80 +ed69d087fdfd394491657a28ba9bc58e7849b7db jdk8-b81 +825da6847791994a8f405ee397df9e7fa638a458 jdk8-b82 diff --git a/langtools/src/share/classes/com/sun/source/doctree/AttributeTree.java b/langtools/src/share/classes/com/sun/source/doctree/AttributeTree.java index 26dd4c3995f..aa757f6df9e 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/AttributeTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/AttributeTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,9 @@ import javax.lang.model.element.Name; * * @since 1.8 */ +@jdk.Supported public interface AttributeTree extends DocTree { + @jdk.Supported enum ValueKind { EMPTY, UNQUOTED, SINGLE, DOUBLE }; Name getName(); diff --git a/langtools/src/share/classes/com/sun/source/doctree/AuthorTree.java b/langtools/src/share/classes/com/sun/source/doctree/AuthorTree.java index d6580c5eaf2..7391fd2e6e9 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/AuthorTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/AuthorTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.util.List; * * @since 1.8 */ +@jdk.Supported public interface AuthorTree extends BlockTagTree { List getName(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/BlockTagTree.java b/langtools/src/share/classes/com/sun/source/doctree/BlockTagTree.java index 9c72c1d973b..0af9fc54b9f 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/BlockTagTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/BlockTagTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ package com.sun.source.doctree; * * @since 1.8 */ +@jdk.Supported public interface BlockTagTree extends DocTree { String getTagName(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/CommentTree.java b/langtools/src/share/classes/com/sun/source/doctree/CommentTree.java index cd89cf5ca0d..a4ad14fc552 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/CommentTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/CommentTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ package com.sun.source.doctree; * * @since 1.8 */ +@jdk.Supported public interface CommentTree extends DocTree { String getBody(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/DeprecatedTree.java b/langtools/src/share/classes/com/sun/source/doctree/DeprecatedTree.java index c24baacc7ee..974b9b5f5aa 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/DeprecatedTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/DeprecatedTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.util.List; * * @since 1.8 */ +@jdk.Supported public interface DeprecatedTree extends BlockTagTree { List getBody(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/DocCommentTree.java b/langtools/src/share/classes/com/sun/source/doctree/DocCommentTree.java index d59cfffc2db..903f76f0936 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/DocCommentTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/DocCommentTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.util.List; * * @since 1.8 */ +@jdk.Supported public interface DocCommentTree extends DocTree { List getFirstSentence(); List getBody(); diff --git a/langtools/src/share/classes/com/sun/source/doctree/DocRootTree.java b/langtools/src/share/classes/com/sun/source/doctree/DocRootTree.java index 05205fb0faf..7e01e544f55 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/DocRootTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/DocRootTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,4 +33,5 @@ package com.sun.source.doctree; * * @since 1.8 */ +@jdk.Supported public interface DocRootTree extends InlineTagTree { } diff --git a/langtools/src/share/classes/com/sun/source/doctree/DocTree.java b/langtools/src/share/classes/com/sun/source/doctree/DocTree.java index a28cdcbe852..4f1cc00a30e 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/DocTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/DocTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,9 @@ package com.sun.source.doctree; * * @since 1.8 */ +@jdk.Supported public interface DocTree { + @jdk.Supported enum Kind { /** * Used for instances of {@link AttributeTree} diff --git a/langtools/src/share/classes/com/sun/source/doctree/DocTreeVisitor.java b/langtools/src/share/classes/com/sun/source/doctree/DocTreeVisitor.java index c7feb40d244..71b548e4228 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/DocTreeVisitor.java +++ b/langtools/src/share/classes/com/sun/source/doctree/DocTreeVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,7 @@ package com.sun.source.doctree; * * @since 1.8 */ +@jdk.Supported public interface DocTreeVisitor { R visitAttribute(AttributeTree node, P p); R visitAuthor(AuthorTree node, P p); diff --git a/langtools/src/share/classes/com/sun/source/doctree/EndElementTree.java b/langtools/src/share/classes/com/sun/source/doctree/EndElementTree.java index 2584f798c6c..ae01e3406d1 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/EndElementTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/EndElementTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import javax.lang.model.element.Name; * * @since 1.8 */ +@jdk.Supported public interface EndElementTree extends DocTree { Name getName(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/EntityTree.java b/langtools/src/share/classes/com/sun/source/doctree/EntityTree.java index 9c6ad50aee0..fb86c6dc62a 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/EntityTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/EntityTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ import javax.lang.model.element.Name; * * @since 1.8 */ +@jdk.Supported public interface EntityTree extends DocTree { Name getName(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/ErroneousTree.java b/langtools/src/share/classes/com/sun/source/doctree/ErroneousTree.java index ca50acbbfc7..02292949d9d 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/ErroneousTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/ErroneousTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import javax.tools.JavaFileObject; * * @since 1.8 */ +@jdk.Supported public interface ErroneousTree extends TextTree { /** * Gets a diagnostic object giving details about diff --git a/langtools/src/share/classes/com/sun/source/doctree/IdentifierTree.java b/langtools/src/share/classes/com/sun/source/doctree/IdentifierTree.java index 0be2ddf2a34..5257cbf5376 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/IdentifierTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/IdentifierTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import javax.lang.model.element.Name; * * @since 1.8 */ +@jdk.Supported public interface IdentifierTree extends DocTree { Name getName(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/InheritDocTree.java b/langtools/src/share/classes/com/sun/source/doctree/InheritDocTree.java index 8af74b6a330..b853d6a82d4 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/InheritDocTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/InheritDocTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,4 +34,5 @@ package com.sun.source.doctree; * * @since 1.8 */ +@jdk.Supported public interface InheritDocTree extends InlineTagTree { } diff --git a/langtools/src/share/classes/com/sun/source/doctree/InlineTagTree.java b/langtools/src/share/classes/com/sun/source/doctree/InlineTagTree.java index a6cec5307c2..411b04e79ac 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/InlineTagTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/InlineTagTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ package com.sun.source.doctree; * * @since 1.8 */ +@jdk.Supported public interface InlineTagTree extends DocTree { String getTagName(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/LinkTree.java b/langtools/src/share/classes/com/sun/source/doctree/LinkTree.java index 41f28e0e95f..4c7c6876701 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/LinkTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/LinkTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ import java.util.List; * * @since 1.8 */ +@jdk.Supported public interface LinkTree extends InlineTagTree { ReferenceTree getReference(); List getLabel(); diff --git a/langtools/src/share/classes/com/sun/source/doctree/LiteralTree.java b/langtools/src/share/classes/com/sun/source/doctree/LiteralTree.java index 0531501fa41..b2cd2823412 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/LiteralTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/LiteralTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ package com.sun.source.doctree; * * @since 1.8 */ +@jdk.Supported public interface LiteralTree extends InlineTagTree { TextTree getBody(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/ParamTree.java b/langtools/src/share/classes/com/sun/source/doctree/ParamTree.java index a7dcf6a6aac..f0090bbd639 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/ParamTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/ParamTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.util.List; * * @since 1.8 */ +@jdk.Supported public interface ParamTree extends BlockTagTree { boolean isTypeParameter(); IdentifierTree getName(); diff --git a/langtools/src/share/classes/com/sun/source/doctree/ReferenceTree.java b/langtools/src/share/classes/com/sun/source/doctree/ReferenceTree.java index 1ab12de2498..0bbfcdc853e 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/ReferenceTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/ReferenceTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ package com.sun.source.doctree; * * @since 1.8 */ +@jdk.Supported public interface ReferenceTree extends DocTree { String getSignature(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/ReturnTree.java b/langtools/src/share/classes/com/sun/source/doctree/ReturnTree.java index 5b0fe313ac7..e948ca96cb0 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/ReturnTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/ReturnTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.util.List; * * @since 1.8 */ +@jdk.Supported public interface ReturnTree extends BlockTagTree { List getDescription(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/SeeTree.java b/langtools/src/share/classes/com/sun/source/doctree/SeeTree.java index 6d70194aacb..8d09ff26387 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/SeeTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/SeeTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ import java.util.List; * * @since 1.8 */ +@jdk.Supported public interface SeeTree extends BlockTagTree { List getReference(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/SerialDataTree.java b/langtools/src/share/classes/com/sun/source/doctree/SerialDataTree.java index 02c2f26c943..2044f5db632 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/SerialDataTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/SerialDataTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.util.List; * * @since 1.8 */ +@jdk.Supported public interface SerialDataTree extends BlockTagTree { List getDescription(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/SerialFieldTree.java b/langtools/src/share/classes/com/sun/source/doctree/SerialFieldTree.java index eb47017c331..cae5ff9f72c 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/SerialFieldTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/SerialFieldTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.util.List; * * @since 1.8 */ +@jdk.Supported public interface SerialFieldTree extends BlockTagTree { IdentifierTree getName(); ReferenceTree getType(); diff --git a/langtools/src/share/classes/com/sun/source/doctree/SerialTree.java b/langtools/src/share/classes/com/sun/source/doctree/SerialTree.java index 5f5f6ccaa92..c95ae9b1da5 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/SerialTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/SerialTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.util.List; * * @since 1.8 */ +@jdk.Supported public interface SerialTree extends BlockTagTree { List getDescription(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/SinceTree.java b/langtools/src/share/classes/com/sun/source/doctree/SinceTree.java index 60090967e10..f6600d09465 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/SinceTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/SinceTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.util.List; * * @since 1.8 */ +@jdk.Supported public interface SinceTree extends BlockTagTree { List getBody(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/StartElementTree.java b/langtools/src/share/classes/com/sun/source/doctree/StartElementTree.java index f3d4f28ddbe..e72e21df0ea 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/StartElementTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/StartElementTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ import javax.lang.model.element.Name; * * @since 1.8 */ +@jdk.Supported public interface StartElementTree extends DocTree { Name getName(); List getAttributes(); diff --git a/langtools/src/share/classes/com/sun/source/doctree/TextTree.java b/langtools/src/share/classes/com/sun/source/doctree/TextTree.java index 5db02702a10..40fcf37ced4 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/TextTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/TextTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ package com.sun.source.doctree; * * @since 1.8 */ +@jdk.Supported public interface TextTree extends DocTree { String getBody(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/ThrowsTree.java b/langtools/src/share/classes/com/sun/source/doctree/ThrowsTree.java index 795d3a38f62..c86729c1af6 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/ThrowsTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/ThrowsTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ import java.util.List; * * @since 1.8 */ +@jdk.Supported public interface ThrowsTree extends BlockTagTree { ReferenceTree getExceptionName(); List getDescription(); diff --git a/langtools/src/share/classes/com/sun/source/doctree/UnknownBlockTagTree.java b/langtools/src/share/classes/com/sun/source/doctree/UnknownBlockTagTree.java index f985dc39d12..113691ebd40 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/UnknownBlockTagTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/UnknownBlockTagTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.util.List; * @since 1.8 * */ +@jdk.Supported public interface UnknownBlockTagTree extends BlockTagTree { List getContent(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/UnknownInlineTagTree.java b/langtools/src/share/classes/com/sun/source/doctree/UnknownInlineTagTree.java index 9ab78173592..f9072fff04d 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/UnknownInlineTagTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/UnknownInlineTagTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.util.List; * @since 1.8 * */ +@jdk.Supported public interface UnknownInlineTagTree extends InlineTagTree { List getContent(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/ValueTree.java b/langtools/src/share/classes/com/sun/source/doctree/ValueTree.java index 3f61f2519b4..91f63735a6b 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/ValueTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/ValueTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ package com.sun.source.doctree; * * @since 1.8 */ +@jdk.Supported public interface ValueTree extends InlineTagTree { ReferenceTree getReference(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/VersionTree.java b/langtools/src/share/classes/com/sun/source/doctree/VersionTree.java index 4595ec04a5e..d36ba1e457a 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/VersionTree.java +++ b/langtools/src/share/classes/com/sun/source/doctree/VersionTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ import java.util.List; * * @since 1.8 */ +@jdk.Supported public interface VersionTree extends BlockTagTree { List getBody(); } diff --git a/langtools/src/share/classes/com/sun/source/doctree/package-info.java b/langtools/src/share/classes/com/sun/source/doctree/package-info.java index 8b84ed3ec71..888fb79ebd3 100644 --- a/langtools/src/share/classes/com/sun/source/doctree/package-info.java +++ b/langtools/src/share/classes/com/sun/source/doctree/package-info.java @@ -31,4 +31,5 @@ * @since 1.8 * @see http://download.oracle.com/javase/6/docs/technotes/tools/solaris/javadoc.html#javadoctags */ +@jdk.Supported package com.sun.source.doctree; diff --git a/langtools/src/share/classes/com/sun/source/tree/AnnotatedTypeTree.java b/langtools/src/share/classes/com/sun/source/tree/AnnotatedTypeTree.java index ca799344cc8..f9f3014819a 100644 --- a/langtools/src/share/classes/com/sun/source/tree/AnnotatedTypeTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/AnnotatedTypeTree.java @@ -41,6 +41,7 @@ import java.util.List; * @author Mahmood Ali * @since 1.8 */ +@jdk.Supported public interface AnnotatedTypeTree extends ExpressionTree { List getAnnotations(); ExpressionTree getUnderlyingType(); diff --git a/langtools/src/share/classes/com/sun/source/tree/AnnotationTree.java b/langtools/src/share/classes/com/sun/source/tree/AnnotationTree.java index 5a9074b28f3..5a785ee2910 100644 --- a/langtools/src/share/classes/com/sun/source/tree/AnnotationTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/AnnotationTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,7 @@ import java.util.List; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface AnnotationTree extends ExpressionTree { Tree getAnnotationType(); List getArguments(); diff --git a/langtools/src/share/classes/com/sun/source/tree/ArrayAccessTree.java b/langtools/src/share/classes/com/sun/source/tree/ArrayAccessTree.java index 7e5fc2cfc5f..97696c6d734 100644 --- a/langtools/src/share/classes/com/sun/source/tree/ArrayAccessTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/ArrayAccessTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface ArrayAccessTree extends ExpressionTree { ExpressionTree getExpression(); ExpressionTree getIndex(); diff --git a/langtools/src/share/classes/com/sun/source/tree/ArrayTypeTree.java b/langtools/src/share/classes/com/sun/source/tree/ArrayTypeTree.java index 0c58a719ccb..b6275bedc12 100644 --- a/langtools/src/share/classes/com/sun/source/tree/ArrayTypeTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/ArrayTypeTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface ArrayTypeTree extends Tree { Tree getType(); } diff --git a/langtools/src/share/classes/com/sun/source/tree/AssertTree.java b/langtools/src/share/classes/com/sun/source/tree/AssertTree.java index fce758ed9dc..90ca3c5c665 100644 --- a/langtools/src/share/classes/com/sun/source/tree/AssertTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/AssertTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface AssertTree extends StatementTree { ExpressionTree getCondition(); ExpressionTree getDetail(); diff --git a/langtools/src/share/classes/com/sun/source/tree/AssignmentTree.java b/langtools/src/share/classes/com/sun/source/tree/AssignmentTree.java index 9c5480d503d..a2cc6022a74 100644 --- a/langtools/src/share/classes/com/sun/source/tree/AssignmentTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/AssignmentTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface AssignmentTree extends ExpressionTree { ExpressionTree getVariable(); ExpressionTree getExpression(); diff --git a/langtools/src/share/classes/com/sun/source/tree/BinaryTree.java b/langtools/src/share/classes/com/sun/source/tree/BinaryTree.java index d24497a3c74..9767c0e8612 100644 --- a/langtools/src/share/classes/com/sun/source/tree/BinaryTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/BinaryTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface BinaryTree extends ExpressionTree { ExpressionTree getLeftOperand(); ExpressionTree getRightOperand(); diff --git a/langtools/src/share/classes/com/sun/source/tree/BlockTree.java b/langtools/src/share/classes/com/sun/source/tree/BlockTree.java index 330309a080a..278e257f476 100644 --- a/langtools/src/share/classes/com/sun/source/tree/BlockTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/BlockTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,7 @@ import java.util.List; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface BlockTree extends StatementTree { boolean isStatic(); List getStatements(); diff --git a/langtools/src/share/classes/com/sun/source/tree/BreakTree.java b/langtools/src/share/classes/com/sun/source/tree/BreakTree.java index e287a98152c..f07eda07e65 100644 --- a/langtools/src/share/classes/com/sun/source/tree/BreakTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/BreakTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,7 @@ import javax.lang.model.element.Name; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface BreakTree extends StatementTree { Name getLabel(); } diff --git a/langtools/src/share/classes/com/sun/source/tree/CaseTree.java b/langtools/src/share/classes/com/sun/source/tree/CaseTree.java index a273c2ffbd8..5dc5b78e5f1 100644 --- a/langtools/src/share/classes/com/sun/source/tree/CaseTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/CaseTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,7 @@ import java.util.List; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface CaseTree extends Tree { /** * @return null if and only if this Case is {@code default:} diff --git a/langtools/src/share/classes/com/sun/source/tree/CatchTree.java b/langtools/src/share/classes/com/sun/source/tree/CatchTree.java index 9c34e860028..6e68963b289 100644 --- a/langtools/src/share/classes/com/sun/source/tree/CatchTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/CatchTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface CatchTree extends Tree { VariableTree getParameter(); BlockTree getBlock(); diff --git a/langtools/src/share/classes/com/sun/source/tree/ClassTree.java b/langtools/src/share/classes/com/sun/source/tree/ClassTree.java index 81c7c2f223e..f675b2723b8 100644 --- a/langtools/src/share/classes/com/sun/source/tree/ClassTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/ClassTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,7 @@ import javax.lang.model.element.Name; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface ClassTree extends StatementTree { ModifiersTree getModifiers(); Name getSimpleName(); diff --git a/langtools/src/share/classes/com/sun/source/tree/CompilationUnitTree.java b/langtools/src/share/classes/com/sun/source/tree/CompilationUnitTree.java index e6ff1aad67c..086b71fb1ad 100644 --- a/langtools/src/share/classes/com/sun/source/tree/CompilationUnitTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/CompilationUnitTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ import javax.tools.JavaFileObject; * @author Peter von der Ahé * @since 1.6 */ +@jdk.Supported public interface CompilationUnitTree extends Tree { List getPackageAnnotations(); ExpressionTree getPackageName(); diff --git a/langtools/src/share/classes/com/sun/source/tree/CompoundAssignmentTree.java b/langtools/src/share/classes/com/sun/source/tree/CompoundAssignmentTree.java index 86eb99c27c1..9ca04da6708 100644 --- a/langtools/src/share/classes/com/sun/source/tree/CompoundAssignmentTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/CompoundAssignmentTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface CompoundAssignmentTree extends ExpressionTree { ExpressionTree getVariable(); ExpressionTree getExpression(); diff --git a/langtools/src/share/classes/com/sun/source/tree/ConditionalExpressionTree.java b/langtools/src/share/classes/com/sun/source/tree/ConditionalExpressionTree.java index 4492611f931..b2ce4007f18 100644 --- a/langtools/src/share/classes/com/sun/source/tree/ConditionalExpressionTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/ConditionalExpressionTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface ConditionalExpressionTree extends ExpressionTree { ExpressionTree getCondition(); ExpressionTree getTrueExpression(); diff --git a/langtools/src/share/classes/com/sun/source/tree/ContinueTree.java b/langtools/src/share/classes/com/sun/source/tree/ContinueTree.java index 98db3549faf..0634957c371 100644 --- a/langtools/src/share/classes/com/sun/source/tree/ContinueTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/ContinueTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,7 @@ import javax.lang.model.element.Name; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface ContinueTree extends StatementTree { Name getLabel(); } diff --git a/langtools/src/share/classes/com/sun/source/tree/DoWhileLoopTree.java b/langtools/src/share/classes/com/sun/source/tree/DoWhileLoopTree.java index 4a6e20b43bd..d6a18379a81 100644 --- a/langtools/src/share/classes/com/sun/source/tree/DoWhileLoopTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/DoWhileLoopTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface DoWhileLoopTree extends StatementTree { ExpressionTree getCondition(); StatementTree getStatement(); diff --git a/langtools/src/share/classes/com/sun/source/tree/EmptyStatementTree.java b/langtools/src/share/classes/com/sun/source/tree/EmptyStatementTree.java index baf13c15503..1882685b432 100644 --- a/langtools/src/share/classes/com/sun/source/tree/EmptyStatementTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/EmptyStatementTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,4 +39,5 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface EmptyStatementTree extends StatementTree {} diff --git a/langtools/src/share/classes/com/sun/source/tree/EnhancedForLoopTree.java b/langtools/src/share/classes/com/sun/source/tree/EnhancedForLoopTree.java index f550bfaf1d3..9f2051a746d 100644 --- a/langtools/src/share/classes/com/sun/source/tree/EnhancedForLoopTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/EnhancedForLoopTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface EnhancedForLoopTree extends StatementTree { VariableTree getVariable(); ExpressionTree getExpression(); diff --git a/langtools/src/share/classes/com/sun/source/tree/ErroneousTree.java b/langtools/src/share/classes/com/sun/source/tree/ErroneousTree.java index d37911781d3..8591cc32245 100644 --- a/langtools/src/share/classes/com/sun/source/tree/ErroneousTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/ErroneousTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.util.List; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface ErroneousTree extends ExpressionTree { List getErrorTrees(); } diff --git a/langtools/src/share/classes/com/sun/source/tree/ExpressionStatementTree.java b/langtools/src/share/classes/com/sun/source/tree/ExpressionStatementTree.java index f3661c1d323..cc78a8bf913 100644 --- a/langtools/src/share/classes/com/sun/source/tree/ExpressionStatementTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/ExpressionStatementTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface ExpressionStatementTree extends StatementTree { ExpressionTree getExpression(); } diff --git a/langtools/src/share/classes/com/sun/source/tree/ExpressionTree.java b/langtools/src/share/classes/com/sun/source/tree/ExpressionTree.java index 1ef4349fce8..d0e9b4032d5 100644 --- a/langtools/src/share/classes/com/sun/source/tree/ExpressionTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/ExpressionTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,4 +35,5 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface ExpressionTree extends Tree {} diff --git a/langtools/src/share/classes/com/sun/source/tree/ForLoopTree.java b/langtools/src/share/classes/com/sun/source/tree/ForLoopTree.java index 12e21b7954a..7adea339784 100644 --- a/langtools/src/share/classes/com/sun/source/tree/ForLoopTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/ForLoopTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,7 @@ import java.util.List; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface ForLoopTree extends StatementTree { List getInitializer(); ExpressionTree getCondition(); diff --git a/langtools/src/share/classes/com/sun/source/tree/IdentifierTree.java b/langtools/src/share/classes/com/sun/source/tree/IdentifierTree.java index 1d2d8adc7ad..dc662c06eb0 100644 --- a/langtools/src/share/classes/com/sun/source/tree/IdentifierTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/IdentifierTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ import javax.lang.model.element.Name; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface IdentifierTree extends ExpressionTree { Name getName(); } diff --git a/langtools/src/share/classes/com/sun/source/tree/IfTree.java b/langtools/src/share/classes/com/sun/source/tree/IfTree.java index f6009466451..ad88dd5590d 100644 --- a/langtools/src/share/classes/com/sun/source/tree/IfTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/IfTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface IfTree extends StatementTree { ExpressionTree getCondition(); StatementTree getThenStatement(); diff --git a/langtools/src/share/classes/com/sun/source/tree/ImportTree.java b/langtools/src/share/classes/com/sun/source/tree/ImportTree.java index 1fd027d5259..8eb61acc307 100644 --- a/langtools/src/share/classes/com/sun/source/tree/ImportTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/ImportTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface ImportTree extends Tree { boolean isStatic(); /** diff --git a/langtools/src/share/classes/com/sun/source/tree/InstanceOfTree.java b/langtools/src/share/classes/com/sun/source/tree/InstanceOfTree.java index 20d95e73eab..a7d632514e1 100644 --- a/langtools/src/share/classes/com/sun/source/tree/InstanceOfTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/InstanceOfTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface InstanceOfTree extends ExpressionTree { ExpressionTree getExpression(); Tree getType(); diff --git a/langtools/src/share/classes/com/sun/source/tree/IntersectionTypeTree.java b/langtools/src/share/classes/com/sun/source/tree/IntersectionTypeTree.java index 09404699dac..7476564fb21 100644 --- a/langtools/src/share/classes/com/sun/source/tree/IntersectionTypeTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/IntersectionTypeTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.util.List; * * @since 1.8 */ +@jdk.Supported public interface IntersectionTypeTree extends Tree { List getBounds(); } diff --git a/langtools/src/share/classes/com/sun/source/tree/LabeledStatementTree.java b/langtools/src/share/classes/com/sun/source/tree/LabeledStatementTree.java index ba58dd488fd..644189f932d 100644 --- a/langtools/src/share/classes/com/sun/source/tree/LabeledStatementTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/LabeledStatementTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ import javax.lang.model.element.Name; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface LabeledStatementTree extends StatementTree { Name getLabel(); StatementTree getStatement(); diff --git a/langtools/src/share/classes/com/sun/source/tree/LambdaExpressionTree.java b/langtools/src/share/classes/com/sun/source/tree/LambdaExpressionTree.java index 163f113ef05..ffd230d943d 100644 --- a/langtools/src/share/classes/com/sun/source/tree/LambdaExpressionTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/LambdaExpressionTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,12 +37,14 @@ import java.util.List; * (x,y)-> { return x + y; } * } */ +@jdk.Supported public interface LambdaExpressionTree extends ExpressionTree { /** * Lambda expressions come in two forms: (i) expression lambdas, whose body * is an expression, and (ii) statement lambdas, whose body is a block */ + @jdk.Supported public enum BodyKind { /** enum constant for expression lambdas */ EXPRESSION, diff --git a/langtools/src/share/classes/com/sun/source/tree/LineMap.java b/langtools/src/share/classes/com/sun/source/tree/LineMap.java index 609a3b105e6..4c0c29bf446 100644 --- a/langtools/src/share/classes/com/sun/source/tree/LineMap.java +++ b/langtools/src/share/classes/com/sun/source/tree/LineMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ package com.sun.source.tree; * * @since 1.6 */ +@jdk.Supported public interface LineMap { /** * Find the start position of a line. diff --git a/langtools/src/share/classes/com/sun/source/tree/LiteralTree.java b/langtools/src/share/classes/com/sun/source/tree/LiteralTree.java index a8be528c2f8..adc3937fd75 100644 --- a/langtools/src/share/classes/com/sun/source/tree/LiteralTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/LiteralTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface LiteralTree extends ExpressionTree { Object getValue(); } diff --git a/langtools/src/share/classes/com/sun/source/tree/MemberReferenceTree.java b/langtools/src/share/classes/com/sun/source/tree/MemberReferenceTree.java index c17b96f6f0f..03b8a6a81e7 100644 --- a/langtools/src/share/classes/com/sun/source/tree/MemberReferenceTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/MemberReferenceTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,12 +39,14 @@ import javax.lang.model.element.Name; * * @since 1.8 */ +@jdk.Supported public interface MemberReferenceTree extends ExpressionTree { /** * There are two kinds of member references: (i) method references and * (ii) constructor references */ + @jdk.Supported public enum ReferenceMode { /** enum constant for method references */ INVOKE, diff --git a/langtools/src/share/classes/com/sun/source/tree/MemberSelectTree.java b/langtools/src/share/classes/com/sun/source/tree/MemberSelectTree.java index e5beec5d234..8b1b8e41c27 100644 --- a/langtools/src/share/classes/com/sun/source/tree/MemberSelectTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/MemberSelectTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ import javax.lang.model.element.Name; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface MemberSelectTree extends ExpressionTree { ExpressionTree getExpression(); Name getIdentifier(); diff --git a/langtools/src/share/classes/com/sun/source/tree/MethodInvocationTree.java b/langtools/src/share/classes/com/sun/source/tree/MethodInvocationTree.java index 4728d9963dc..2ccbeae2386 100644 --- a/langtools/src/share/classes/com/sun/source/tree/MethodInvocationTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/MethodInvocationTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,7 @@ import java.util.List; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface MethodInvocationTree extends ExpressionTree { List getTypeArguments(); ExpressionTree getMethodSelect(); diff --git a/langtools/src/share/classes/com/sun/source/tree/MethodTree.java b/langtools/src/share/classes/com/sun/source/tree/MethodTree.java index d72302a647b..8d9820ba5fe 100644 --- a/langtools/src/share/classes/com/sun/source/tree/MethodTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/MethodTree.java @@ -46,6 +46,7 @@ import javax.lang.model.element.Name; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface MethodTree extends Tree { ModifiersTree getModifiers(); Name getName(); diff --git a/langtools/src/share/classes/com/sun/source/tree/ModifiersTree.java b/langtools/src/share/classes/com/sun/source/tree/ModifiersTree.java index 3189651e373..3fae9c07f93 100644 --- a/langtools/src/share/classes/com/sun/source/tree/ModifiersTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/ModifiersTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,7 @@ import javax.lang.model.element.Modifier; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface ModifiersTree extends Tree { Set getFlags(); List getAnnotations(); diff --git a/langtools/src/share/classes/com/sun/source/tree/NewArrayTree.java b/langtools/src/share/classes/com/sun/source/tree/NewArrayTree.java index cdd5cd51a9b..b9f1bddf487 100644 --- a/langtools/src/share/classes/com/sun/source/tree/NewArrayTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/NewArrayTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,7 @@ import java.util.List; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface NewArrayTree extends ExpressionTree { Tree getType(); List getDimensions(); diff --git a/langtools/src/share/classes/com/sun/source/tree/NewClassTree.java b/langtools/src/share/classes/com/sun/source/tree/NewClassTree.java index 06d713bef9f..561d411a3d8 100644 --- a/langtools/src/share/classes/com/sun/source/tree/NewClassTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/NewClassTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,7 @@ import java.util.List; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface NewClassTree extends ExpressionTree { ExpressionTree getEnclosingExpression(); List getTypeArguments(); diff --git a/langtools/src/share/classes/com/sun/source/tree/ParameterizedTypeTree.java b/langtools/src/share/classes/com/sun/source/tree/ParameterizedTypeTree.java index aef328ddee9..c51aad58178 100644 --- a/langtools/src/share/classes/com/sun/source/tree/ParameterizedTypeTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/ParameterizedTypeTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ import java.util.List; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface ParameterizedTypeTree extends Tree { Tree getType(); List getTypeArguments(); diff --git a/langtools/src/share/classes/com/sun/source/tree/ParenthesizedTree.java b/langtools/src/share/classes/com/sun/source/tree/ParenthesizedTree.java index d68516fac66..2e0cd4d49be 100644 --- a/langtools/src/share/classes/com/sun/source/tree/ParenthesizedTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/ParenthesizedTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface ParenthesizedTree extends ExpressionTree { ExpressionTree getExpression(); } diff --git a/langtools/src/share/classes/com/sun/source/tree/PrimitiveTypeTree.java b/langtools/src/share/classes/com/sun/source/tree/PrimitiveTypeTree.java index f6cd5669de5..0b98b59db3b 100644 --- a/langtools/src/share/classes/com/sun/source/tree/PrimitiveTypeTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/PrimitiveTypeTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ import javax.lang.model.type.TypeKind; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface PrimitiveTypeTree extends Tree { TypeKind getPrimitiveTypeKind(); } diff --git a/langtools/src/share/classes/com/sun/source/tree/ReturnTree.java b/langtools/src/share/classes/com/sun/source/tree/ReturnTree.java index 62a51cb3316..b8d451bd6db 100644 --- a/langtools/src/share/classes/com/sun/source/tree/ReturnTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/ReturnTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface ReturnTree extends StatementTree { ExpressionTree getExpression(); } diff --git a/langtools/src/share/classes/com/sun/source/tree/Scope.java b/langtools/src/share/classes/com/sun/source/tree/Scope.java index 5d86fc8bf24..17b79be4d59 100644 --- a/langtools/src/share/classes/com/sun/source/tree/Scope.java +++ b/langtools/src/share/classes/com/sun/source/tree/Scope.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,7 @@ import javax.lang.model.element.TypeElement; * * @since 1.6 */ +@jdk.Supported public interface Scope { /** * Returns the enclosing scope. diff --git a/langtools/src/share/classes/com/sun/source/tree/StatementTree.java b/langtools/src/share/classes/com/sun/source/tree/StatementTree.java index 47dba7dd64a..2bae01c551c 100644 --- a/langtools/src/share/classes/com/sun/source/tree/StatementTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/StatementTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,4 +35,5 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface StatementTree extends Tree {} diff --git a/langtools/src/share/classes/com/sun/source/tree/SwitchTree.java b/langtools/src/share/classes/com/sun/source/tree/SwitchTree.java index c5a87c42c88..3d8a11fdf94 100644 --- a/langtools/src/share/classes/com/sun/source/tree/SwitchTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/SwitchTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,7 @@ import java.util.List; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface SwitchTree extends StatementTree { ExpressionTree getExpression(); List getCases(); diff --git a/langtools/src/share/classes/com/sun/source/tree/SynchronizedTree.java b/langtools/src/share/classes/com/sun/source/tree/SynchronizedTree.java index fd7cb063c21..579e0755d0e 100644 --- a/langtools/src/share/classes/com/sun/source/tree/SynchronizedTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/SynchronizedTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface SynchronizedTree extends StatementTree { ExpressionTree getExpression(); BlockTree getBlock(); diff --git a/langtools/src/share/classes/com/sun/source/tree/ThrowTree.java b/langtools/src/share/classes/com/sun/source/tree/ThrowTree.java index a91f63b0cb9..474b588ec34 100644 --- a/langtools/src/share/classes/com/sun/source/tree/ThrowTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/ThrowTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface ThrowTree extends StatementTree { ExpressionTree getExpression(); } diff --git a/langtools/src/share/classes/com/sun/source/tree/Tree.java b/langtools/src/share/classes/com/sun/source/tree/Tree.java index 58ecb984b82..306991d2cbd 100644 --- a/langtools/src/share/classes/com/sun/source/tree/Tree.java +++ b/langtools/src/share/classes/com/sun/source/tree/Tree.java @@ -39,11 +39,13 @@ package com.sun.source.tree; * * @since 1.6 */ +@jdk.Supported public interface Tree { /** * Enumerates all kinds of trees. */ + @jdk.Supported public enum Kind { ANNOTATED_TYPE(AnnotatedTypeTree.class), diff --git a/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java b/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java index ad549b229e6..386e714fc8d 100644 --- a/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java +++ b/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java @@ -56,6 +56,7 @@ package com.sun.source.tree; * * @since 1.6 */ +@jdk.Supported public interface TreeVisitor { R visitAnnotatedType(AnnotatedTypeTree node, P p); R visitAnnotation(AnnotationTree node, P p); diff --git a/langtools/src/share/classes/com/sun/source/tree/TryTree.java b/langtools/src/share/classes/com/sun/source/tree/TryTree.java index f2510bd5821..0b7b19e5e70 100644 --- a/langtools/src/share/classes/com/sun/source/tree/TryTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/TryTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,7 @@ import java.util.List; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface TryTree extends StatementTree { BlockTree getBlock(); List getCatches(); diff --git a/langtools/src/share/classes/com/sun/source/tree/TypeCastTree.java b/langtools/src/share/classes/com/sun/source/tree/TypeCastTree.java index 43dc6192e38..77ad546f5eb 100644 --- a/langtools/src/share/classes/com/sun/source/tree/TypeCastTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/TypeCastTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface TypeCastTree extends ExpressionTree { Tree getType(); ExpressionTree getExpression(); diff --git a/langtools/src/share/classes/com/sun/source/tree/TypeParameterTree.java b/langtools/src/share/classes/com/sun/source/tree/TypeParameterTree.java index fd4a17407c7..293a38b35a5 100644 --- a/langtools/src/share/classes/com/sun/source/tree/TypeParameterTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/TypeParameterTree.java @@ -44,6 +44,7 @@ import javax.lang.model.element.Name; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface TypeParameterTree extends Tree { Name getName(); List getBounds(); diff --git a/langtools/src/share/classes/com/sun/source/tree/UnaryTree.java b/langtools/src/share/classes/com/sun/source/tree/UnaryTree.java index 7b4d9e834af..cb0da5e3d8b 100644 --- a/langtools/src/share/classes/com/sun/source/tree/UnaryTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/UnaryTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface UnaryTree extends ExpressionTree { ExpressionTree getExpression(); } diff --git a/langtools/src/share/classes/com/sun/source/tree/UnionTypeTree.java b/langtools/src/share/classes/com/sun/source/tree/UnionTypeTree.java index 2a4b935fde8..57b98922a9f 100644 --- a/langtools/src/share/classes/com/sun/source/tree/UnionTypeTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/UnionTypeTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.util.List; * * @since 1.7 */ +@jdk.Supported public interface UnionTypeTree extends Tree { List getTypeAlternatives(); } diff --git a/langtools/src/share/classes/com/sun/source/tree/VariableTree.java b/langtools/src/share/classes/com/sun/source/tree/VariableTree.java index ea73f23ad3e..7fba7df2b58 100644 --- a/langtools/src/share/classes/com/sun/source/tree/VariableTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/VariableTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ import javax.lang.model.element.Name; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface VariableTree extends StatementTree { ModifiersTree getModifiers(); Name getName(); diff --git a/langtools/src/share/classes/com/sun/source/tree/WhileLoopTree.java b/langtools/src/share/classes/com/sun/source/tree/WhileLoopTree.java index fd4a832a71c..e7c4351dff7 100644 --- a/langtools/src/share/classes/com/sun/source/tree/WhileLoopTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/WhileLoopTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface WhileLoopTree extends StatementTree { ExpressionTree getCondition(); StatementTree getStatement(); diff --git a/langtools/src/share/classes/com/sun/source/tree/WildcardTree.java b/langtools/src/share/classes/com/sun/source/tree/WildcardTree.java index d3f62fd033e..d60f797567d 100644 --- a/langtools/src/share/classes/com/sun/source/tree/WildcardTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/WildcardTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ package com.sun.source.tree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface WildcardTree extends Tree { Tree getBound(); } diff --git a/langtools/src/share/classes/com/sun/source/tree/package-info.java b/langtools/src/share/classes/com/sun/source/tree/package-info.java index 7a204645f61..7df58d8b6d4 100644 --- a/langtools/src/share/classes/com/sun/source/tree/package-info.java +++ b/langtools/src/share/classes/com/sun/source/tree/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,4 +31,5 @@ * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported package com.sun.source.tree; diff --git a/langtools/src/share/classes/com/sun/source/util/DocTreeScanner.java b/langtools/src/share/classes/com/sun/source/util/DocTreeScanner.java index 4d23b2266be..eba4730f585 100644 --- a/langtools/src/share/classes/com/sun/source/util/DocTreeScanner.java +++ b/langtools/src/share/classes/com/sun/source/util/DocTreeScanner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,6 +67,7 @@ import com.sun.source.doctree.*; * * @since 1.8 */ +@jdk.Supported public class DocTreeScanner implements DocTreeVisitor { /** diff --git a/langtools/src/share/classes/com/sun/source/util/DocTrees.java b/langtools/src/share/classes/com/sun/source/util/DocTrees.java index a2f6635df75..63f6c899c20 100644 --- a/langtools/src/share/classes/com/sun/source/util/DocTrees.java +++ b/langtools/src/share/classes/com/sun/source/util/DocTrees.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ import javax.tools.Diagnostic; * * @since 1.8 */ +@jdk.Supported public abstract class DocTrees extends Trees { /** * Gets a DocTrees object for a given CompilationTask. diff --git a/langtools/src/share/classes/com/sun/source/util/JavacTask.java b/langtools/src/share/classes/com/sun/source/util/JavacTask.java index 7cd9a279dc5..e760f5c3526 100644 --- a/langtools/src/share/classes/com/sun/source/util/JavacTask.java +++ b/langtools/src/share/classes/com/sun/source/util/JavacTask.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,7 @@ import com.sun.tools.javac.util.Context; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public abstract class JavacTask implements CompilationTask { /** diff --git a/langtools/src/share/classes/com/sun/source/util/Plugin.java b/langtools/src/share/classes/com/sun/source/util/Plugin.java index 0b500f31c84..726115535f1 100644 --- a/langtools/src/share/classes/com/sun/source/util/Plugin.java +++ b/langtools/src/share/classes/com/sun/source/util/Plugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,7 @@ import javax.tools.StandardLocation; * * @since 1.8 */ +@jdk.Supported public interface Plugin { /** * Get the user-friendly name of this plug-in. diff --git a/langtools/src/share/classes/com/sun/source/util/SimpleDocTreeVisitor.java b/langtools/src/share/classes/com/sun/source/util/SimpleDocTreeVisitor.java index a1be626b82e..25e8010fffe 100644 --- a/langtools/src/share/classes/com/sun/source/util/SimpleDocTreeVisitor.java +++ b/langtools/src/share/classes/com/sun/source/util/SimpleDocTreeVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import com.sun.source.doctree.*; * * @since 1.8 */ +@jdk.Supported public class SimpleDocTreeVisitor implements DocTreeVisitor { protected final R DEFAULT_VALUE; diff --git a/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java b/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java index 9d4aede36d9..d8bf052729b 100644 --- a/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java +++ b/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java @@ -33,6 +33,7 @@ import com.sun.source.tree.*; * @author Peter von der Ahé * @since 1.6 */ +@jdk.Supported public class SimpleTreeVisitor implements TreeVisitor { protected final R DEFAULT_VALUE; diff --git a/langtools/src/share/classes/com/sun/source/util/SourcePositions.java b/langtools/src/share/classes/com/sun/source/util/SourcePositions.java index b3a9fea2384..d55c73135ab 100644 --- a/langtools/src/share/classes/com/sun/source/util/SourcePositions.java +++ b/langtools/src/share/classes/com/sun/source/util/SourcePositions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import com.sun.source.tree.*; * @author Peter von der Ahé * @since 1.6 */ +@jdk.Supported public interface SourcePositions { /** diff --git a/langtools/src/share/classes/com/sun/source/util/TaskEvent.java b/langtools/src/share/classes/com/sun/source/util/TaskEvent.java index 625eae9f534..d49a9d5b9a7 100644 --- a/langtools/src/share/classes/com/sun/source/util/TaskEvent.java +++ b/langtools/src/share/classes/com/sun/source/util/TaskEvent.java @@ -36,12 +36,14 @@ import com.sun.source.tree.CompilationUnitTree; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public final class TaskEvent { /** * Kind of task event. * @since 1.6 */ + @jdk.Supported public enum Kind { /** * For events related to the parsing of a file. diff --git a/langtools/src/share/classes/com/sun/source/util/TaskListener.java b/langtools/src/share/classes/com/sun/source/util/TaskListener.java index 602ccbfe232..39099759802 100644 --- a/langtools/src/share/classes/com/sun/source/util/TaskListener.java +++ b/langtools/src/share/classes/com/sun/source/util/TaskListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ package com.sun.source.util; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public interface TaskListener { public void started(TaskEvent e); diff --git a/langtools/src/share/classes/com/sun/source/util/TreePath.java b/langtools/src/share/classes/com/sun/source/util/TreePath.java index a150e67e7c9..d7df6a96b03 100644 --- a/langtools/src/share/classes/com/sun/source/util/TreePath.java +++ b/langtools/src/share/classes/com/sun/source/util/TreePath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ import com.sun.source.tree.*; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public class TreePath implements Iterable { /** * Gets a tree path for a tree node within a compilation unit. diff --git a/langtools/src/share/classes/com/sun/source/util/TreePathScanner.java b/langtools/src/share/classes/com/sun/source/util/TreePathScanner.java index 4df7d243d6a..54f8a99f80d 100644 --- a/langtools/src/share/classes/com/sun/source/util/TreePathScanner.java +++ b/langtools/src/share/classes/com/sun/source/util/TreePathScanner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ import com.sun.source.tree.*; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public class TreePathScanner extends TreeScanner { /** diff --git a/langtools/src/share/classes/com/sun/source/util/TreeScanner.java b/langtools/src/share/classes/com/sun/source/util/TreeScanner.java index d503bac7b00..ee05b228b32 100644 --- a/langtools/src/share/classes/com/sun/source/util/TreeScanner.java +++ b/langtools/src/share/classes/com/sun/source/util/TreeScanner.java @@ -68,6 +68,7 @@ import com.sun.source.tree.*; * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported public class TreeScanner implements TreeVisitor { /** Scan a single node. diff --git a/langtools/src/share/classes/com/sun/source/util/Trees.java b/langtools/src/share/classes/com/sun/source/util/Trees.java index 7ee8b291b94..439b684cbe6 100644 --- a/langtools/src/share/classes/com/sun/source/util/Trees.java +++ b/langtools/src/share/classes/com/sun/source/util/Trees.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,6 +51,7 @@ import com.sun.source.tree.Tree; * * @author Peter von der Ahé */ +@jdk.Supported public abstract class Trees { /** * Gets a Trees object for a given CompilationTask. diff --git a/langtools/src/share/classes/com/sun/source/util/package-info.java b/langtools/src/share/classes/com/sun/source/util/package-info.java index 852dbc2eb6d..7e9659b7abe 100644 --- a/langtools/src/share/classes/com/sun/source/util/package-info.java +++ b/langtools/src/share/classes/com/sun/source/util/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,4 +30,5 @@ * @author Jonathan Gibbons * @since 1.6 */ +@jdk.Supported package com.sun.source.util; diff --git a/langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java b/langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java index 9628b961f79..be6d5282c69 100644 --- a/langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java +++ b/langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java @@ -483,7 +483,7 @@ public class ClassWriter { out.writeByte(attr.method_parameter_table.length); for (MethodParameters_attribute.Entry e : attr.method_parameter_table) { out.writeShort(e.name_index); - out.writeInt(e.flags); + out.writeShort(e.flags); } return null; } diff --git a/langtools/src/share/classes/com/sun/tools/classfile/MethodParameters_attribute.java b/langtools/src/share/classes/com/sun/tools/classfile/MethodParameters_attribute.java index cbf44d20ae4..bf060cf8a26 100644 --- a/langtools/src/share/classes/com/sun/tools/classfile/MethodParameters_attribute.java +++ b/langtools/src/share/classes/com/sun/tools/classfile/MethodParameters_attribute.java @@ -73,7 +73,7 @@ public class MethodParameters_attribute extends Attribute { public static class Entry { Entry(ClassReader cr) throws IOException { name_index = cr.readUnsignedShort(); - flags = cr.readInt(); + flags = cr.readUnsignedShort(); } public static int length() { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java index bbc14f74fc8..d49fd9ea5bb 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java @@ -60,7 +60,7 @@ public class ConstructorWriterImpl extends AbstractExecutableMemberWriter ClassDoc classDoc) { super(writer, classDoc); VisibleMemberMap visibleMemberMap = new VisibleMemberMap(classDoc, - VisibleMemberMap.CONSTRUCTORS, configuration.nodeprecated); + VisibleMemberMap.CONSTRUCTORS, configuration); List constructors = new ArrayList(visibleMemberMap.getMembersFor(classDoc)); for (int i = 0; i < constructors.size(); i++) { if ((constructors.get(i)).isProtected() || diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java index 7d3c71b8e21..8a9b107dca5 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java @@ -543,7 +543,8 @@ public class HtmlDocletWriter extends HtmlDocWriter { } HtmlTree navList = new HtmlTree(HtmlTag.UL); navList.addStyle(HtmlStyle.navList); - navList.addAttr(HtmlAttr.TITLE, "Navigation"); + navList.addAttr(HtmlAttr.TITLE, + configuration.getText("doclet.Navigation")); if (configuration.createoverview) { navList.addContent(getNavLinkContents()); } @@ -1299,13 +1300,31 @@ public class HtmlDocletWriter extends HtmlDocWriter { */ public String getDocLink(int context, ClassDoc classDoc, MemberDoc doc, String label, boolean strong) { + return getDocLink(context, classDoc, doc, label, strong, false); + } + + /** + * Return the link for the given member. + * + * @param context the id of the context where the link will be printed. + * @param classDoc the classDoc that we should link to. This is not + * necessarily equal to doc.containingClass(). We may be + * inheriting comments. + * @param doc the member being linked to. + * @param label the label for the link. + * @param strong true if the link should be strong. + * @param isProperty true if the doc parameter is a JavaFX property. + * @return the link for the given member. + */ + public String getDocLink(int context, ClassDoc classDoc, MemberDoc doc, + String label, boolean strong, boolean isProperty) { if (! (doc.isIncluded() || Util.isLinkable(classDoc, configuration))) { return label; } else if (doc instanceof ExecutableMemberDoc) { ExecutableMemberDoc emd = (ExecutableMemberDoc)doc; return getLink(new LinkInfoImpl(configuration, context, classDoc, - getAnchor(emd), label, strong)); + getAnchor(emd, isProperty), label, strong)); } else if (doc instanceof MemberDoc) { return getLink(new LinkInfoImpl(configuration, context, classDoc, doc.name(), label, strong)); @@ -1343,6 +1362,13 @@ public class HtmlDocletWriter extends HtmlDocWriter { } public String getAnchor(ExecutableMemberDoc emd) { + return getAnchor(emd, false); + } + + public String getAnchor(ExecutableMemberDoc emd, boolean isProperty) { + if (isProperty) { + return emd.name(); + } StringBuilder signature = new StringBuilder(emd.signature()); StringBuilder signatureParsed = new StringBuilder(); int counter = 0; diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkInfoImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkInfoImpl.java index 417e2ff9f94..ae64b75e0c4 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkInfoImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkInfoImpl.java @@ -198,6 +198,11 @@ public class LinkInfoImpl extends LinkInfo { */ public static final int CONTEXT_CLASS_USE_HEADER = 33; + /** + * The header for property documentation copied from parent. + */ + public static final int CONTEXT_PROPERTY_DOC_COPY = 34; + public final ConfigurationImpl configuration; /** @@ -422,6 +427,7 @@ public class LinkInfoImpl extends LinkInfo { case CONTEXT_SUBCLASSES: case CONTEXT_METHOD_DOC_COPY: case CONTEXT_FIELD_DOC_COPY: + case CONTEXT_PROPERTY_DOC_COPY: case CONTEXT_CLASS_USE_HEADER: includeTypeInClassLinkLabel = false; break; diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageFrameWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageFrameWriter.java index 4535afaf55c..851fed9f82b 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageFrameWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageFrameWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -161,6 +161,7 @@ public class PackageFrameWriter extends HtmlDocletWriter { */ protected void addClassKindListing(ClassDoc[] arr, Content labelContent, Content contentTree) { + arr = Util.filterOutPrivateClasses(arr, configuration.javafx); if(arr.length > 0) { Arrays.sort(arr); boolean printedHeader = false; diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PropertyWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PropertyWriterImpl.java new file mode 100644 index 00000000000..4fa52f202c7 --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PropertyWriterImpl.java @@ -0,0 +1,322 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.doclets.formats.html; + +import java.io.*; + +import com.sun.javadoc.*; +import com.sun.tools.doclets.formats.html.markup.*; +import com.sun.tools.doclets.internal.toolkit.*; +import com.sun.tools.doclets.internal.toolkit.util.*; + +/** + * Writes property documentation in HTML format. + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Robert Field + * @author Atul M Dambalkar + * @author Jamie Ho (rewrite) + * @author Bhavesh Patel (Modified) + */ +public class PropertyWriterImpl extends AbstractMemberWriter + implements PropertyWriter, MemberSummaryWriter { + + public PropertyWriterImpl(SubWriterHolderWriter writer, ClassDoc classdoc) { + super(writer, classdoc); + } + + /** + * {@inheritDoc} + */ + public Content getMemberSummaryHeader(ClassDoc classDoc, + Content memberSummaryTree) { + memberSummaryTree.addContent(HtmlConstants.START_OF_PROPERTY_SUMMARY); + Content memberTree = writer.getMemberTreeHeader(); + writer.addSummaryHeader(this, classDoc, memberTree); + return memberTree; + } + + /** + * {@inheritDoc} + */ + public Content getPropertyDetailsTreeHeader(ClassDoc classDoc, + Content memberDetailsTree) { + memberDetailsTree.addContent(HtmlConstants.START_OF_PROPERTY_DETAILS); + Content propertyDetailsTree = writer.getMemberTreeHeader(); + propertyDetailsTree.addContent(writer.getMarkerAnchor("property_detail")); + Content heading = HtmlTree.HEADING(HtmlConstants.DETAILS_HEADING, + writer.propertyDetailsLabel); + propertyDetailsTree.addContent(heading); + return propertyDetailsTree; + } + + /** + * {@inheritDoc} + */ + public Content getPropertyDocTreeHeader(MethodDoc property, + Content propertyDetailsTree) { + propertyDetailsTree.addContent( + writer.getMarkerAnchor(property.name())); + Content propertyDocTree = writer.getMemberTreeHeader(); + Content heading = new HtmlTree(HtmlConstants.MEMBER_HEADING); + heading.addContent(property.name().substring(0, property.name().lastIndexOf("Property"))); + propertyDocTree.addContent(heading); + return propertyDocTree; + } + + /** + * {@inheritDoc} + */ + public Content getSignature(MethodDoc property) { + Content pre = new HtmlTree(HtmlTag.PRE); + writer.addAnnotationInfo(property, pre); + addModifiers(property, pre); + Content propertylink = new RawHtml(writer.getLink(new LinkInfoImpl( + configuration, LinkInfoImpl.CONTEXT_MEMBER, + property.returnType()))); + pre.addContent(propertylink); + pre.addContent(" "); + if (configuration.linksource) { + Content propertyName = new StringContent(property.name()); + writer.addSrcLink(property, propertyName, pre); + } else { + addName(property.name(), pre); + } + return pre; + } + + /** + * {@inheritDoc} + */ + public void addDeprecated(MethodDoc property, Content propertyDocTree) { + } + + /** + * {@inheritDoc} + */ + public void addComments(MethodDoc property, Content propertyDocTree) { + ClassDoc holder = property.containingClass(); + if (property.inlineTags().length > 0) { + if (holder.equals(classdoc) || + (! (holder.isPublic() || Util.isLinkable(holder, configuration)))) { + writer.addInlineComment(property, propertyDocTree); + } else { + Content link = new RawHtml( + writer.getDocLink(LinkInfoImpl.CONTEXT_PROPERTY_DOC_COPY, + holder, property, + holder.isIncluded() ? + holder.typeName() : holder.qualifiedTypeName(), + false)); + Content codeLink = HtmlTree.CODE(link); + Content strong = HtmlTree.STRONG(holder.isClass()? + writer.descfrmClassLabel : writer.descfrmInterfaceLabel); + strong.addContent(writer.getSpace()); + strong.addContent(codeLink); + propertyDocTree.addContent(HtmlTree.DIV(HtmlStyle.block, strong)); + writer.addInlineComment(property, propertyDocTree); + } + } + } + + /** + * {@inheritDoc} + */ + public void addTags(MethodDoc property, Content propertyDocTree) { + writer.addTagsInfo(property, propertyDocTree); + } + + /** + * {@inheritDoc} + */ + public Content getPropertyDetails(Content propertyDetailsTree) { + return getMemberTree(propertyDetailsTree); + } + + /** + * {@inheritDoc} + */ + public Content getPropertyDoc(Content propertyDocTree, + boolean isLastContent) { + return getMemberTree(propertyDocTree, isLastContent); + } + + /** + * Close the writer. + */ + public void close() throws IOException { + writer.close(); + } + + public int getMemberKind() { + return VisibleMemberMap.PROPERTIES; + } + + /** + * {@inheritDoc} + */ + public void addSummaryLabel(Content memberTree) { + Content label = HtmlTree.HEADING(HtmlConstants.SUMMARY_HEADING, + writer.getResource("doclet.Property_Summary")); + memberTree.addContent(label); + } + + /** + * {@inheritDoc} + */ + public String getTableSummary() { + return configuration.getText("doclet.Member_Table_Summary", + configuration.getText("doclet.Property_Summary"), + configuration.getText("doclet.properties")); + } + + /** + * {@inheritDoc} + */ + public String getCaption() { + return configuration.getText("doclet.Properties"); + } + + /** + * {@inheritDoc} + */ + public String[] getSummaryTableHeader(ProgramElementDoc member) { + String[] header = new String[] { + configuration.getText("doclet.Type"), + configuration.getText("doclet.0_and_1", + configuration.getText("doclet.Property"), + configuration.getText("doclet.Description")) + }; + return header; + } + + /** + * {@inheritDoc} + */ + public void addSummaryAnchor(ClassDoc cd, Content memberTree) { + memberTree.addContent(writer.getMarkerAnchor("property_summary")); + } + + /** + * {@inheritDoc} + */ + public void addInheritedSummaryAnchor(ClassDoc cd, Content inheritedTree) { + inheritedTree.addContent(writer.getMarkerAnchor( + "properties_inherited_from_class_" + configuration.getClassName(cd))); + } + + /** + * {@inheritDoc} + */ + public void addInheritedSummaryLabel(ClassDoc cd, Content inheritedTree) { + Content classLink = new RawHtml(writer.getPreQualifiedClassLink( + LinkInfoImpl.CONTEXT_MEMBER, cd, false)); + Content label = new StringContent(cd.isClass() ? + configuration.getText("doclet.Properties_Inherited_From_Class") : + configuration.getText("doclet.Properties_Inherited_From_Interface")); + Content labelHeading = HtmlTree.HEADING(HtmlConstants.INHERITED_SUMMARY_HEADING, + label); + labelHeading.addContent(writer.getSpace()); + labelHeading.addContent(classLink); + inheritedTree.addContent(labelHeading); + } + + /** + * {@inheritDoc} + */ + protected void addSummaryLink(int context, ClassDoc cd, ProgramElementDoc member, + Content tdSummary) { + Content strong = HtmlTree.STRONG(new RawHtml( + writer.getDocLink(context, + cd, + (MemberDoc) member, + member.name().substring(0, member.name().lastIndexOf("Property")), + false, + true))); + + Content code = HtmlTree.CODE(strong); + tdSummary.addContent(code); + } + + /** + * {@inheritDoc} + */ + protected void addInheritedSummaryLink(ClassDoc cd, + ProgramElementDoc member, Content linksTree) { + linksTree.addContent(new RawHtml( + writer.getDocLink(LinkInfoImpl.CONTEXT_MEMBER, cd, (MemberDoc)member, + ((member.name().lastIndexOf("Property") != -1) && configuration.javafx) + ? member.name().substring(0, member.name().length() - "Property".length()) + : member.name(), + false, true))); + } + + /** + * {@inheritDoc} + */ + protected void addSummaryType(ProgramElementDoc member, Content tdSummaryType) { + MethodDoc property = (MethodDoc)member; + addModifierAndType(property, property.returnType(), tdSummaryType); + } + + /** + * {@inheritDoc} + */ + protected Content getDeprecatedLink(ProgramElementDoc member) { + return writer.getDocLink(LinkInfoImpl.CONTEXT_MEMBER, + (MemberDoc) member, ((MethodDoc)member).qualifiedName()); + } + + /** + * {@inheritDoc} + */ + protected Content getNavSummaryLink(ClassDoc cd, boolean link) { + if (link) { + return writer.getHyperLink((cd == null)? + "property_summary": + "properties_inherited_from_class_" + + configuration.getClassName(cd), + writer.getResource("doclet.navProperty")); + } else { + return writer.getResource("doclet.navProperty"); + } + } + + /** + * {@inheritDoc} + */ + protected void addNavDetailLink(boolean link, Content liNav) { + if (link) { + liNav.addContent(writer.getHyperLink("property_detail", + writer.getResource("doclet.navProperty"))); + } else { + liNav.addContent(writer.getResource("doclet.navProperty")); + } + } +} diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/WriterFactoryImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/WriterFactoryImpl.java index 7cbd32984ca..b8a1775c7be 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/WriterFactoryImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/WriterFactoryImpl.java @@ -143,6 +143,15 @@ public class WriterFactoryImpl implements WriterFactory { classWriter.getClassDoc()); } + /** + * {@inheritDoc} + */ + public PropertyWriterImpl getPropertyWriter(ClassWriter classWriter) + throws Exception { + return new PropertyWriterImpl((SubWriterHolderWriter) classWriter, + classWriter.getClassDoc()); + } + /** * {@inheritDoc} */ @@ -174,6 +183,8 @@ public class WriterFactoryImpl implements WriterFactory { return getEnumConstantWriter(classWriter); case VisibleMemberMap.FIELDS: return getFieldWriter(classWriter); + case VisibleMemberMap.PROPERTIES: + return getPropertyWriter(classWriter); case VisibleMemberMap.INNERCLASSES: return new NestedClassWriterImpl((SubWriterHolderWriter) classWriter, classWriter.getClassDoc()); diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlConstants.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlConstants.java index 9830976b94c..7c32503e625 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlConstants.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlConstants.java @@ -111,6 +111,12 @@ public class HtmlConstants { public static final Content START_OF_FIELD_SUMMARY = new Comment("=========== FIELD SUMMARY ==========="); + /** + * Marker to identify start of properties summary. + */ + public static final Content START_OF_PROPERTY_SUMMARY = + new Comment("=========== PROPERTY SUMMARY ==========="); + /** * Marker to identify start of method summary. */ @@ -135,6 +141,12 @@ public class HtmlConstants { public static final Content START_OF_FIELD_DETAILS = new Comment("============ FIELD DETAIL ==========="); + /** + * Marker to identify start of property details. + */ + public static final Content START_OF_PROPERTY_DETAILS = + new Comment("============ PROPERTY DETAIL ==========="); + /** * Marker to identify start of constructor details. */ diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java index 915b37cbce1..f4d04bb69dd 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlWriter.java @@ -148,6 +148,8 @@ public class HtmlWriter { public final Content fieldDetailsLabel; + public final Content propertyDetailsLabel; + public final Content constructorDetailsLabel; public final Content enumConstantsDetailsLabel; @@ -226,6 +228,7 @@ public class HtmlWriter { methodDetailsLabel = getResource("doclet.Method_Detail"); annotationTypeDetailsLabel = getResource("doclet.Annotation_Type_Member_Detail"); fieldDetailsLabel = getResource("doclet.Field_Detail"); + propertyDetailsLabel = getResource("doclet.Property_Detail"); constructorDetailsLabel = getResource("doclet.Constructor_Detail"); enumConstantsDetailsLabel = getResource("doclet.Enum_Constant_Detail"); specifiedByLabel = getResource("doclet.Specified_By"); diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties index f36f7cf4548..1193cf913f9 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties @@ -36,6 +36,7 @@ doclet.navAnnotationTypeOptionalMember=Optional doclet.navAnnotationTypeRequiredMember=Required doclet.navAnnotationTypeMember=Element doclet.navField=Field +doclet.navProperty=Property doclet.navEnum=Enum Constants doclet.navConstructor=Constr doclet.navMethod=Method @@ -44,6 +45,7 @@ doclet.Window_Single_Index=Index doclet.Window_Split_Index={0}-Index doclet.Help=Help doclet.Skip_navigation_links=Skip navigation links +doclet.Navigation=Navigation doclet.New_Page=NewPage doclet.navDeprecated=Deprecated doclet.Window_Deprecated_List=Deprecated List @@ -95,7 +97,7 @@ doclet.Subclasses=Direct Known Subclasses: doclet.Subinterfaces=All Known Subinterfaces: doclet.Implementing_Classes=All Known Implementing Classes: doclet.Functional_Interface=Functional Interface: -doclet.Functional_Interface_Message=This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference. +doclet.Functional_Interface_Message=This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference. doclet.also=also doclet.Frames=Frames doclet.No_Frames=No Frames diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/AbstractDoclet.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/AbstractDoclet.java index fd398aa5346..40c4a980915 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/AbstractDoclet.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/AbstractDoclet.java @@ -80,6 +80,9 @@ public abstract class AbstractDoclet { } try { doclet.startGeneration(root); + } catch (Configuration.Fault f) { + root.printError(f.getMessage()); + return false; } catch (Exception exc) { exc.printStackTrace(); return false; @@ -110,7 +113,7 @@ public abstract class AbstractDoclet { * * @see com.sun.javadoc.RootDoc */ - private void startGeneration(RootDoc root) throws Exception { + private void startGeneration(RootDoc root) throws Configuration.Fault, Exception { if (root.classes().length == 0) { configuration.message. error("doclet.No_Public_Classes_To_Document"); diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java index f393c8d8c68..c34e1dface9 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java @@ -53,6 +53,21 @@ import javax.tools.JavaFileManager; */ public abstract class Configuration { + /** + * Exception used to report a problem during setOptions. + */ + public class Fault extends Exception { + private static final long serialVersionUID = 0; + + Fault(String msg) { + super(msg); + } + + Fault(String msg, Exception cause) { + super(msg, cause); + } + } + /** * The factory for builders. */ @@ -175,6 +190,12 @@ public abstract class Configuration { */ public boolean showauthor = false; + /** + * Generate documentation for JavaFX getters and setters automatically + * by copying it from the appropriate property definition. + */ + public boolean javafx = false; + /** * Generate version specific information for the all the classes * if @version tag is used in the doc comment and if -version option is @@ -251,7 +272,7 @@ public abstract class Configuration { * @param options The array of option names and values. * @throws DocletAbortException */ - public abstract void setSpecificDocletOptions(String[][] options); + public abstract void setSpecificDocletOptions(String[][] options) throws Fault; /** * Return the doclet specific {@link MessageRetriever} @@ -317,6 +338,7 @@ public abstract class Configuration { option = option.toLowerCase(); if (option.equals("-author") || option.equals("-docfilessubdirs") || + option.equals("-javafx") || option.equals("-keywords") || option.equals("-linksource") || option.equals("-nocomment") || @@ -406,15 +428,26 @@ public abstract class Configuration { * * @param options the two dimensional array of options. */ - public void setOptions(String[][] options) { + public void setOptions(String[][] options) throws Fault { LinkedHashSet customTagStrs = new LinkedHashSet(); + + // Some options, specifically -link and -linkoffline, require that + // the output directory has already been created: so do that first. for (int oi = 0; oi < options.length; ++oi) { String[] os = options[oi]; String opt = os[0].toLowerCase(); if (opt.equals("-d")) { destDirName = addTrailingFileSep(os[1]); docFileDestDirName = destDirName; - } else if (opt.equals("-docfilessubdirs")) { + ensureOutputDirExists(); + break; + } + } + + for (int oi = 0; oi < options.length; ++oi) { + String[] os = options[oi]; + String opt = os[0].toLowerCase(); + if (opt.equals("-docfilessubdirs")) { copydocfilesubdirs = true; } else if (opt.equals("-docencoding")) { docencoding = os[1]; @@ -422,6 +455,8 @@ public abstract class Configuration { encoding = os[1]; } else if (opt.equals("-author")) { showauthor = true; + } else if (opt.equals("-javafx")) { + javafx = true; } else if (opt.equals("-nosince")) { nosince = true; } else if (opt.equals("-version")) { @@ -494,7 +529,7 @@ public abstract class Configuration { * * @throws DocletAbortException */ - public void setOptions() { + public void setOptions() throws Fault { initPackageArray(); setOptions(root.options()); if (!profilespath.isEmpty()) { @@ -508,6 +543,23 @@ public abstract class Configuration { setSpecificDocletOptions(root.options()); } + private void ensureOutputDirExists() throws Fault { + DocFile destDir = DocFile.createFileForDirectory(this, destDirName); + if (!destDir.exists()) { + //Create the output directory (in case it doesn't exist yet) + root.printNotice(getText("doclet.dest_dir_create", destDirName)); + destDir.mkdirs(); + } else if (!destDir.isDirectory()) { + throw new Fault(getText( + "doclet.destination_directory_not_directory_0", + destDir.getPath())); + } else if (!destDir.canWrite()) { + throw new Fault(getText( + "doclet.destination_directory_not_writable_0", + destDir.getPath())); + } + } + /** * Initialize the taglet manager. The strings to initialize the simple custom tags should @@ -517,7 +569,7 @@ public abstract class Configuration { */ private void initTagletManager(Set customTagStrs) { tagletManager = tagletManager == null ? - new TagletManager(nosince, showversion, showauthor, message) : + new TagletManager(nosince, showversion, showauthor, javafx, message) : tagletManager; String[] args; for (Iterator it = customTagStrs.iterator(); it.hasNext(); ) { @@ -641,26 +693,7 @@ public abstract class Configuration { for (int oi = 0; oi < options.length; oi++) { String[] os = options[oi]; String opt = os[0].toLowerCase(); - if (opt.equals("-d")) { - String destdirname = addTrailingFileSep(os[1]); - DocFile destDir = DocFile.createFileForDirectory(this, destdirname); - if (!destDir.exists()) { - //Create the output directory (in case it doesn't exist yet) - reporter.printNotice(getText("doclet.dest_dir_create", - destdirname)); - destDir.mkdirs(); - } else if (!destDir.isDirectory()) { - reporter.printError(getText( - "doclet.destination_directory_not_directory_0", - destDir.getPath())); - return false; - } else if (!destDir.canWrite()) { - reporter.printError(getText( - "doclet.destination_directory_not_writable_0", - destDir.getPath())); - return false; - } - } else if (opt.equals("-docencoding")) { + if (opt.equals("-docencoding")) { docencodingfound = true; if (!checkOutputFileEncoding(os[1], reporter)) { return false; diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/PropertyWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/PropertyWriter.java new file mode 100644 index 00000000000..971af7cac31 --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/PropertyWriter.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.doclets.internal.toolkit; + +import java.io.*; +import com.sun.javadoc.*; + +/** + * The interface for writing property output. + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Jamie Ho + * @author Bhavesh Patel (Modified) + * @since 1.7 + */ + +public interface PropertyWriter { + + /** + * Get the property details tree header. + * + * @param classDoc the class being documented + * @param memberDetailsTree the content tree representing member details + * @return content tree for the property details header + */ + public Content getPropertyDetailsTreeHeader(ClassDoc classDoc, + Content memberDetailsTree); + + /** + * Get the property documentation tree header. + * + * @param property the property being documented + * @param propertyDetailsTree the content tree representing property details + * @return content tree for the property documentation header + */ + public Content getPropertyDocTreeHeader(MethodDoc property, + Content propertyDetailsTree); + + /** + * Get the signature for the given property. + * + * @param property the property being documented + * @return content tree for the property signature + */ + public Content getSignature(MethodDoc property); + + /** + * Add the deprecated output for the given property. + * + * @param property the property being documented + * @param propertyDocTree content tree to which the deprecated information will be added + */ + public void addDeprecated(MethodDoc property, Content propertyDocTree); + + /** + * Add the comments for the given property. + * + * @param property the property being documented + * @param propertyDocTree the content tree to which the comments will be added + */ + public void addComments(MethodDoc property, Content propertyDocTree); + + /** + * Add the tags for the given property. + * + * @param property the property being documented + * @param propertyDocTree the content tree to which the tags will be added + */ + public void addTags(MethodDoc property, Content propertyDocTree); + + /** + * Get the property details tree. + * + * @param memberDetailsTree the content tree representing member details + * @return content tree for the property details + */ + public Content getPropertyDetails(Content memberDetailsTree); + + /** + * Get the property documentation. + * + * @param propertyDocTree the content tree representing property documentation + * @param isLastContent true if the content to be added is the last content + * @return content tree for the property documentation + */ + public Content getPropertyDoc(Content propertyDocTree, boolean isLastContent); + + /** + * Close the writer. + */ + public void close() throws IOException; +} diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/WriterFactory.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/WriterFactory.java index 123a3ad9080..1fa4c2f00e9 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/WriterFactory.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/WriterFactory.java @@ -174,6 +174,16 @@ public interface WriterFactory { public abstract FieldWriter getFieldWriter(ClassWriter classWriter) throws Exception; + /** + * Return the property writer for a given class. + * + * @param classWriter the writer for the class being documented. + * @return the property writer for the give class. Return null if this + * writer is not supported by the doclet. + */ + public abstract PropertyWriter getPropertyWriter(ClassWriter classWriter) + throws Exception; + /** * Return the constructor writer for a given class. * diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/AnnotationTypeRequiredMemberBuilder.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/AnnotationTypeRequiredMemberBuilder.java index b44161dab81..84ded901668 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/AnnotationTypeRequiredMemberBuilder.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/AnnotationTypeRequiredMemberBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,7 +86,7 @@ public class AnnotationTypeRequiredMemberBuilder extends AbstractMemberBuilder { this.classDoc = classDoc; this.writer = writer; this.visibleMemberMap = new VisibleMemberMap(classDoc, memberType, - configuration.nodeprecated); + configuration); this.members = new ArrayList( this.visibleMemberMap.getMembersFor(classDoc)); if (configuration.getMemberComparator() != null) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/BuilderFactory.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/BuilderFactory.java index c99349d6c23..7152f2bd4f2 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/BuilderFactory.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/BuilderFactory.java @@ -227,6 +227,19 @@ public class BuilderFactory { writerFactory.getFieldWriter(classWriter)); } + /** + * Return an instance of the property builder for the given class. + * + * @return an instance of the field builder for the given class. + */ + public AbstractBuilder getPropertyBuilder(ClassWriter classWriter) throws Exception { + final PropertyWriter propertyWriter = + writerFactory.getPropertyWriter(classWriter); + return PropertyBuilder.getInstance(context, + classWriter.getClassDoc(), + propertyWriter); + } + /** * Return an instance of the constructor builder for the given class. * diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ClassBuilder.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ClassBuilder.java index efc9d563473..b0d64d59beb 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ClassBuilder.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ClassBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -380,6 +380,17 @@ public class ClassBuilder extends AbstractBuilder { getFieldBuilder(writer).buildChildren(node, memberDetailsTree); } + /** + * Build the property documentation. + * + * @param elements the XML elements that specify how a field is documented. + */ + public void buildPropertyDetails(XMLNode node, + Content memberDetailsTree) throws Exception { + configuration.getBuilderFactory(). + getPropertyBuilder(writer).buildChildren(node, memberDetailsTree); + } + /** * Build the constructor documentation. * diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ConstantsSummaryBuilder.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ConstantsSummaryBuilder.java index bab4f0da24e..c13d4855135 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ConstantsSummaryBuilder.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ConstantsSummaryBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -265,7 +265,7 @@ public class ConstantsSummaryBuilder extends AbstractBuilder { */ private boolean hasConstantField (ClassDoc classDoc) { VisibleMemberMap visibleMemberMapFields = new VisibleMemberMap(classDoc, - VisibleMemberMap.FIELDS, configuration.nodeprecated); + VisibleMemberMap.FIELDS, configuration); List fields = visibleMemberMapFields.getLeafClassMembers(configuration); for (Iterator iter = fields.iterator(); iter.hasNext(); ) { FieldDoc field = (FieldDoc) iter.next(); @@ -323,9 +323,9 @@ public class ConstantsSummaryBuilder extends AbstractBuilder { public ConstantFieldBuilder(ClassDoc classdoc) { this.classdoc = classdoc; visibleMemberMapFields = new VisibleMemberMap(classdoc, - VisibleMemberMap.FIELDS, configuration.nodeprecated); + VisibleMemberMap.FIELDS, configuration); visibleMemberMapEnumConst = new VisibleMemberMap(classdoc, - VisibleMemberMap.ENUM_CONSTANTS, configuration.nodeprecated); + VisibleMemberMap.ENUM_CONSTANTS, configuration); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ConstructorBuilder.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ConstructorBuilder.java index d4cb7061f6c..c744678a112 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ConstructorBuilder.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/ConstructorBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,7 +93,7 @@ public class ConstructorBuilder extends AbstractMemberBuilder { new VisibleMemberMap( classDoc, VisibleMemberMap.CONSTRUCTORS, - configuration.nodeprecated); + configuration); constructors = new ArrayList(visibleMemberMap.getMembersFor(classDoc)); for (int i = 0; i < constructors.size(); i++) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/EnumConstantBuilder.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/EnumConstantBuilder.java index 6ac59cd3034..32127fa428b 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/EnumConstantBuilder.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/EnumConstantBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,7 +87,7 @@ public class EnumConstantBuilder extends AbstractMemberBuilder { new VisibleMemberMap( classDoc, VisibleMemberMap.ENUM_CONSTANTS, - configuration.nodeprecated); + configuration); enumConstants = new ArrayList(visibleMemberMap.getMembersFor(classDoc)); if (configuration.getMemberComparator() != null) { diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/FieldBuilder.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/FieldBuilder.java index a9dbec3bd74..98bde47b13d 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/FieldBuilder.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/FieldBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,7 +88,7 @@ public class FieldBuilder extends AbstractMemberBuilder { new VisibleMemberMap( classDoc, VisibleMemberMap.FIELDS, - configuration.nodeprecated); + configuration); fields = new ArrayList(visibleMemberMap.getLeafClassMembers( configuration)); diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/MemberSummaryBuilder.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/MemberSummaryBuilder.java index aef27a1501a..0eb548ff9e8 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/MemberSummaryBuilder.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/MemberSummaryBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package com.sun.tools.doclets.internal.toolkit.builders; import java.util.*; +import java.text.MessageFormat; import com.sun.javadoc.*; import com.sun.tools.doclets.internal.toolkit.*; @@ -82,7 +83,7 @@ public class MemberSummaryBuilder extends AbstractMemberBuilder { new VisibleMemberMap( classDoc, i, - configuration.nodeprecated); + configuration); } } @@ -253,6 +254,17 @@ public class MemberSummaryBuilder extends AbstractMemberBuilder { addSummary(writer, visibleMemberMap, true, memberSummaryTree); } + /** + * Build the summary for the fields. + */ + public void buildPropertiesSummary(XMLNode node, Content memberSummaryTree) { + MemberSummaryWriter writer = + memberSummaryWriters[VisibleMemberMap.PROPERTIES]; + VisibleMemberMap visibleMemberMap = + visibleMemberMaps[VisibleMemberMap.PROPERTIES]; + addSummary(writer, visibleMemberMap, true, memberSummaryTree); + } + /** * Build the summary for the nested classes. * @@ -311,6 +323,11 @@ public class MemberSummaryBuilder extends AbstractMemberBuilder { List tableContents = new LinkedList(); for (int i = 0; i < members.size(); i++) { ProgramElementDoc member = members.get(i); + final ProgramElementDoc propertyDoc = + visibleMemberMap.getPropertyMemberDoc(member); + if (propertyDoc != null) { + processProperty(visibleMemberMap, member, propertyDoc); + } Tag[] firstSentenceTags = member.firstSentenceTags(); if (member instanceof MethodDoc && firstSentenceTags.length == 0) { //Inherit comments from overriden or implemented method if @@ -329,6 +346,106 @@ public class MemberSummaryBuilder extends AbstractMemberBuilder { } } + /** + * Process the property method, property setter and/or property getter + * comment text so that it contains the documentation from + * the property field. The method adds the leading sentence, + * copied documentation including the defaultValue tag and + * the see tags if the appropriate property getter and setter are + * available. + * + * @param visibleMemberMap the members information. + * @param member the member which is to be augmented. + * @param propertyDoc the original property documentation. + */ + private void processProperty(VisibleMemberMap visibleMemberMap, + ProgramElementDoc member, + ProgramElementDoc propertyDoc) { + StringBuilder commentTextBuilder = new StringBuilder(); + final boolean isSetter = isSetter(member); + final boolean isGetter = isGetter(member); + if (isGetter || isSetter) { + //add "[GS]ets the value of the property PROPERTY_NAME." + if (isSetter) { + commentTextBuilder.append( + MessageFormat.format( + configuration.getText("doclet.PropertySetterWithName"), + Util.propertyNameFromMethodName(member.name()))); + } + if (isGetter) { + commentTextBuilder.append( + MessageFormat.format( + configuration.getText("doclet.PropertyGetterWithName"), + Util.propertyNameFromMethodName(member.name()))); + } + if (propertyDoc.commentText() != null + && !propertyDoc.commentText().isEmpty()) { + commentTextBuilder.append(" \n @propertyDescription "); + } + } + commentTextBuilder.append(propertyDoc.commentText()); + + Tag[] tags = propertyDoc.tags("@defaultValue"); + if (tags != null) { + for (Tag tag: tags) { + commentTextBuilder.append("\n") + .append(tag.name()) + .append(" ") + .append(tag.text()); + } + } + + //add @see tags + if (!isGetter && !isSetter) { + MethodDoc getter = (MethodDoc) visibleMemberMap.getGetterForProperty(member); + MethodDoc setter = (MethodDoc) visibleMemberMap.getSetterForProperty(member); + + if ((null != getter) + && (commentTextBuilder.indexOf("@see #" + getter.name()) == -1)) { + commentTextBuilder.append("\n @see #") + .append(getter.name()) + .append("() "); + } + + if ((null != setter) + && (commentTextBuilder.indexOf("@see #" + setter.name()) == -1)) { + String typeName = setter.parameters()[0].typeName(); + // Removal of type parameters and package information. + typeName = typeName.split("<")[0]; + if (typeName.contains(".")) { + typeName = typeName.substring(typeName.lastIndexOf(".") + 1); + } + commentTextBuilder.append("\n @see #").append(setter.name()); + + if (setter.parameters()[0].type().asTypeVariable() == null) { + commentTextBuilder.append("(").append(typeName).append(")"); + } + commentTextBuilder.append(" \n"); + } + } + member.setRawCommentText(commentTextBuilder.toString()); + } + /** + * Test whether the method is a getter. + * @param ped property method documentation. Needs to be either property + * method, property getter, or property setter. + * @return true if the given documentation belongs to a getter. + */ + private boolean isGetter(ProgramElementDoc ped) { + final String pedName = ped.name(); + return pedName.startsWith("get") || pedName.startsWith("is"); + } + + /** + * Test whether the method is a setter. + * @param ped property method documentation. Needs to be either property + * method, property getter, or property setter. + * @return true if the given documentation belongs to a setter. + */ + private boolean isSetter(ProgramElementDoc ped) { + return ped.name().startsWith("set"); + } + /** * Build the inherited member summary for the given methods. * diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/MethodBuilder.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/MethodBuilder.java index 2c9b10c93ba..23008798080 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/MethodBuilder.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/MethodBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,7 +88,7 @@ public class MethodBuilder extends AbstractMemberBuilder { visibleMemberMap = new VisibleMemberMap( classDoc, VisibleMemberMap.METHODS, - configuration.nodeprecated); + configuration); methods = new ArrayList(visibleMemberMap.getLeafClassMembers( configuration)); diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PackageSummaryBuilder.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PackageSummaryBuilder.java index a40968da070..abe2740f9ce 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PackageSummaryBuilder.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PackageSummaryBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -176,6 +176,7 @@ public class PackageSummaryBuilder extends AbstractBuilder { ? packageDoc.interfaces() : configuration.classDocCatalog.interfaces( Util.getPackageName(packageDoc)); + interfaces = Util.filterOutPrivateClasses(interfaces, configuration.javafx); if (interfaces.length > 0) { packageWriter.addClassesSummary( interfaces, @@ -205,6 +206,7 @@ public class PackageSummaryBuilder extends AbstractBuilder { ? packageDoc.ordinaryClasses() : configuration.classDocCatalog.ordinaryClasses( Util.getPackageName(packageDoc)); + classes = Util.filterOutPrivateClasses(classes, configuration.javafx); if (classes.length > 0) { packageWriter.addClassesSummary( classes, @@ -234,6 +236,7 @@ public class PackageSummaryBuilder extends AbstractBuilder { ? packageDoc.enums() : configuration.classDocCatalog.enums( Util.getPackageName(packageDoc)); + enums = Util.filterOutPrivateClasses(enums, configuration.javafx); if (enums.length > 0) { packageWriter.addClassesSummary( enums, @@ -263,6 +266,7 @@ public class PackageSummaryBuilder extends AbstractBuilder { ? packageDoc.exceptions() : configuration.classDocCatalog.exceptions( Util.getPackageName(packageDoc)); + exceptions = Util.filterOutPrivateClasses(exceptions, configuration.javafx); if (exceptions.length > 0) { packageWriter.addClassesSummary( exceptions, @@ -292,6 +296,7 @@ public class PackageSummaryBuilder extends AbstractBuilder { ? packageDoc.errors() : configuration.classDocCatalog.errors( Util.getPackageName(packageDoc)); + errors = Util.filterOutPrivateClasses(errors, configuration.javafx); if (errors.length > 0) { packageWriter.addClassesSummary( errors, @@ -321,6 +326,7 @@ public class PackageSummaryBuilder extends AbstractBuilder { ? packageDoc.annotationTypes() : configuration.classDocCatalog.annotationTypes( Util.getPackageName(packageDoc)); + annotationTypes = Util.filterOutPrivateClasses(annotationTypes, configuration.javafx); if (annotationTypes.length > 0) { packageWriter.addClassesSummary( annotationTypes, diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PropertyBuilder.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PropertyBuilder.java new file mode 100644 index 00000000000..6430da64e3d --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/PropertyBuilder.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.doclets.internal.toolkit.builders; + +import java.util.*; + +import com.sun.tools.doclets.internal.toolkit.util.*; +import com.sun.tools.doclets.internal.toolkit.*; +import com.sun.javadoc.*; + +/** + * Builds documentation for a property. + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @author Jamie Ho + * @author Bhavesh Patel (Modified) + * @since 1.7 + */ +public class PropertyBuilder extends AbstractMemberBuilder { + + /** + * The class whose properties are being documented. + */ + private final ClassDoc classDoc; + + /** + * The visible properties for the given class. + */ + private final VisibleMemberMap visibleMemberMap; + + /** + * The writer to output the property documentation. + */ + private final PropertyWriter writer; + + /** + * The list of properties being documented. + */ + private final List properties; + + /** + * The index of the current property that is being documented at this point + * in time. + */ + private int currentPropertyIndex; + + /** + * Construct a new PropertyBuilder. + * + * @param context the build context. + * @param classDoc the class whoses members are being documented. + * @param writer the doclet specific writer. + */ + private PropertyBuilder(Context context, + ClassDoc classDoc, + PropertyWriter writer) { + super(context); + this.classDoc = classDoc; + this.writer = writer; + visibleMemberMap = + new VisibleMemberMap( + classDoc, + VisibleMemberMap.PROPERTIES, + configuration); + properties = + new ArrayList(visibleMemberMap.getMembersFor(classDoc)); + if (configuration.getMemberComparator() != null) { + Collections.sort(properties, configuration.getMemberComparator()); + } + } + + /** + * Construct a new PropertyBuilder. + * + * @param context the build context. + * @param classDoc the class whoses members are being documented. + * @param writer the doclet specific writer. + */ + public static PropertyBuilder getInstance(Context context, + ClassDoc classDoc, + PropertyWriter writer) { + return new PropertyBuilder(context, classDoc, writer); + } + + /** + * {@inheritDoc} + */ + public String getName() { + return "PropertyDetails"; + } + + /** + * Returns a list of properties that will be documented for the given class. + * This information can be used for doclet specific documentation + * generation. + * + * @param classDoc the {@link ClassDoc} we want to check. + * @return a list of properties that will be documented. + */ + public List members(ClassDoc classDoc) { + return visibleMemberMap.getMembersFor(classDoc); + } + + /** + * Returns the visible member map for the properties of this class. + * + * @return the visible member map for the properties of this class. + */ + public VisibleMemberMap getVisibleMemberMap() { + return visibleMemberMap; + } + + /** + * summaryOrder.size() + */ + public boolean hasMembersToDocument() { + return properties.size() > 0; + } + + /** + * Build the property documentation. + * + * @param node the XML element that specifies which components to document + * @param memberDetailsTree the content tree to which the documentation will be added + */ + public void buildPropertyDoc(XMLNode node, Content memberDetailsTree) { + if (writer == null) { + return; + } + int size = properties.size(); + if (size > 0) { + Content propertyDetailsTree = writer.getPropertyDetailsTreeHeader( + classDoc, memberDetailsTree); + for (currentPropertyIndex = 0; currentPropertyIndex < size; + currentPropertyIndex++) { + Content propertyDocTree = writer.getPropertyDocTreeHeader( + (MethodDoc) properties.get(currentPropertyIndex), + propertyDetailsTree); + buildChildren(node, propertyDocTree); + propertyDetailsTree.addContent(writer.getPropertyDoc( + propertyDocTree, (currentPropertyIndex == size - 1))); + } + memberDetailsTree.addContent( + writer.getPropertyDetails(propertyDetailsTree)); + } + } + + /** + * Build the signature. + * + * @param node the XML element that specifies which components to document + * @param propertyDocTree the content tree to which the documentation will be added + */ + public void buildSignature(XMLNode node, Content propertyDocTree) { + propertyDocTree.addContent( + writer.getSignature((MethodDoc) properties.get(currentPropertyIndex))); + } + + /** + * Build the deprecation information. + * + * @param node the XML element that specifies which components to document + * @param propertyDocTree the content tree to which the documentation will be added + */ + public void buildDeprecationInfo(XMLNode node, Content propertyDocTree) { + writer.addDeprecated( + (MethodDoc) properties.get(currentPropertyIndex), propertyDocTree); + } + + /** + * Build the comments for the property. Do nothing if + * {@link Configuration#nocomment} is set to true. + * + * @param node the XML element that specifies which components to document + * @param propertyDocTree the content tree to which the documentation will be added + */ + public void buildPropertyComments(XMLNode node, Content propertyDocTree) { + if (!configuration.nocomment) { + writer.addComments((MethodDoc) properties.get(currentPropertyIndex), propertyDocTree); + } + } + + /** + * Build the tag information. + * + * @param node the XML element that specifies which components to document + * @param propertyDocTree the content tree to which the documentation will be added + */ + public void buildTagInfo(XMLNode node, Content propertyDocTree) { + writer.addTags((MethodDoc) properties.get(currentPropertyIndex), propertyDocTree); + } + + /** + * Return the property writer for this builder. + * + * @return the property writer for this builder. + */ + public PropertyWriter getWriter() { + return writer; + } +} diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml index c4e408f4cae..aabaafff250 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nashorn/buildtools/nasgen/nasgen.iml b/nashorn/buildtools/nasgen/nasgen.iml new file mode 100644 index 00000000000..f6c890a2ddc --- /dev/null +++ b/nashorn/buildtools/nasgen/nasgen.iml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + diff --git a/langtools/test/tools/javah/6257087/foo.sh b/nashorn/buildtools/nasgen/project.properties similarity index 52% rename from langtools/test/tools/javah/6257087/foo.sh rename to nashorn/buildtools/nasgen/project.properties index e141e623db5..5963f68e5c3 100644 --- a/langtools/test/tools/javah/6257087/foo.sh +++ b/nashorn/buildtools/nasgen/project.properties @@ -1,74 +1,52 @@ -#! /bin/sh -f - # -# Copyright (c) 2006, 2009, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# +# # This code is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License version 2 only, as # published by the Free Software Foundation. -# +# # This code is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # version 2 for more details (a copy is included in the LICENSE file that # accompanied this code). -# +# # You should have received a copy of the GNU General Public License version # 2 along with this work; if not, write to the Free Software Foundation, # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# +# # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. # +application.title=nasgen -# -# @test -# @bug 6257087 -# @run shell foo.sh +# source and target levels +build.compiler=modern +javac.source=1.7 +javac.target=1.7 +build.classes.dir=${build.dir}/classes -TS=${TESTSRC-.} -TC=${TESTCLASSES-.} +# This directory is removed when the project is cleaned: +build.dir=build -if [ "${TESTJAVA}" = "" ] -then - echo "TESTJAVA not set. Test cannot execute. Failed." - exit 1 -fi +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/nasgen.jar +dist.javadoc.dir=${dist.dir}/javadoc -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - SunOS | Linux | Darwin ) - PS=":" - FS="/" - ;; - CYGWIN* ) - PS=":" - FS="/" - DIFFOPTS="--strip-trailing-cr" - ;; - Windows* ) - PS=";" - FS="\\" - ;; - * ) - echo "Unrecognized system!" - exit 1; - ;; -esac +nashorn.dir=../../ -"${TESTJAVA}${FS}bin${FS}javac" ${TESTTOOLVMOPTS} -d "${TC}" "${TS}${FS}foo.java" -"${TESTJAVA}${FS}bin${FS}javah" ${TESTTOOLVMOPTS} -classpath "${TC}" -d "${TC}" foo -diff ${DIFFOPTS} -c "${TS}${FS}foo_bar.h" "${TC}${FS}foo_bar.h" -result=$? +javac.debug=true -if [ $result -eq 0 ] -then - echo "Passed" -else - echo "Failed" -fi -exit $result +javac.classpath=\ + ${nashorn.dir}/build/classes + +meta.inf.dir=${src.dir}/META-INF +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +run.jvmargs= +src.dir=src diff --git a/nashorn/buildtools/nasgen/src/META-INF/MANIFEST.MF b/nashorn/buildtools/nasgen/src/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..b70986369a1 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/META-INF/MANIFEST.MF @@ -0,0 +1,4 @@ +Manifest-Version: 1.0 +Class-Path: lib/ant-1.7.1.jar +Main-Class: jdk.nashorn.internal.tools.nasgen.Main + diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java new file mode 100644 index 00000000000..808f2658046 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java @@ -0,0 +1,334 @@ +/* + * 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.tools.nasgen; + +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE; +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.CLINIT; +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.LOOKUP_NEWPROPERTY; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_NEWPROPERTY_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_NEWMAP; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_NEWMAP_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_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; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SETTER_PREFIX; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_OBJECT; + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.List; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Type; +import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind; + +/** + * Base class for class generator classes. + * + */ +public class ClassGenerator { + /** ASM class writer used to output bytecode for this class */ + protected final ClassWriter cw; + + /** + * Constructor + */ + protected ClassGenerator() { + this.cw = makeClassWriter(); + } + + MethodGenerator makeStaticInitializer() { + return makeStaticInitializer(cw); + } + + MethodGenerator makeConstructor() { + return makeConstructor(cw); + } + + MethodGenerator makeMethod(final int access, final String name, final String desc) { + return makeMethod(cw, access, name, desc); + } + + void addMapField() { + addMapField(cw); + } + + void addField(final String name, final String desc) { + addField(cw, name, desc); + } + + void addFunctionField(final String name) { + addFunctionField(cw, name); + } + + void addGetter(final String owner, final MemberInfo memInfo) { + addGetter(cw, owner, memInfo); + } + + void addSetter(final String owner, final MemberInfo memInfo) { + addSetter(cw, owner, memInfo); + } + + void emitGetClassName(final String name) { + final MethodGenerator mi = makeMethod(ACC_PUBLIC, GET_CLASS_NAME, GET_CLASS_NAME_DESC); + mi.loadLiteral(name); + mi.returnValue(); + mi.computeMaxs(); + mi.visitEnd(); + } + + static ClassWriter makeClassWriter() { + return new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) { + @Override + protected String getCommonSuperClass(final String type1, final String type2) { + try { + return super.getCommonSuperClass(type1, type2); + } catch (final RuntimeException | LinkageError e) { + return StringConstants.OBJECT_TYPE; + } + } + }; + } + + static MethodGenerator makeStaticInitializer(final ClassVisitor cv) { + return makeStaticInitializer(cv, CLINIT); + } + + static MethodGenerator makeStaticInitializer(final ClassVisitor cv, final String name) { + final int access = ACC_PUBLIC | ACC_STATIC; + final String desc = DEFAULT_INIT_DESC; + final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null); + return new MethodGenerator(mv, access, name, desc); + } + + static MethodGenerator makeConstructor(final ClassVisitor cv) { + final int access = ACC_PUBLIC; + final String name = INIT; + final String desc = DEFAULT_INIT_DESC; + final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null); + return new MethodGenerator(mv, access, name, desc); + } + + static MethodGenerator makeMethod(final ClassVisitor cv, final int access, final String name, final String desc) { + final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null); + return new MethodGenerator(mv, access, name, desc); + } + + static void emitStaticInitPrefix(final MethodGenerator mi, final String className) { + mi.visitCode(); + mi.pushNull(); + mi.putStatic(className, MAP_FIELD_NAME, MAP_DESC); + mi.loadClass(className); + mi.invokeStatic(MAP_TYPE, MAP_NEWMAP, MAP_NEWMAP_DESC); + mi.storeLocal(0); + } + + static void emitStaticInitSuffix(final MethodGenerator mi, final String className) { + mi.loadLocal(0); + mi.putStatic(className, MAP_FIELD_NAME, MAP_DESC); + mi.returnVoid(); + mi.computeMaxs(); + mi.visitEnd(); + } + + @SuppressWarnings("fallthrough") + private static Type memInfoType(final MemberInfo memInfo) { + switch (memInfo.getJavaDesc().charAt(0)) { + case 'I': return Type.INT_TYPE; + case 'J': return Type.LONG_TYPE; + case 'D': return Type.DOUBLE_TYPE; + default: assert false : memInfo.getJavaDesc(); + case 'L': return TYPE_OBJECT; + } + } + + private static String getterDesc(final MemberInfo memInfo) { + return Type.getMethodDescriptor(memInfoType(memInfo)); + } + + private static String setterDesc(final MemberInfo memInfo) { + return Type.getMethodDescriptor(Type.VOID_TYPE, memInfoType(memInfo)); + } + + static void addGetter(final ClassVisitor cv, final String owner, final MemberInfo memInfo) { + final int access = ACC_PUBLIC; + final String name = GETTER_PREFIX + memInfo.getJavaName(); + final String desc = getterDesc(memInfo); + final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null); + final MethodGenerator mi = new MethodGenerator(mv, access, name, desc); + mi.visitCode(); + if (memInfo.isStatic() && memInfo.getKind() == Kind.PROPERTY) { + mi.getStatic(owner, memInfo.getJavaName(), memInfo.getJavaDesc()); + } else { + mi.loadLocal(0); + mi.getField(owner, memInfo.getJavaName(), memInfo.getJavaDesc()); + } + mi.returnValue(); + mi.computeMaxs(); + mi.visitEnd(); + } + + static void addSetter(final ClassVisitor cv, final String owner, final MemberInfo memInfo) { + final int access = ACC_PUBLIC; + final String name = SETTER_PREFIX + memInfo.getJavaName(); + final String desc = setterDesc(memInfo); + final MethodVisitor mv = cv.visitMethod(access, name, desc, null, null); + final MethodGenerator mi = new MethodGenerator(mv, access, name, desc); + mi.visitCode(); + if (memInfo.isStatic() && memInfo.getKind() == Kind.PROPERTY) { + mi.loadLocal(1); + mi.putStatic(owner, memInfo.getJavaName(), memInfo.getJavaDesc()); + } else { + mi.loadLocal(0); + mi.loadLocal(1); + mi.putField(owner, memInfo.getJavaName(), memInfo.getJavaDesc()); + } + mi.returnVoid(); + mi.computeMaxs(); + mi.visitEnd(); + } + + static void addMapField(final ClassVisitor cv) { + // add a MAP static field + final FieldVisitor fv = cv.visitField(ACC_PRIVATE | ACC_STATIC, + MAP_FIELD_NAME, MAP_DESC, null, null); + if (fv != null) { + fv.visitEnd(); + } + } + + static void addField(final ClassVisitor cv, final String name, final String desc) { + final FieldVisitor fv = cv.visitField(ACC_PRIVATE, name, desc, null, null); + if (fv != null) { + fv.visitEnd(); + } + } + + static void addFunctionField(final ClassVisitor cv, final String name) { + addField(cv, name, OBJECT_DESC); + } + + static void newFunction(final MethodGenerator mi, final String className, final MemberInfo memInfo, final List specs) { + final boolean arityFound = (memInfo.getArity() != MemberInfo.DEFAULT_ARITY); + + mi.loadLiteral(memInfo.getName()); + mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className, memInfo.getJavaName(), memInfo.getJavaDesc())); + + assert specs != null; + if (!specs.isEmpty()) { + mi.memberInfoArray(className, specs); + mi.invokeStatic(SCRIPTFUNCTIONIMPL_TYPE, SCRIPTFUNCTIONIMPL_MAKEFUNCTION, SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC); + } else { + mi.invokeStatic(SCRIPTFUNCTIONIMPL_TYPE, SCRIPTFUNCTIONIMPL_MAKEFUNCTION, SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC); + } + + if (arityFound) { + mi.dup(); + mi.push(memInfo.getArity()); + mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY, SCRIPTFUNCTION_SETARITY_DESC); + } + + } + + static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo memInfo) { + final String propertyName = memInfo.getName(); + mi.loadLocal(0); + mi.loadLiteral(propertyName); + // setup flags + mi.push(memInfo.getAttributes()); + // setup getter method handle + String javaName = GETTER_PREFIX + memInfo.getJavaName(); + mi.visitLdcInsn(new Handle(H_INVOKEVIRTUAL, className, javaName, getterDesc(memInfo))); + // setup setter method handle + if (memInfo.isFinal()) { + mi.pushNull(); + } else { + javaName = SETTER_PREFIX + memInfo.getJavaName(); + mi.visitLdcInsn(new Handle(H_INVOKEVIRTUAL, className, javaName, setterDesc(memInfo))); + } + mi.invokeStatic(LOOKUP_TYPE, LOOKUP_NEWPROPERTY, LOOKUP_NEWPROPERTY_DESC); + mi.storeLocal(0); + } + + static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo getter, final MemberInfo setter) { + final String propertyName = getter.getName(); + mi.loadLocal(0); + mi.loadLiteral(propertyName); + // setup flags + mi.push(getter.getAttributes()); + // setup getter method handle + mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className, + getter.getJavaName(), getter.getJavaDesc())); + // setup setter method handle + if (setter == null) { + mi.pushNull(); + } else { + mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className, + setter.getJavaName(), setter.getJavaDesc())); + } + mi.invokeStatic(LOOKUP_TYPE, LOOKUP_NEWPROPERTY, LOOKUP_NEWPROPERTY_DESC); + mi.storeLocal(0); + } + + static ScriptClassInfo getScriptClassInfo(final String fileName) throws IOException { + try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName))) { + return getScriptClassInfo(new ClassReader(bis)); + } + } + + static ScriptClassInfo getScriptClassInfo(final byte[] classBuf) { + return getScriptClassInfo(new ClassReader(classBuf)); + } + + private static ScriptClassInfo getScriptClassInfo(final ClassReader reader) { + final ScriptClassInfoCollector scic = new ScriptClassInfoCollector(); + reader.accept(scic, 0); + return scic.getScriptClassInfo(); + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java new file mode 100644 index 00000000000..836cb8930c0 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java @@ -0,0 +1,276 @@ +/* + * 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.tools.nasgen; + +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; +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.MAP_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPE; +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; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_INIT_DESC3; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_INIT_DESC4; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; +import jdk.internal.org.objectweb.asm.Handle; + +/** + * This class generates constructor class for a @ClassInfo annotated class. + * + */ +public class ConstructorGenerator extends ClassGenerator { + private final ScriptClassInfo scriptClassInfo; + private final String className; + private final MemberInfo constructor; + private final int memberCount; + private final List specs; + + ConstructorGenerator(final ScriptClassInfo sci) { + this.scriptClassInfo = sci; + + this.className = scriptClassInfo.getConstructorClassName(); + this.constructor = scriptClassInfo.getConstructor(); + this.memberCount = scriptClassInfo.getConstructorMemberCount(); + this.specs = scriptClassInfo.getSpecializedConstructors(); + } + + byte[] getClassBytes() { + // new class extensing from ScriptObject + final String superClass = (constructor != null)? SCRIPTFUNCTIONIMPL_TYPE : SCRIPTOBJECT_TYPE; + cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, className, null, superClass, null); + if (memberCount > 0) { + // add fields + emitFields(); + // add + emitStaticInitializer(); + } + // add + emitConstructor(); + + if (constructor == null) { + emitGetClassName(scriptClassInfo.getName()); + } + + cw.visitEnd(); + return cw.toByteArray(); + } + + // --Internals only below this point + private void emitFields() { + // Introduce "Function" type instance fields for each + // constructor @Function in script class and introduce instance + // fields for each constructor @Property in the script class. + for (MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (memInfo.isConstructorFunction()) { + addFunctionField(memInfo.getJavaName()); + memInfo = (MemberInfo)memInfo.clone(); + memInfo.setJavaDesc(OBJECT_DESC); + memInfo.setJavaAccess(ACC_PUBLIC); + addGetter(className, memInfo); + addSetter(className, memInfo); + } else if (memInfo.isConstructorProperty()) { + if (memInfo.isStaticFinal()) { + addGetter(scriptClassInfo.getJavaName(), memInfo); + } else { + addField(memInfo.getJavaName(), memInfo.getJavaDesc()); + memInfo = (MemberInfo)memInfo.clone(); + memInfo.setJavaAccess(ACC_PUBLIC); + addGetter(className, memInfo); + addSetter(className, memInfo); + } + } + } + + addMapField(); + } + + private void emitStaticInitializer() { + final MethodGenerator mi = makeStaticInitializer(); + emitStaticInitPrefix(mi, className); + + for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (memInfo.isConstructorFunction() || memInfo.isConstructorProperty()) { + linkerAddGetterSetter(mi, className, memInfo); + } else if (memInfo.isConstructorGetter()) { + final MemberInfo setter = scriptClassInfo.findSetter(memInfo); + linkerAddGetterSetter(mi, scriptClassInfo.getJavaName(), memInfo, setter); + } + } + emitStaticInitSuffix(mi, className); + } + + private void emitConstructor() { + final MethodGenerator mi = makeConstructor(); + mi.visitCode(); + callSuper(mi); + + if (memberCount > 0) { + // initialize Function type fields + initFunctionFields(mi); + // initialize data fields + initDataFields(mi); + } + + if (constructor != null) { + final int arity = constructor.getArity(); + if (arity != MemberInfo.DEFAULT_ARITY) { + mi.loadThis(); + mi.push(arity); + mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY, + SCRIPTFUNCTION_SETARITY_DESC); + } + } + mi.returnVoid(); + mi.computeMaxs(); + mi.visitEnd(); + } + + private void loadMap(final MethodGenerator mi) { + if (memberCount > 0) { + mi.getStatic(className, MAP_FIELD_NAME, MAP_DESC); + // make sure we use duplicated PropertyMap so that original map + // stays intact and so can be used for many globals in same context + mi.invokeVirtual(MAP_TYPE, MAP_DUPLICATE, MAP_DUPLICATE_DESC); + } + } + + private void callSuper(final MethodGenerator mi) { + String superClass, superDesc; + mi.loadThis(); + if (constructor == null) { + // call ScriptObject. + superClass = SCRIPTOBJECT_TYPE; + superDesc = (memberCount > 0) ? SCRIPTOBJECT_INIT_DESC : DEFAULT_INIT_DESC; + loadMap(mi); + } else { + // call Function. + superClass = SCRIPTFUNCTIONIMPL_TYPE; + superDesc = (memberCount > 0) ? SCRIPTFUNCTIONIMPL_INIT_DESC4 : SCRIPTFUNCTIONIMPL_INIT_DESC3; + mi.loadLiteral(constructor.getName()); + mi.visitLdcInsn(new Handle(H_INVOKESTATIC, scriptClassInfo.getJavaName(), constructor.getJavaName(), constructor.getJavaDesc())); + loadMap(mi); + mi.memberInfoArray(scriptClassInfo.getJavaName(), specs); //pushes null if specs empty + } + + mi.invokeSpecial(superClass, INIT, superDesc); + } + + private void initFunctionFields(final MethodGenerator mi) { + for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (!memInfo.isConstructorFunction()) { + continue; + } + mi.loadThis(); + newFunction(mi, scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName())); + mi.putField(className, memInfo.getJavaName(), OBJECT_DESC); + } + } + + private void initDataFields(final MethodGenerator mi) { + for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (!memInfo.isConstructorProperty() || memInfo.isFinal()) { + continue; + } + final Object value = memInfo.getValue(); + if (value != null) { + mi.loadThis(); + mi.loadLiteral(value); + mi.putField(className, memInfo.getJavaName(), memInfo.getJavaDesc()); + } else if (!memInfo.getInitClass().isEmpty()) { + final String clazz = memInfo.getInitClass(); + mi.loadThis(); + mi.newObject(clazz); + mi.dup(); + mi.invokeSpecial(clazz, INIT, DEFAULT_INIT_DESC); + mi.putField(className, memInfo.getJavaName(), memInfo.getJavaDesc()); + } + } + + if (constructor != null) { + mi.loadThis(); + final String protoName = scriptClassInfo.getPrototypeClassName(); + mi.newObject(protoName); + mi.dup(); + mi.invokeSpecial(protoName, INIT, DEFAULT_INIT_DESC); + mi.dup(); + mi.loadThis(); + mi.invokeStatic(PROTOTYPEOBJECT_TYPE, PROTOTYPEOBJECT_SETCONSTRUCTOR, + PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC); + mi.putField(SCRIPTFUNCTION_TYPE, PROTOTYPE, OBJECT_DESC); + } + } + + /** + * Entry point for ConstructorGenerator run separately as an application. Will display + * usage. Takes one argument, a class name. + * @param args args vector + * @throws IOException if class can't be read + */ + public static void main(final String[] args) throws IOException { + if (args.length != 1) { + System.err.println("Usage: " + ConstructorGenerator.class.getName() + " "); + System.exit(1); + } + + final String className = args[0].replace('.', '/'); + final ScriptClassInfo sci = getScriptClassInfo(className + ".class"); + if (sci == null) { + System.err.println("No @ScriptClass in " + className); + System.exit(2); + throw new IOException(); // get rid of warning for sci.verify() below - may be null + } + + try { + sci.verify(); + } catch (final Exception e) { + System.err.println(e.getMessage()); + System.exit(3); + } + final ConstructorGenerator gen = new ConstructorGenerator(sci); + try (FileOutputStream fos = new FileOutputStream(className + CONSTRUCTOR_SUFFIX + ".class")) { + fos.write(gen.getClassBytes()); + } + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/Main.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/Main.java new file mode 100644 index 00000000000..7c8439b3319 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/Main.java @@ -0,0 +1,181 @@ +/* + * 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.tools.nasgen; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.util.CheckClassAdapter; + +/** + * Main class for the "nasgen" tool. + * + */ +public class Main { + private static final boolean DEBUG = Boolean.getBoolean("nasgen.debug"); + + private interface ErrorReporter { + public void error(String msg); + } + + /** + * Public entry point for Nasgen if invoked from command line. Nasgen takes three arguments + * in order: input directory, package list, output directory + * + * @param args argument vector + */ + public static void main(final String[] args) { + final ErrorReporter reporter = new ErrorReporter() { + @Override + public void error(final String msg) { + Main.error(msg, 1); + } + }; + if (args.length == 3) { + processAll(args[0], args[1], args[2], reporter); + } else { + error("Usage: nasgen ", 1); + } + } + + private static void processAll(final String in, final String pkgList, final String out, final ErrorReporter reporter) { + final File inDir = new File(in); + if (!inDir.exists() || !inDir.isDirectory()) { + reporter.error(in + " does not exist or not a directory"); + return; + } + + final File outDir = new File(out); + if (!outDir.exists() || !outDir.isDirectory()) { + reporter.error(out + " does not exist or not a directory"); + return; + } + + final String[] packages = pkgList.split(":"); + for (String pkg : packages) { + pkg = pkg.replace('.', File.separatorChar); + final File dir = new File(inDir, pkg); + final File[] classes = dir.listFiles(); + for (final File clazz : classes) { + if (clazz.isFile() && clazz.getName().endsWith(".class")) { + if (! process(clazz, new File(outDir, pkg), reporter)) { + return; + } + } + } + } + } + + private static boolean process(final File inFile, final File outDir, final ErrorReporter reporter) { + try { + byte[] buf = new byte[(int)inFile.length()]; + + try (FileInputStream fin = new FileInputStream(inFile)) { + fin.read(buf); + } + + final ScriptClassInfo sci = ClassGenerator.getScriptClassInfo(buf); + + if (sci != null) { + try { + sci.verify(); + } catch (final Exception e) { + reporter.error(e.getMessage()); + return false; + } + + // create necessary output package dir + outDir.mkdirs(); + + // instrument @ScriptClass + final ClassWriter writer = ClassGenerator.makeClassWriter(); + final ClassReader reader = new ClassReader(buf); + final ScriptClassInstrumentor inst = new ScriptClassInstrumentor(writer, sci); + reader.accept(inst, 0); + //noinspection UnusedAssignment + + // write instrumented class + try (FileOutputStream fos = new FileOutputStream(new File(outDir, inFile.getName()))) { + buf = writer.toByteArray(); + if (DEBUG) { + verify(buf); + } + fos.write(buf); + } + + // simple class name without package prefix + String simpleName = inFile.getName(); + simpleName = simpleName.substring(0, simpleName.indexOf(".class")); + + if (sci.getPrototypeMemberCount() > 0) { + // generate prototype class + final PrototypeGenerator protGen = new PrototypeGenerator(sci); + buf = protGen.getClassBytes(); + if (DEBUG) { + verify(buf); + } + try (FileOutputStream fos = new FileOutputStream(new File(outDir, simpleName + StringConstants.PROTOTYPE_SUFFIX + ".class"))) { + fos.write(buf); + } + } + + if (sci.getConstructorMemberCount() > 0 || sci.getConstructor() != null) { + // generate constructor class + final ConstructorGenerator consGen = new ConstructorGenerator(sci); + buf = consGen.getClassBytes(); + if (DEBUG) { + verify(buf); + } + try (FileOutputStream fos = new FileOutputStream(new File(outDir, simpleName + StringConstants.CONSTRUCTOR_SUFFIX + ".class"))) { + fos.write(buf); + } + } + } + return true; + } catch (final IOException | RuntimeException e) { + if (DEBUG) { + e.printStackTrace(System.err); + } + reporter.error(e.getMessage()); + + return false; + } + } + + private static void verify(final byte[] buf) { + final ClassReader cr = new ClassReader(buf); + CheckClassAdapter.verify(cr, false, new PrintWriter(System.err)); + } + + private static void error(final String msg, final int exitCode) { + System.err.println(msg); + System.exit(exitCode); + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java new file mode 100644 index 00000000000..3fdd7c686bb --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java @@ -0,0 +1,377 @@ +/* + * 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.tools.nasgen; + +import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_ARRAY_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; + +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.Type; +import jdk.nashorn.internal.objects.annotations.Where; + +/** + * Details about a Java method or field annotated with any of the field/method + * annotations from the jdk.nashorn.internal.objects.annotations package. + */ +public final class MemberInfo implements Cloneable { + /** + * The different kinds of available class annotations + */ + public static enum Kind { + /** This is a script class */ + SCRIPT_CLASS, + /** This is a constructor */ + CONSTRUCTOR, + /** This is a function */ + FUNCTION, + /** This is a getter */ + GETTER, + /** This is a setter */ + SETTER, + /** This is a property */ + PROPERTY, + /** This is a specialized version of a function */ + SPECIALIZED_FUNCTION, + /** This is a specialized version of a constructor */ + SPECIALIZED_CONSTRUCTOR + } + + // keep in sync with jdk.nashorn.internal.objects.annotations.Attribute + static final int DEFAULT_ATTRIBUTES = 0x0; + + static final int DEFAULT_ARITY = -2; + + // the kind of the script annotation - one of the above constants + private MemberInfo.Kind kind; + // script property name + private String name; + // script property attributes + private int attributes; + // name of the java member + private String javaName; + // type descriptor of the java member + private String javaDesc; + // access bits of the Java field or method + private int javaAccess; + // initial value for static @Property fields + private Object value; + // class whose object is created to fill property value + private String initClass; + // arity of the Function or Constructor + private int arity; + + private Where where; + + /** + * @return the kind + */ + public Kind getKind() { + return kind; + } + + /** + * @param kind the kind to set + */ + public void setKind(final Kind kind) { + this.kind = kind; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(final String name) { + this.name = name; + } + + /** + * @return the attributes + */ + public int getAttributes() { + return attributes; + } + + /** + * @param attributes the attributes to set + */ + public void setAttributes(final int attributes) { + this.attributes = attributes; + } + + /** + * @return the javaName + */ + public String getJavaName() { + return javaName; + } + + /** + * @param javaName the javaName to set + */ + public void setJavaName(final String javaName) { + this.javaName = javaName; + } + + /** + * @return the javaDesc + */ + public String getJavaDesc() { + return javaDesc; + } + + void setJavaDesc(final String javaDesc) { + this.javaDesc = javaDesc; + } + + int getJavaAccess() { + return javaAccess; + } + + void setJavaAccess(final int access) { + this.javaAccess = access; + } + + Object getValue() { + return value; + } + + void setValue(final Object value) { + this.value = value; + } + + Where getWhere() { + return where; + } + + void setWhere(final Where where) { + this.where = where; + } + + boolean isFinal() { + return (javaAccess & Opcodes.ACC_FINAL) != 0; + } + + boolean isStatic() { + return (javaAccess & Opcodes.ACC_STATIC) != 0; + } + + boolean isStaticFinal() { + return isStatic() && isFinal(); + } + + boolean isInstanceGetter() { + return kind == Kind.GETTER && where == Where.INSTANCE; + } + + /** + * Check whether this MemberInfo is a getter that resides in the instance + * @return true if instance setter + */ + boolean isInstanceSetter() { + return kind == Kind.SETTER && where == Where.INSTANCE; + } + + boolean isInstanceProperty() { + return kind == Kind.PROPERTY && where == Where.INSTANCE; + } + + boolean isInstanceFunction() { + return kind == Kind.FUNCTION && where == Where.INSTANCE; + } + + boolean isPrototypeGetter() { + return kind == Kind.GETTER && where == Where.PROTOTYPE; + } + + boolean isPrototypeSetter() { + return kind == Kind.SETTER && where == Where.PROTOTYPE; + } + + boolean isPrototypeProperty() { + return kind == Kind.PROPERTY && where == Where.PROTOTYPE; + } + + boolean isPrototypeFunction() { + return kind == Kind.FUNCTION && where == Where.PROTOTYPE; + } + + boolean isConstructorGetter() { + return kind == Kind.GETTER && where == Where.CONSTRUCTOR; + } + + boolean isConstructorSetter() { + return kind == Kind.SETTER && where == Where.CONSTRUCTOR; + } + + boolean isConstructorProperty() { + return kind == Kind.PROPERTY && where == Where.CONSTRUCTOR; + } + + boolean isConstructorFunction() { + return kind == Kind.FUNCTION && where == Where.CONSTRUCTOR; + } + + boolean isConstructor() { + return kind == Kind.CONSTRUCTOR; + } + + void verify() { + if (kind == Kind.CONSTRUCTOR) { + final Type returnType = Type.getReturnType(javaDesc); + if (! returnType.toString().equals(OBJECT_DESC)) { + error("return value should be of Object type, found" + returnType); + } + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + if (argTypes.length < 2) { + error("constructor methods should have at least 2 args"); + } + if (! argTypes[0].equals(Type.BOOLEAN_TYPE)) { + error("first argument should be of boolean type, found" + argTypes[0]); + } + if (! argTypes[1].toString().equals(OBJECT_DESC)) { + error("second argument should be of Object type, found" + argTypes[0]); + } + + if (argTypes.length > 2) { + for (int i = 2; i < argTypes.length - 1; i++) { + if (! argTypes[i].toString().equals(OBJECT_DESC)) { + error(i + "'th argument should be of Object type, found " + argTypes[i]); + } + } + + final String lastArgType = argTypes[argTypes.length - 1].toString(); + final boolean isVarArg = lastArgType.equals(OBJECT_ARRAY_DESC); + if (!lastArgType.equals(OBJECT_DESC) && !isVarArg) { + error("last argument is neither Object nor Object[] type: " + lastArgType); + } + + if (isVarArg && argTypes.length > 3) { + error("vararg constructor has more than 3 arguments"); + } + } + } else if (kind == Kind.FUNCTION) { + final Type returnType = Type.getReturnType(javaDesc); + if (! returnType.toString().equals(OBJECT_DESC)) { + error("return value should be of Object type, found" + returnType); + } + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + if (argTypes.length < 1) { + error("function methods should have at least 1 arg"); + } + if (! argTypes[0].toString().equals(OBJECT_DESC)) { + error("first argument should be of Object type, found" + argTypes[0]); + } + + if (argTypes.length > 1) { + for (int i = 1; i < argTypes.length - 1; i++) { + if (! argTypes[i].toString().equals(OBJECT_DESC)) { + error(i + "'th argument should be of Object type, found " + argTypes[i]); + } + } + + final String lastArgType = argTypes[argTypes.length - 1].toString(); + final boolean isVarArg = lastArgType.equals(OBJECT_ARRAY_DESC); + if (!lastArgType.equals(OBJECT_DESC) && !isVarArg) { + error("last argument is neither Object nor Object[] type: " + lastArgType); + } + + if (isVarArg && argTypes.length > 2) { + error("vararg function has more than 2 arguments"); + } + } + } else if (kind == Kind.GETTER) { + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + if (argTypes.length != 1) { + error("getter methods should have one argument"); + } + if (! argTypes[0].toString().equals(OBJECT_DESC)) { + error("first argument of getter should be of Object type, found: " + argTypes[0]); + } + if (Type.getReturnType(javaDesc).equals(Type.VOID_TYPE)) { + error("return type of getter should not be void"); + } + } else if (kind == Kind.SETTER) { + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + if (argTypes.length != 2) { + error("setter methods should have two arguments"); + } + if (! argTypes[0].toString().equals(OBJECT_DESC)) { + error("first argument of setter should be of Object type, found: " + argTypes[0]); + } + if (!Type.getReturnType(javaDesc).toString().equals("V")) { + error("return type of setter should be void, found: " + Type.getReturnType(javaDesc)); + } + } + } + + private void error(final String msg) { + throw new RuntimeException(javaName + javaDesc + " : " + msg); + } + + /** + * @return the initClass + */ + String getInitClass() { + return initClass; + } + + /** + * @param initClass the initClass to set + */ + void setInitClass(final String initClass) { + this.initClass = initClass; + } + + @Override + protected Object clone() { + try { + return super.clone(); + } catch (final CloneNotSupportedException e) { + assert false : "clone not supported " + e; + return null; + } + } + + /** + * @return the arity + */ + int getArity() { + return arity; + } + + /** + * @param arity the arity to set + */ + void setArity(final int arity) { + this.arity = arity; + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java new file mode 100644 index 00000000000..c3dfd878526 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java @@ -0,0 +1,426 @@ +/* + * 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.tools.nasgen; + +import static jdk.internal.org.objectweb.asm.Opcodes.AALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.AASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.ACONST_NULL; +import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.ANEWARRAY; +import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN; +import static jdk.internal.org.objectweb.asm.Opcodes.ASM4; +import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.BALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.BASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.BIPUSH; +import static jdk.internal.org.objectweb.asm.Opcodes.CALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.CASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST; +import static jdk.internal.org.objectweb.asm.Opcodes.DALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.DASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.DCONST_0; +import static jdk.internal.org.objectweb.asm.Opcodes.DRETURN; +import static jdk.internal.org.objectweb.asm.Opcodes.DUP; +import static jdk.internal.org.objectweb.asm.Opcodes.DUP2; +import static jdk.internal.org.objectweb.asm.Opcodes.FALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.FASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.FCONST_0; +import static jdk.internal.org.objectweb.asm.Opcodes.FRETURN; +import static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD; +import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.IALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.IASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0; +import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL; +import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN; +import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.LALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.LCONST_0; +import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN; +import static jdk.internal.org.objectweb.asm.Opcodes.NEW; +import static jdk.internal.org.objectweb.asm.Opcodes.POP; +import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD; +import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; +import static jdk.internal.org.objectweb.asm.Opcodes.SALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.SASTORE; +import static jdk.internal.org.objectweb.asm.Opcodes.SIPUSH; +import static jdk.internal.org.objectweb.asm.Opcodes.SWAP; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.METHODHANDLE_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_METHODHANDLE; + +import java.util.List; +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Type; + +/** + * Base class for all method generating classes. + * + */ +public class MethodGenerator extends MethodVisitor { + private final int access; + private final String name; + private final String descriptor; + private final Type returnType; + private final Type[] argumentTypes; + + MethodGenerator(final MethodVisitor mv, final int access, final String name, final String descriptor) { + super(ASM4, mv); + this.access = access; + this.name = name; + this.descriptor = descriptor; + this.returnType = Type.getReturnType(descriptor); + this.argumentTypes = Type.getArgumentTypes(descriptor); + } + + int getAccess() { + return access; + } + + final String getName() { + return name; + } + + final String getDescriptor() { + return descriptor; + } + + final Type getReturnType() { + return returnType; + } + + final Type[] getArgumentTypes() { + return argumentTypes; + } + + /** + * Check whether access for this method is static + * @return true if static + */ + protected final boolean isStatic() { + return (getAccess() & ACC_STATIC) != 0; + } + + /** + * Check whether this method is a constructor + * @return true if constructor + */ + protected final boolean isConstructor() { + return "".equals(name); + } + + void newObject(final String type) { + super.visitTypeInsn(NEW, type); + } + + void newObjectArray(final String type) { + super.visitTypeInsn(ANEWARRAY, type); + } + + void loadThis() { + if ((access & ACC_STATIC) != 0) { + throw new IllegalStateException("no 'this' inside static method"); + } + super.visitVarInsn(ALOAD, 0); + } + + void returnValue() { + super.visitInsn(returnType.getOpcode(IRETURN)); + } + + void returnVoid() { + super.visitInsn(RETURN); + } + + // load, store + void arrayLoad(final Type type) { + super.visitInsn(type.getOpcode(IALOAD)); + } + + void arrayLoad() { + super.visitInsn(AALOAD); + } + + void arrayStore(final Type type) { + super.visitInsn(type.getOpcode(IASTORE)); + } + + void arrayStore() { + super.visitInsn(AASTORE); + } + + void loadLiteral(final Object value) { + super.visitLdcInsn(value); + } + + void classLiteral(final String className) { + super.visitLdcInsn(className); + } + + void loadLocal(final Type type, final int index) { + super.visitVarInsn(type.getOpcode(ILOAD), index); + } + + void loadLocal(final int index) { + super.visitVarInsn(ALOAD, index); + } + + void storeLocal(final Type type, final int index) { + super.visitVarInsn(type.getOpcode(ISTORE), index); + } + + void storeLocal(final int index) { + super.visitVarInsn(ASTORE, index); + } + + void checkcast(final String type) { + super.visitTypeInsn(CHECKCAST, type); + } + + // push constants/literals + void pushNull() { + super.visitInsn(ACONST_NULL); + } + + void push(final int value) { + if (value >= -1 && value <= 5) { + super.visitInsn(ICONST_0 + value); + } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { + super.visitIntInsn(BIPUSH, value); + } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { + super.visitIntInsn(SIPUSH, value); + } else { + super.visitLdcInsn(value); + } + } + + void loadClass(final String className) { + super.visitLdcInsn(Type.getObjectType(className)); + } + + void pop() { + super.visitInsn(POP); + } + + // various "dups" + void dup() { + super.visitInsn(DUP); + } + + void dup2() { + super.visitInsn(DUP2); + } + + void swap() { + super.visitInsn(SWAP); + } + + void dupArrayValue(final int arrayOpcode) { + switch (arrayOpcode) { + case IALOAD: case FALOAD: + case AALOAD: case BALOAD: + case CALOAD: case SALOAD: + case IASTORE: case FASTORE: + case AASTORE: case BASTORE: + case CASTORE: case SASTORE: + dup(); + break; + + case LALOAD: case DALOAD: + case LASTORE: case DASTORE: + dup2(); + break; + default: + throw new AssertionError("invalid dup"); + } + } + + void dupReturnValue(final int returnOpcode) { + switch (returnOpcode) { + case IRETURN: + case FRETURN: + case ARETURN: + super.visitInsn(DUP); + return; + case LRETURN: + case DRETURN: + super.visitInsn(DUP2); + return; + case RETURN: + return; + default: + throw new IllegalArgumentException("not return"); + } + } + + void dupValue(final Type type) { + switch (type.getSize()) { + case 1: + dup(); + break; + case 2: + dup2(); + break; + default: + throw new AssertionError("invalid dup"); + } + } + + void dupValue(final String desc) { + final int typeCode = desc.charAt(0); + switch (typeCode) { + case '[': + case 'L': + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + super.visitInsn(DUP); + break; + case 'J': + case 'D': + super.visitInsn(DUP2); + break; + default: + throw new RuntimeException("invalid signature"); + } + } + + // push default value of given type desc + void defaultValue(final String desc) { + final int typeCode = desc.charAt(0); + switch (typeCode) { + case '[': + case 'L': + super.visitInsn(ACONST_NULL); + break; + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + super.visitInsn(ICONST_0); + break; + case 'J': + super.visitInsn(LCONST_0); + break; + case 'F': + super.visitInsn(FCONST_0); + break; + case 'D': + super.visitInsn(DCONST_0); + break; + default: + throw new AssertionError("invalid desc " + desc); + } + } + + // invokes, field get/sets + void invokeVirtual(final String owner, final String method, final String desc) { + super.visitMethodInsn(INVOKEVIRTUAL, owner, method, desc); + } + + void invokeSpecial(final String owner, final String method, final String desc) { + super.visitMethodInsn(INVOKESPECIAL, owner, method, desc); + } + + void invokeStatic(final String owner, final String method, final String desc) { + super.visitMethodInsn(INVOKESTATIC, owner, method, desc); + } + + void putStatic(final String owner, final String field, final String desc) { + super.visitFieldInsn(PUTSTATIC, owner, field, desc); + } + + void getStatic(final String owner, final String field, final String desc) { + super.visitFieldInsn(GETSTATIC, owner, field, desc); + } + + void putField(final String owner, final String field, final String desc) { + super.visitFieldInsn(PUTFIELD, owner, field, desc); + } + + void getField(final String owner, final String field, final String desc) { + super.visitFieldInsn(GETFIELD, owner, field, desc); + } + + void memberInfoArray(final String className, final List mis) { + if (mis.isEmpty()) { + pushNull(); + return; + } + + int pos = 0; + push(mis.size()); + newObjectArray(METHODHANDLE_TYPE); + for (final MemberInfo mi : mis) { + dup(); + push(pos++); + visitLdcInsn(new Handle(H_INVOKESTATIC, className, mi.getJavaName(), mi.getJavaDesc())); + arrayStore(TYPE_METHODHANDLE); + } + } + + void computeMaxs() { + // These values are ignored as we create class writer + // with ClassWriter.COMPUTE_MAXS flag. + super.visitMaxs(Short.MAX_VALUE, Short.MAX_VALUE); + } + + // debugging support - print calls + void println(final String msg) { + super.visitFieldInsn(GETSTATIC, + "java/lang/System", + "out", + "Ljava/io/PrintStream;"); + super.visitLdcInsn(msg); + super.visitMethodInsn(INVOKEVIRTUAL, + "java/io/PrintStream", + "println", + "(Ljava/lang/String;)V"); + } + + // print the object on the top of the stack + void printObject() { + super.visitFieldInsn(GETSTATIC, + "java/lang/System", + "out", + "Ljava/io/PrintStream;"); + super.visitInsn(SWAP); + super.visitMethodInsn(INVOKEVIRTUAL, + "java/io/PrintStream", + "println", + "(Ljava/lang/Object;)V"); + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/NullVisitor.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/NullVisitor.java new file mode 100644 index 00000000000..de2f3923889 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/NullVisitor.java @@ -0,0 +1,88 @@ +/* + * 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.tools.nasgen; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +/** + * A visitor that does nothing on visitXXX calls. + * + */ +public class NullVisitor extends ClassVisitor { + NullVisitor() { + super(Opcodes.ASM4); + } + + @Override + public MethodVisitor visitMethod( + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) { + return new MethodVisitor(Opcodes.ASM4) { + @Override + public AnnotationVisitor visitAnnotationDefault() { + return new NullAnnotationVisitor(); + } + + @Override + public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + return new NullAnnotationVisitor(); + } + }; + } + + @Override + public FieldVisitor visitField( + final int access, + final String name, + final String desc, + final String signature, + final Object value) { + return new FieldVisitor(Opcodes.ASM4) { + @Override + public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + return new NullAnnotationVisitor(); + } + }; + } + + @Override + public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { + return new NullAnnotationVisitor(); + } + + private static class NullAnnotationVisitor extends AnnotationVisitor { + NullAnnotationVisitor() { + super(Opcodes.ASM4); + } + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java new file mode 100644 index 00000000000..17750cd1bbf --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java @@ -0,0 +1,184 @@ +/* + * 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.tools.nasgen; + +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; +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.MAP_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE; +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; + +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * This class generates prototype class for a @ClassInfo annotated class. + * + */ +public class PrototypeGenerator extends ClassGenerator { + private final ScriptClassInfo scriptClassInfo; + private final String className; + private final int memberCount; + + PrototypeGenerator(final ScriptClassInfo sci) { + this.scriptClassInfo = sci; + this.className = scriptClassInfo.getPrototypeClassName(); + this.memberCount = scriptClassInfo.getPrototypeMemberCount(); + } + + byte[] getClassBytes() { + // new class extensing from ScriptObject + cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, className, null, PROTOTYPEOBJECT_TYPE, null); + if (memberCount > 0) { + // add fields + emitFields(); + // add + emitStaticInitializer(); + } + // add + emitConstructor(); + + // add getClassName() + emitGetClassName(scriptClassInfo.getName()); + + cw.visitEnd(); + return cw.toByteArray(); + } + + // --Internals only below this point + private void emitFields() { + // introduce "Function" type instance fields for each + // prototype @Function in script class info + for (MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (memInfo.isPrototypeFunction()) { + addFunctionField(memInfo.getJavaName()); + memInfo = (MemberInfo)memInfo.clone(); + memInfo.setJavaDesc(OBJECT_DESC); + addGetter(className, memInfo); + addSetter(className, memInfo); + } else if (memInfo.isPrototypeProperty()) { + if (memInfo.isStaticFinal()) { + addGetter(scriptClassInfo.getJavaName(), memInfo); + } else { + addField(memInfo.getJavaName(), memInfo.getJavaDesc()); + memInfo = (MemberInfo)memInfo.clone(); + memInfo.setJavaAccess(ACC_PUBLIC); + addGetter(className, memInfo); + addSetter(className, memInfo); + } + } + } + + addMapField(); + } + + private void emitStaticInitializer() { + final MethodGenerator mi = makeStaticInitializer(); + emitStaticInitPrefix(mi, className); + for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (memInfo.isPrototypeFunction() || memInfo.isPrototypeProperty()) { + linkerAddGetterSetter(mi, className, memInfo); + } else if (memInfo.isPrototypeGetter()) { + final MemberInfo setter = scriptClassInfo.findSetter(memInfo); + linkerAddGetterSetter(mi, scriptClassInfo.getJavaName(), memInfo, setter); + } + } + emitStaticInitSuffix(mi, className); + } + + private void emitConstructor() { + final MethodGenerator mi = makeConstructor(); + mi.visitCode(); + mi.loadThis(); + if (memberCount > 0) { + // call "super(map$)" + mi.getStatic(className, MAP_FIELD_NAME, MAP_DESC); + // make sure we use duplicated PropertyMap so that original map + // stays intact and so can be used for many globals in same context + mi.invokeVirtual(MAP_TYPE, MAP_DUPLICATE, MAP_DUPLICATE_DESC); + mi.invokeSpecial(PROTOTYPEOBJECT_TYPE, INIT, SCRIPTOBJECT_INIT_DESC); + // initialize Function type fields + initFunctionFields(mi); + } else { + // call "super()" + mi.invokeSpecial(PROTOTYPEOBJECT_TYPE, INIT, DEFAULT_INIT_DESC); + } + mi.returnVoid(); + mi.computeMaxs(); + mi.visitEnd(); + } + + private void initFunctionFields(final MethodGenerator mi) { + for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (! memInfo.isPrototypeFunction()) { + continue; + } + mi.loadThis(); + newFunction(mi, scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName())); + mi.putField(className, memInfo.getJavaName(), OBJECT_DESC); + } + } + + /** + * External entry point for PrototypeGenerator if called from the command line + * + * @param args arguments, takes 1 argument which is the class to process + * @throws IOException if class cannot be read + */ + public static void main(final String[] args) throws IOException { + if (args.length != 1) { + System.err.println("Usage: " + ConstructorGenerator.class.getName() + " "); + System.exit(1); + } + + final String className = args[0].replace('.', '/'); + final ScriptClassInfo sci = getScriptClassInfo(className + ".class"); + if (sci == null) { + System.err.println("No @ScriptClass in " + className); + System.exit(2); + throw new AssertionError(); //guard against warning that sci is null below + } + try { + sci.verify(); + } catch (final Exception e) { + System.err.println(e.getMessage()); + System.exit(3); + } + final PrototypeGenerator gen = new PrototypeGenerator(sci); + try (FileOutputStream fos = new FileOutputStream(className + PROTOTYPE_SUFFIX + ".class")) { + fos.write(gen.getClassBytes()); + } + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java new file mode 100644 index 00000000000..0a1579ff5c8 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java @@ -0,0 +1,237 @@ +/* + * 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.tools.nasgen; + +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import jdk.internal.org.objectweb.asm.Type; +import jdk.nashorn.internal.objects.annotations.Constructor; +import jdk.nashorn.internal.objects.annotations.Function; +import jdk.nashorn.internal.objects.annotations.Getter; +import jdk.nashorn.internal.objects.annotations.Property; +import jdk.nashorn.internal.objects.annotations.ScriptClass; +import jdk.nashorn.internal.objects.annotations.Setter; +import jdk.nashorn.internal.objects.annotations.SpecializedConstructor; +import jdk.nashorn.internal.objects.annotations.SpecializedFunction; +import jdk.nashorn.internal.objects.annotations.Where; +import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind; + +/** + * All annotation information from a class that is annotated with + * the annotation com.sun.oracle.objects.annotations.ScriptClass. + * + */ +public final class ScriptClassInfo { + // descriptots for various annotations + static final String SCRIPT_CLASS_ANNO_DESC = Type.getDescriptor(ScriptClass.class); + static final String CONSTRUCTOR_ANNO_DESC = Type.getDescriptor(Constructor.class); + static final String FUNCTION_ANNO_DESC = Type.getDescriptor(Function.class); + static final String GETTER_ANNO_DESC = Type.getDescriptor(Getter.class); + static final String SETTER_ANNO_DESC = Type.getDescriptor(Setter.class); + static final String PROPERTY_ANNO_DESC = Type.getDescriptor(Property.class); + static final String WHERE_ENUM_DESC = Type.getDescriptor(Where.class); + static final String SPECIALIZED_FUNCTION = Type.getDescriptor(SpecializedFunction.class); + static final String SPECIALIZED_CONSTRUCTOR = Type.getDescriptor(SpecializedConstructor.class); + + static final Map annotations = new HashMap<>(); + + static { + annotations.put(SCRIPT_CLASS_ANNO_DESC, Kind.SCRIPT_CLASS); + annotations.put(FUNCTION_ANNO_DESC, Kind.FUNCTION); + annotations.put(CONSTRUCTOR_ANNO_DESC, Kind.CONSTRUCTOR); + annotations.put(GETTER_ANNO_DESC, Kind.GETTER); + annotations.put(SETTER_ANNO_DESC, Kind.SETTER); + annotations.put(PROPERTY_ANNO_DESC, Kind.PROPERTY); + annotations.put(SPECIALIZED_FUNCTION, Kind.SPECIALIZED_FUNCTION); + annotations.put(SPECIALIZED_CONSTRUCTOR, Kind.SPECIALIZED_CONSTRUCTOR); + } + + // name of the script class + private String name; + // member info for script properties + private List members = Collections.emptyList(); + // java class name that is annotated with @ScriptClass + private String javaName; + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(final String name) { + this.name = name; + } + + /** + * @return the members + */ + public List getMembers() { + return Collections.unmodifiableList(members); + } + + /** + * @param members the members to set + */ + public void setMembers(final List members) { + this.members = members; + } + + MemberInfo getConstructor() { + for (final MemberInfo memInfo : members) { + if (memInfo.getKind() == Kind.CONSTRUCTOR) { + return memInfo; + } + } + return null; + } + + List getSpecializedConstructors() { + final List res = new LinkedList<>(); + for (final MemberInfo memInfo : members) { + if (memInfo.getKind() == Kind.SPECIALIZED_CONSTRUCTOR) { + res.add(memInfo); + } + } + return res; + } + + int getPrototypeMemberCount() { + int count = 0; + for (final MemberInfo memInfo : members) { + if (memInfo.getWhere() == Where.PROTOTYPE || memInfo.isConstructor()) { + count++; + } + } + return count; + } + + int getConstructorMemberCount() { + int count = 0; + for (final MemberInfo memInfo : members) { + if (memInfo.getWhere() == Where.CONSTRUCTOR) { + count++; + } + } + return count; + } + + int getInstancePropertyCount() { + int count = 0; + for (final MemberInfo memInfo : members) { + if (memInfo.getWhere() == Where.INSTANCE) { + count++; + } + } + return count; + } + + MemberInfo find(final String findJavaName, final String findJavaDesc, final int findAccess) { + for (final MemberInfo memInfo : members) { + if (memInfo.getJavaName().equals(findJavaName) && + memInfo.getJavaDesc().equals(findJavaDesc) && + memInfo.getJavaAccess() == findAccess) { + return memInfo; + } + } + return null; + } + + List findSpecializations(final String methodName) { + final List res = new LinkedList<>(); + for (final MemberInfo memInfo : members) { + if (memInfo.getName().equals(methodName) && + memInfo.getKind() == Kind.SPECIALIZED_FUNCTION) { + res.add(memInfo); + } + } + return res; + } + + MemberInfo findSetter(final MemberInfo getter) { + assert getter.getKind() == Kind.GETTER : "getter expected"; + final String getterName = getter.getName(); + final Where getterWhere = getter.getWhere(); + for (final MemberInfo memInfo : members) { + if (memInfo.getKind() == Kind.SETTER && + getterName.equals(memInfo.getName()) && + getterWhere == memInfo.getWhere()) { + return memInfo; + } + } + return null; + } + + /** + * @return the javaName + */ + public String getJavaName() { + return javaName; + } + + /** + * @param javaName the javaName to set + */ + void setJavaName(final String javaName) { + this.javaName = javaName; + } + + String getConstructorClassName() { + return getJavaName() + StringConstants.CONSTRUCTOR_SUFFIX; + } + + String getPrototypeClassName() { + return getJavaName() + StringConstants.PROTOTYPE_SUFFIX; + } + + void verify() { + boolean constructorSeen = false; + for (final MemberInfo memInfo : getMembers()) { + if (memInfo.isConstructor()) { + if (constructorSeen) { + error("more than @Constructor method"); + } + constructorSeen = true; + } + try { + memInfo.verify(); + } catch (final Exception e) { + error(e.getMessage()); + } + } + } + + private void error(final String msg) throws RuntimeException { + throw new RuntimeException(javaName + " : " + msg); + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java new file mode 100644 index 00000000000..5561cfbf947 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java @@ -0,0 +1,331 @@ +/* + * 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.tools.nasgen; + +import static jdk.nashorn.internal.tools.nasgen.ScriptClassInfo.SCRIPT_CLASS_ANNO_DESC; +import static jdk.nashorn.internal.tools.nasgen.ScriptClassInfo.WHERE_ENUM_DESC; + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.nashorn.internal.objects.annotations.Where; +import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind; + +/** + * This class collects all @ScriptClass and other annotation information from a + * compiled .class file. Enforces that @Function/@Getter/@Setter/@Constructor + * methods are declared to be 'static'. + */ +public class ScriptClassInfoCollector extends ClassVisitor { + private String scriptClassName; + private List scriptMembers; + private String javaClassName; + + ScriptClassInfoCollector(final ClassVisitor visitor) { + super(Opcodes.ASM4, visitor); + } + + ScriptClassInfoCollector() { + this(new NullVisitor()); + } + + private void addScriptMember(final MemberInfo memInfo) { + if (scriptMembers == null) { + scriptMembers = new ArrayList<>(); + } + scriptMembers.add(memInfo); + } + + @Override + public void visit(final int version, final int access, final String name, final String signature, + final String superName, final String[] interfaces) { + super.visit(version, access, name, signature, superName, interfaces); + javaClassName = name; + } + + @Override + public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { + final AnnotationVisitor delegateAV = super.visitAnnotation(desc, visible); + if (SCRIPT_CLASS_ANNO_DESC.equals(desc)) { + return new AnnotationVisitor(Opcodes.ASM4, delegateAV) { + @Override + public void visit(final String name, final Object value) { + if ("value".equals(name)) { + scriptClassName = (String) value; + } + super.visit(name, value); + } + }; + } + + return delegateAV; + } + + @Override + public FieldVisitor visitField(final int fieldAccess, final String fieldName, final String fieldDesc, final String signature, final Object value) { + final FieldVisitor delegateFV = super.visitField(fieldAccess, fieldName, fieldDesc, signature, value); + + return new FieldVisitor(Opcodes.ASM4, delegateFV) { + @Override + public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + final AnnotationVisitor delegateAV = super.visitAnnotation(descriptor, visible); + + if (ScriptClassInfo.PROPERTY_ANNO_DESC.equals(descriptor)) { + final MemberInfo memInfo = new MemberInfo(); + + memInfo.setKind(Kind.PROPERTY); + memInfo.setJavaName(fieldName); + memInfo.setJavaDesc(fieldDesc); + memInfo.setJavaAccess(fieldAccess); + + if ((fieldAccess & Opcodes.ACC_STATIC) != 0) { + memInfo.setValue(value); + } + + addScriptMember(memInfo); + + return new AnnotationVisitor(Opcodes.ASM4, delegateAV) { + // These could be "null" if values are not suppiled, + // in which case we have to use the default values. + private String name; + private Integer attributes; + private String clazz = ""; + private Where where; + + @Override + public void visit(final String annotationName, final Object annotationValue) { + switch (annotationName) { + case "name": + this.name = (String) annotationValue; + break; + case "attributes": + this.attributes = (Integer) annotationValue; + break; + case "clazz": + this.clazz = (annotationValue == null) ? "" : annotationValue.toString(); + break; + default: + break; + } + super.visit(annotationName, annotationValue); + } + + @Override + public void visitEnum(final String enumName, final String desc, final String enumValue) { + if ("where".equals(enumName) && WHERE_ENUM_DESC.equals(desc)) { + this.where = Where.valueOf(enumValue); + } + super.visitEnum(enumName, desc, enumValue); + } + + @Override + public void visitEnd() { + super.visitEnd(); + memInfo.setName(name == null ? fieldName : name); + memInfo.setAttributes(attributes == null + ? MemberInfo.DEFAULT_ATTRIBUTES : attributes); + clazz = clazz.replace('.', '/'); + memInfo.setInitClass(clazz); + memInfo.setWhere(where == null? Where.INSTANCE : where); + } + }; + } + + return delegateAV; + } + }; + } + + private void error(final String javaName, final String javaDesc, final String msg) { + throw new RuntimeException(scriptClassName + "." + javaName + javaDesc + " : " + msg); + } + + @Override + public MethodVisitor visitMethod(final int methodAccess, final String methodName, + final String methodDesc, final String signature, final String[] exceptions) { + + final MethodVisitor delegateMV = super.visitMethod(methodAccess, methodName, methodDesc, + signature, exceptions); + + return new MethodVisitor(Opcodes.ASM4, delegateMV) { + + @Override + public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { + final AnnotationVisitor delegateAV = super.visitAnnotation(descriptor, visible); + final Kind annoKind = ScriptClassInfo.annotations.get(descriptor); + + if (annoKind != null) { + if ((methodAccess & Opcodes.ACC_STATIC) == 0) { + error(methodName, methodDesc, "nasgen method annotations cannot be on instance methods"); + } + + final MemberInfo memInfo = new MemberInfo(); + + memInfo.setKind(annoKind); + memInfo.setJavaName(methodName); + memInfo.setJavaDesc(methodDesc); + memInfo.setJavaAccess(methodAccess); + + addScriptMember(memInfo); + + return new AnnotationVisitor(Opcodes.ASM4, delegateAV) { + // These could be "null" if values are not suppiled, + // in which case we have to use the default values. + private String name; + private Integer attributes; + private Integer arity; + private Where where; + + @Override + public void visit(final String annotationName, final Object annotationValue) { + switch (annotationName) { + case "name": + this.name = (String)annotationValue; + break; + case "attributes": + this.attributes = (Integer)annotationValue; + break; + case "arity": + this.arity = (Integer)annotationValue; + break; + default: + break; + } + + super.visit(annotationName, annotationValue); + } + + @Override + public void visitEnum(final String enumName, final String desc, final String enumValue) { + if ("where".equals(enumName) && WHERE_ENUM_DESC.equals(desc)) { + this.where = Where.valueOf(enumValue); + } + super.visitEnum(enumName, desc, enumValue); + } + + @Override + public void visitEnd() { + super.visitEnd(); + + if (memInfo.getKind() == Kind.CONSTRUCTOR) { + memInfo.setName(name == null ? scriptClassName : name); + } else { + memInfo.setName(name == null ? methodName : name); + } + memInfo.setAttributes(attributes == null ? MemberInfo.DEFAULT_ATTRIBUTES : attributes); + + memInfo.setArity((arity == null)? MemberInfo.DEFAULT_ARITY : arity); + if (where == null) { + // by default @Getter/@Setter belongs to INSTANCE + // @Function belong to PROTOTYPE. + switch (memInfo.getKind()) { + case GETTER: + case SETTER: + where = Where.INSTANCE; + break; + case SPECIALIZED_CONSTRUCTOR: + case CONSTRUCTOR: + where = Where.CONSTRUCTOR; + break; + case FUNCTION: + where = Where.PROTOTYPE; + break; + case SPECIALIZED_FUNCTION: + //TODO is this correct + default: + break; + } + } + memInfo.setWhere(where); + } + }; + } + + return delegateAV; + } + }; + } + + ScriptClassInfo getScriptClassInfo() { + ScriptClassInfo sci = null; + if (scriptClassName != null) { + sci = new ScriptClassInfo(); + sci.setName(scriptClassName); + if (scriptMembers == null) { + scriptMembers = Collections.emptyList(); + } + sci.setMembers(scriptMembers); + sci.setJavaName(javaClassName); + } + return sci; + } + + /** + * External entry point for ScriptClassInfoCollector if invoked from the command line + * @param args argument vector, args contains a class for which to collect info + * @throws IOException if there were problems parsing args or class + */ + public static void main(final String[] args) throws IOException { + if (args.length != 1) { + System.err.println("Usage: " + ScriptClassInfoCollector.class.getName() + " "); + System.exit(1); + } + + args[0] = args[0].replace('.', '/'); + final ScriptClassInfoCollector scic = new ScriptClassInfoCollector(); + try (final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(args[0] + ".class"))) { + final ClassReader reader = new ClassReader(bis); + reader.accept(scic, 0); + } + final ScriptClassInfo sci = scic.getScriptClassInfo(); + final PrintStream out = System.out; + if (sci != null) { + out.println("script class: " + sci.getName()); + out.println("==================================="); + for (final MemberInfo memInfo : sci.getMembers()) { + out.println("kind : " + memInfo.getKind()); + out.println("name : " + memInfo.getName()); + out.println("attributes: " + memInfo.getAttributes()); + out.println("javaName: " + memInfo.getJavaName()); + out.println("javaDesc: " + memInfo.getJavaDesc()); + out.println("where: " + memInfo.getWhere()); + out.println("====================================="); + } + } else { + out.println(args[0] + " is not a @ScriptClass"); + } + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java new file mode 100644 index 00000000000..d140585f499 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java @@ -0,0 +1,309 @@ +/* + * 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.tools.nasgen; + +import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.DUP; +import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.NEW; +import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD; +import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.$CLINIT$; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.CLINIT; +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.MAP_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE; + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.Attribute; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.util.CheckClassAdapter; +import jdk.nashorn.internal.objects.annotations.Where; +import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind; + +/** + * This class instruments the java class annotated with @ScriptClass. + * + * Changes done are: + * + * 1) remove all jdk.nashorn.internal.objects.annotations.* annotations. + * 2) static final @Property fields stay here. Other @Property fields moved to + * respective classes depending on 'where' value of annotation. + * 2) add "Map" type static field named "$map". + * 3) add static initializer block to initialize map. + */ + +public class ScriptClassInstrumentor extends ClassVisitor { + private final ScriptClassInfo scriptClassInfo; + private final int memberCount; + private boolean staticInitFound; + + ScriptClassInstrumentor(final ClassVisitor visitor, final ScriptClassInfo sci) { + super(Opcodes.ASM4, visitor); + if (sci == null) { + throw new IllegalArgumentException("Null ScriptClassInfo, is the class annotated?"); + } + this.scriptClassInfo = sci; + this.memberCount = scriptClassInfo.getInstancePropertyCount(); + } + + @Override + public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { + if (ScriptClassInfo.annotations.containsKey(desc)) { + // ignore @ScriptClass + return null; + } + + return super.visitAnnotation(desc, visible); + } + + @Override + public FieldVisitor visitField(final int fieldAccess, final String fieldName, + final String fieldDesc, final String signature, final Object value) { + final MemberInfo memInfo = scriptClassInfo.find(fieldName, fieldDesc, fieldAccess); + if (memInfo != null && memInfo.getKind() == Kind.PROPERTY && + memInfo.getWhere() != Where.INSTANCE && !memInfo.isStaticFinal()) { + // non-instance @Property fields - these have to go elsewhere unless 'static final' + return null; + } + + final FieldVisitor delegateFV = super.visitField(fieldAccess, fieldName, fieldDesc, + signature, value); + return new FieldVisitor(Opcodes.ASM4, delegateFV) { + @Override + public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { + if (ScriptClassInfo.annotations.containsKey(desc)) { + // ignore script field annotations + return null; + } + + return fv.visitAnnotation(desc, visible); + } + + @Override + public void visitAttribute(final Attribute attr) { + fv.visitAttribute(attr); + } + + @Override + public void visitEnd() { + fv.visitEnd(); + } + }; + } + + @Override + public MethodVisitor visitMethod(final int methodAccess, final String methodName, + final String methodDesc, final String signature, final String[] exceptions) { + + final boolean isConstructor = INIT.equals(methodName); + final boolean isStaticInit = CLINIT.equals(methodName); + + if (isStaticInit) { + staticInitFound = true; + } + + final MethodGenerator delegateMV = new MethodGenerator(super.visitMethod(methodAccess, methodName, methodDesc, + signature, exceptions), methodAccess, methodName, methodDesc); + + return new MethodVisitor(Opcodes.ASM4, delegateMV) { + @Override + public void visitInsn(final int opcode) { + // call $clinit$ just before return from + if (isStaticInit && opcode == RETURN) { + super.visitMethodInsn(INVOKESTATIC, scriptClassInfo.getJavaName(), + $CLINIT$, DEFAULT_INIT_DESC); + } + super.visitInsn(opcode); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { + if (isConstructor && opcode == INVOKESPECIAL && + INIT.equals(name) && SCRIPTOBJECT_TYPE.equals(owner)) { + super.visitFieldInsn(GETSTATIC, scriptClassInfo.getJavaName(), + MAP_FIELD_NAME, MAP_DESC); + super.visitMethodInsn(INVOKESPECIAL, SCRIPTOBJECT_TYPE, INIT, + SCRIPTOBJECT_INIT_DESC); + + if (memberCount > 0) { + // initialize @Property fields if needed + for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (memInfo.isInstanceProperty() && !memInfo.getInitClass().isEmpty()) { + final String clazz = memInfo.getInitClass(); + super.visitVarInsn(ALOAD, 0); + super.visitTypeInsn(NEW, clazz); + super.visitInsn(DUP); + super.visitMethodInsn(INVOKESPECIAL, clazz, + INIT, DEFAULT_INIT_DESC); + super.visitFieldInsn(PUTFIELD, scriptClassInfo.getJavaName(), + memInfo.getJavaName(), memInfo.getJavaDesc()); + } + + if (memInfo.isInstanceFunction()) { + super.visitVarInsn(ALOAD, 0); + ClassGenerator.newFunction(delegateMV, scriptClassInfo.getJavaName(), memInfo, scriptClassInfo.findSpecializations(memInfo.getJavaName())); + super.visitFieldInsn(PUTFIELD, scriptClassInfo.getJavaName(), + memInfo.getJavaName(), OBJECT_DESC); + } + } + } + } else { + super.visitMethodInsn(opcode, owner, name, desc); + } + } + + @Override + public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { + if (ScriptClassInfo.annotations.containsKey(desc)) { + // ignore script method annotations + return null; + } + return super.visitAnnotation(desc, visible); + } + }; + } + + @Override + public void visitEnd() { + emitFields(); + emitStaticInitializer(); + emitGettersSetters(); + super.visitEnd(); + } + + private void emitFields() { + // introduce "Function" type instance fields for each + // instance @Function in script class info + final String className = scriptClassInfo.getJavaName(); + for (MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (memInfo.isInstanceFunction()) { + ClassGenerator.addFunctionField(cv, memInfo.getJavaName()); + memInfo = (MemberInfo)memInfo.clone(); + memInfo.setJavaDesc(OBJECT_DESC); + ClassGenerator.addGetter(cv, className, memInfo); + ClassGenerator.addSetter(cv, className, memInfo); + } + } + ClassGenerator.addMapField(this); + } + + void emitGettersSetters() { + if (memberCount > 0) { + for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { + final String className = scriptClassInfo.getJavaName(); + if (memInfo.isInstanceProperty()) { + ClassGenerator.addGetter(cv, className, memInfo); + if (! memInfo.isFinal()) { + ClassGenerator.addSetter(cv, className, memInfo); + } + } + } + } + } + + private void emitStaticInitializer() { + final String className = scriptClassInfo.getJavaName(); + if (! staticInitFound) { + // no user written and so create one + final MethodVisitor mv = ClassGenerator.makeStaticInitializer(this); + mv.visitCode(); + mv.visitInsn(RETURN); + mv.visitMaxs(Short.MAX_VALUE, 0); + mv.visitEnd(); + } + // Now generate $clinit$ + final MethodGenerator mi = ClassGenerator.makeStaticInitializer(this, $CLINIT$); + ClassGenerator.emitStaticInitPrefix(mi, className); + if (memberCount > 0) { + for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { + if (memInfo.isInstanceProperty() || memInfo.isInstanceFunction()) { + ClassGenerator.linkerAddGetterSetter(mi, className, memInfo); + } else if (memInfo.isInstanceGetter()) { + final MemberInfo setter = scriptClassInfo.findSetter(memInfo); + ClassGenerator.linkerAddGetterSetter(mi, className, memInfo, setter); + } + } + } + ClassGenerator.emitStaticInitSuffix(mi, className); + } + + /** + * External entry point for ScriptClassInfoCollector if run from the command line + * + * @param args arguments - one argument is needed, the name of the class to collect info from + * + * @throws IOException if there are problems reading class + */ + public static void main(final String[] args) throws IOException { + if (args.length != 1) { + System.err.println("Usage: " + ScriptClassInfoCollector.class.getName() + " "); + System.exit(1); + } + + final String fileName = args[0].replace('.', '/') + ".class"; + final ScriptClassInfo sci = ClassGenerator.getScriptClassInfo(fileName); + if (sci == null) { + System.err.println("No @ScriptClass in " + fileName); + System.exit(2); + throw new AssertionError(); //guard against warning that sci is null below + } + + try { + sci.verify(); + } catch (final Exception e) { + System.err.println(e.getMessage()); + System.exit(3); + } + + final ClassWriter writer = ClassGenerator.makeClassWriter(); + try (final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName))) { + final ClassReader reader = new ClassReader(bis); + final CheckClassAdapter checker = new CheckClassAdapter(writer); + final ScriptClassInstrumentor instr = new ScriptClassInstrumentor(checker, sci); + reader.accept(instr, 0); + } + + try (FileOutputStream fos = new FileOutputStream(fileName)) { + fos.write(writer.toByteArray()); + } + } +} diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java new file mode 100644 index 00000000000..8c2dcef0e85 --- /dev/null +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java @@ -0,0 +1,113 @@ +/* + * 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.tools.nasgen; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Method; +import jdk.internal.org.objectweb.asm.Type; +import jdk.nashorn.internal.lookup.Lookup; +import jdk.nashorn.internal.objects.PrototypeObject; +import jdk.nashorn.internal.objects.ScriptFunctionImpl; +import jdk.nashorn.internal.runtime.PropertyMap; +import jdk.nashorn.internal.runtime.ScriptFunction; +import jdk.nashorn.internal.runtime.ScriptObject; + +/** + * String constants used for code generation/instrumentation. + */ +@SuppressWarnings("javadoc") +public interface StringConstants { + static final Type TYPE_METHOD = Type.getType(Method.class); + static final Type TYPE_METHODHANDLE = Type.getType(MethodHandle.class); + static final Type TYPE_METHODHANDLE_ARRAY = Type.getType(MethodHandle[].class); + static final Type TYPE_OBJECT = Type.getType(Object.class); + static final Type TYPE_CLASS = Type.getType(Class.class); + static final Type TYPE_STRING = Type.getType(String.class); + + // Nashorn types + static final Type TYPE_LOOKUP = Type.getType(Lookup.class); + static final Type TYPE_PROPERTYMAP = Type.getType(PropertyMap.class); + static final Type TYPE_PROTOTYPEOBJECT = Type.getType(PrototypeObject.class); + static final Type TYPE_SCRIPTFUNCTION = Type.getType(ScriptFunction.class); + static final Type TYPE_SCRIPTFUNCTIONIMPL = Type.getType(ScriptFunctionImpl.class); + static final Type TYPE_SCRIPTOBJECT = Type.getType(ScriptObject.class); + + static final String PROTOTYPE = "prototype"; + static final String PROTOTYPE_SUFFIX = "$Prototype"; + static final String CONSTRUCTOR_SUFFIX = "$Constructor"; + // This field name is known to Nashorn runtime (Context). + // Synchronize the name change, if needed at all. + static final String MAP_FIELD_NAME = "$nasgenmap$"; + static final String $CLINIT$ = "$clinit$"; + static final String CLINIT = ""; + static final String INIT = ""; + static final String DEFAULT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE); + + static final String SCRIPTOBJECT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_PROPERTYMAP); + + static final String METHODHANDLE_TYPE = TYPE_METHODHANDLE.getInternalName(); + + static final String OBJECT_TYPE = TYPE_OBJECT.getInternalName(); + static final String OBJECT_DESC = TYPE_OBJECT.getDescriptor(); + static final String OBJECT_ARRAY_DESC = Type.getDescriptor(Object[].class); + + static final String SCRIPTFUNCTION_TYPE = TYPE_SCRIPTFUNCTION.getInternalName(); + static final String SCRIPTFUNCTIONIMPL_TYPE = TYPE_SCRIPTFUNCTIONIMPL.getInternalName(); + static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION = "makeFunction"; + static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC = + Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE); + static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC = + Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE, TYPE_METHODHANDLE_ARRAY); + + static final String SCRIPTFUNCTIONIMPL_INIT_DESC3 = + Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_METHODHANDLE_ARRAY); + static final String SCRIPTFUNCTIONIMPL_INIT_DESC4 = + Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_PROPERTYMAP, TYPE_METHODHANDLE_ARRAY); + static final String SCRIPTFUNCTION_SETARITY = "setArity"; + static final String SCRIPTFUNCTION_SETARITY_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE); + static final String PROTOTYPEOBJECT_TYPE = TYPE_PROTOTYPEOBJECT.getInternalName(); + static final String PROTOTYPEOBJECT_SETCONSTRUCTOR = "setConstructor"; + static final String PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT, TYPE_OBJECT); + static final String SCRIPTOBJECT_TYPE = TYPE_SCRIPTOBJECT.getInternalName(); + static final String MAP_TYPE = TYPE_PROPERTYMAP.getInternalName(); + static final String MAP_DESC = TYPE_PROPERTYMAP.getDescriptor(); + static final String MAP_NEWMAP = "newMap"; + static final String MAP_NEWMAP_DESC = Type.getMethodDescriptor(TYPE_PROPERTYMAP, TYPE_CLASS); + static final String MAP_DUPLICATE = "duplicate"; + static final String MAP_DUPLICATE_DESC = Type.getMethodDescriptor(TYPE_PROPERTYMAP); + static final String MAP_SETFLAGS = "setFlags"; + static final String LOOKUP_TYPE = TYPE_LOOKUP.getInternalName(); + static final String LOOKUP_GETMETHOD = "getMethod"; + static final String LOOKUP_NEWPROPERTY = "newProperty"; + static final String LOOKUP_NEWPROPERTY_DESC = + Type.getMethodDescriptor(TYPE_PROPERTYMAP, TYPE_PROPERTYMAP, TYPE_STRING, Type.INT_TYPE, TYPE_METHODHANDLE, TYPE_METHODHANDLE); + static final String GETTER_PREFIX = "G$"; + static final String SETTER_PREFIX = "S$"; + + // ScriptObject.getClassName() method. + static final String GET_CLASS_NAME = "getClassName"; + static final String GET_CLASS_NAME_DESC = Type.getMethodDescriptor(TYPE_STRING); +} diff --git a/nashorn/docs/DEVELOPER_README b/nashorn/docs/DEVELOPER_README new file mode 100644 index 00000000000..3bd220b2a7c --- /dev/null +++ b/nashorn/docs/DEVELOPER_README @@ -0,0 +1,475 @@ +This document describes system properties that are used for internal +debugging and instrumentation purposes, along with the system loggers, +which are used for the same thing. + +This document is intended as a developer resource, and it is not +needed as Nashorn documentation for normal usage. Flags and system +properties described herein are subject to change without notice. + +===================================== +1. System properties used internally +===================================== + +This documentation of the system property flags assume that the +default value of the flag is false, unless otherwise specified. + +SYSTEM PROPERTY: -Dnashorn.unstable.relink.threshold=x + +This property controls how many call site misses are allowed before a +callsite is relinked with "apply" semantics to never change again. +In the case of megamorphic callsites, this is necessary, or the +program would spend all its time swapping out callsite targets. Dynalink +has a default value (currently 8 relinks) for this property if it +is not explicitly set. + + +SYSTEM PROPERTY: -Dnashorn.compiler.splitter.threshold=x + +This will change the node weight that requires a subgraph of the IR to +be split into several classes in order not to run out of bytecode space. +The default value is 0x8000 (32768). + + +SYSTEM PROPERTY: -Dnashorn.compiler.intarithmetic + +Arithmetic operations in Nashorn (except bitwise ones) typically +coerce the operands to doubles (as per the JavaScript spec). To switch +this off and remain in integer mode, for example for "var x = a&b; var +y = c&d; var z = x*y;", use this flag. This will force the +multiplication of variables that are ints to be done with the IMUL +bytecode and the result "z" to become an int. + +WARNING: Note that is is experimental only to ensure that type support +exists for all primitive types. The generated code is unsound. This +will be the case until we do optimizations based on it. There is a CR +in Nashorn to do better range analysis, and ensure that this is only +done where the operation can't overflow into a wider type. Currently +no overflow checking is done, so at the moment, until range analysis +has been completed, this option is turned off. + +We've experimented by using int arithmetic for everything and putting +overflow checks afterwards, which would recompute the operation with +the correct precision, but have yet to find a configuration where this +is faster than just using doubles directly, even if the int operation +does not overflow. Getting access to a JVM intrinsic that does branch +on overflow would probably alleviate this. + +There is also a problem with this optimistic approach if the symbol +happens to reside in a local variable slot in the bytecode, as those +are strongly typed. Then we would need to split large sections of +control flow, so this is probably not the right way to go, while range +analysis is. There is a large difference between integer bytecode +without overflow checks and double bytecode. The former is +significantly faster. + + +SYSTEM PROPERTY: -Dnashorn.codegen.debug, -Dnashorn.codegen.debug.trace= + +See the description of the codegen logger below. + + +SYSTEM_PROPERTY: -Dnashorn.fields.debug + +See the description on the fields logger below. + + +SYSTEM PROPERTY: -Dnashorn.fields.dual + +When this property is true, Nashorn will attempt to use primitive +fields for AccessorProperties (currently just AccessorProperties, not +spill properties). Memory footprint for script objects will increase, +as we need to maintain both a primitive field (a long) as well as an +Object field for the property value. Ints are represented as the 32 +low bits of the long fields. Doubles are represented as the +doubleToLongBits of their value. This way a single field can be used +for all primitive types. Packing and unpacking doubles to their bit +representation is intrinsified by the JVM and extremely fast. + +While dual fields in theory runs significantly faster than Object +fields due to reduction of boxing and memory allocation overhead, +there is still work to be done to make this a general purpose +solution. Research is ongoing. + +In the future, this might complement or be replaced by experimental +feature sun.misc.TaggedArray, which has been discussed on the mlvm +mailing list. TaggedArrays are basically a way to share data space +between primitives and references, and have the GC understand this. + +As long as only primitive values are written to the fields and enough +type information exists to make sure that any reads don't have to be +uselessly boxed and unboxed, this is significantly faster than the +standard "Objects only" approach that currently is the default. See +test/examples/dual-fields-micro.js for an example that runs twice as +fast with dual fields as without them. Here, the compiler, can +determine that we are dealing with numbers only throughout the entire +property life span of the properties involved. + +If a "real" object (not a boxed primitive) is written to a field that +has a primitive representation, its callsite is relinked and an Object +field is used forevermore for that particular field in that +PropertyMap and its children, even if primitives are later assigned to +it. + +As the amount of compile time type information is very small in a +dynamic language like JavaScript, it is frequently the case that +something has to be treated as an object, because we don't know any +better. In reality though, it is often a boxed primitive is stored to +an AccessorProperty. The fastest way to handle this soundly is to use +a callsite typecheck and avoid blowing the field up to an Object. We +never revert object fields to primitives. Ping-pong:ing back and forth +between primitive representation and Object representation would cause +fatal performance overhead, so this is not an option. + +For a general application the dual fields approach is still slower +than objects only fields in some places, about the same in most cases, +and significantly faster in very few. This is due the program using +primitives, but we still can't prove it. For example "local_var a = +call(); field = a;" may very well write a double to the field, but the +compiler dare not guess a double type if field is a local variable, +due to bytecode variables being strongly typed and later non +interchangeable. To get around this, the entire method would have to +be replaced and a continuation retained to restart from. We believe +that the next steps we should go through are instead: + +1) Implement method specialization based on callsite, as it's quite +frequently the case that numbers are passed around, but currently our +function nodes just have object types visible to the compiler. For +example "var b = 17; func(a,b,17)" is an example where two parameters +can be specialized, but the main version of func might also be called +from another callsite with func(x,y,"string"). + +2) This requires lazy jitting as the functions have to be specialized +per callsite. + +Even though "function square(x) { return x*x }" might look like a +trivial function that can always only take doubles, this is not +true. Someone might have overridden the valueOf for x so that the +toNumber coercion has side effects. To fulfil JavaScript semantics, +the coercion has to run twice for both terms of the multiplication +even if they are the same object. This means that call site +specialization is necessary, not parameter specialization on the form +"function square(x) { var xd = (double)x; return xd*xd; }", as one +might first think. + +Generating a method specialization for any variant of a function that +we can determine by types at compile time is a combinatorial explosion +of byte code (try it e.g. on all the variants of am3 in the Octane +benchmark crypto.js). Thus, this needs to be lazy + +3) Possibly optimistic callsite writes, something on the form + +x = y; //x is a field known to be a primitive. y is only an object as +far as we can tell + +turns into + +try { + x = (int)y; +} catch (X is not an integer field right now | ClassCastException e) { + x = y; +} + +Mini POC shows that this is the key to a lot of dual field performance +in seemingly trivial micros where one unknown object, in reality +actually a primitive, foils it for us. Very common pattern. Once we +are "all primitives", dual fields runs a lot faster than Object fields +only. + +We still have to deal with objects vs primitives for local bytecode +slots, possibly through code copying and versioning. + + +SYSTEM PROPERTY: -Dnashorn.compiler.symbol.trace=[[,*]], + -Dnashorn.compiler.symbol.stacktrace=[[,*]] + +When this property is set, creation and manipulation of any symbol +named "x" will show information about when the compiler changes its +type assumption, bytecode local variable slot assignment and other +data. This is useful if, for example, a symbol shows up as an Object, +when you believe it should be a primitive. Usually there is an +explanation for this, for example that it exists in the global scope +and type analysis has to be more conservative. + +Several symbols names to watch can be specified by comma separation. + +If no variable name is specified (and no equals sign), all symbols +will be watched + +By using "stacktrace" instead of or together with "trace", stack +traces will be displayed upon symbol changes according to the same +semantics. + + +SYSTEM PROPERTY: nashorn.lexer.xmlliterals + +If this property it set, it means that the Lexer should attempt to +parse XML literals, which would otherwise generate syntax +errors. Warning: there are currently no unit tests for this +functionality. + +XML literals, when this is enabled, end up as standard LiteralNodes in +the IR. + + +SYSTEM_PROPERTY: nashorn.debug + +If this property is set to true, Nashorn runs in Debug mode. Debug +mode is slightly slower, as for example statistics counters are enabled +during the run. Debug mode makes available a NativeDebug instance +called "Debug" in the global space that can be used to print property +maps and layout for script objects, as well as a "dumpCounters" method +that will print the current values of the previously mentioned stats +counters. + +These functions currently exists for Debug: + +"map" - print(Debug.map(x)) will dump the PropertyMap for object x to +stdout (currently there also exist functions called "embedX", where X +is a value from 0 to 3, that will dump the contents of the embed pool +for the first spill properties in any script object and "spill", that +will dump the contents of the growing spill pool of spill properties +in any script object. This is of course subject to change without +notice, should we change the script object layout. + +"methodHandle" - this method returns the method handle that is used +for invoking a particular script function. + +"identical" - this method compares two script objects for reference +equality. It is a == Java comparison + +"dumpCounters" - will dump the debug counters' current values to +stdout. + +Currently we count number of ScriptObjects in the system, number of +Scope objects in the system, number of ScriptObject listeners added, +removed and dead (without references). + +We also count number of ScriptFunctions, ScriptFunction invocations +and ScriptFunction allocations. + +Furthermore we count PropertyMap statistics: how many property maps +exist, how many times were property maps cloned, how many times did +the property map history cache hit, prevent new allocations, how many +prototype invalidations were done, how many time the property map +proto cache hit. + +Finally we count callsite misses on a per callsite bases, which occur +when a callsite has to be relinked, due to a previous assumption of +object layout being invalidated. + + +SYSTEM PROPERTY: nashorn.methodhandles.debug, +nashorn.methodhandles.debug=create + +If this property is enabled, each MethodHandle related call that uses +the java.lang.invoke package gets its MethodHandle intercepted and an +instrumentation printout of arguments and return value appended to +it. This shows exactly which method handles are executed and from +where. (Also MethodTypes and SwitchPoints). This can be augmented with +more information, for example, instance count, by subclassing or +further extending the TraceMethodHandleFactory implementation in +MethodHandleFactory.java. + +If the property is specialized with "=create" as its option, +instrumentation will be shown for method handles upon creation time +rather than at runtime usage. + + +SYSTEM PROPERTY: nashorn.methodhandles.debug.stacktrace + +This does the same as nashorn.methodhandles.debug, but when enabled +also dumps the stack trace for every instrumented method handle +operation. Warning: This is enormously verbose, but provides a pretty +decent "grep:able" picture of where the calls are coming from. + +See the description of the codegen logger below for a more verbose +description of this option + + +SYSTEM PROPERTY: nashorn.scriptfunction.specialization.disable + +There are several "fast path" implementations of constructors and +functions in the NativeObject classes that, in their original form, +take a variable amount of arguments. Said functions are also declared +to take Object parameters in their original form, as this is what the +JavaScript specification mandates. + +However, we often know quite a lot more at a callsite of one of these +functions. For example, Math.min is called with a fixed number (2) of +integer arguments. The overhead of boxing these ints to Objects and +folding them into an Object array for the generic varargs Math.min +function is an order of magnitude slower than calling a specialized +implementation of Math.min that takes two integers. Specialized +functions and constructors are identified by the tag +@SpecializedFunction and @SpecializedConstructor in the Nashorn +code. The linker will link in the most appropriate (narrowest types, +right number of types and least number of arguments) specialization if +specializations are available. + +Every ScriptFunction may carry specializations that the linker can +choose from. This framework will likely be extended for user defined +functions. The compiler can often infer enough parameter type info +from callsites for in order to generate simpler versions with less +generic Object types. This feature depends on future lazy jitting, as +there tend to be many calls to user defined functions, some where the +callsite can be specialized, some where we mostly see object +parameters even at the callsite. + +If this system property is set to true, the linker will not attempt to +use any specialized function or constructor for native objects, but +just call the generic one. + + +SYSTEM PROPERTY: nashorn.tcs.miss.samplePercent= + +When running with the trace callsite option (-tcs), Nashorn will count +and instrument any callsite misses that require relinking. As the +number of relinks is large and usually produces a lot of output, this +system property can be used to constrain the percentage of misses that +should be logged. Typically this is set to 1 or 5 (percent). 1% is the +default value. + + +SYSTEM_PROPERTY: nashorn.profilefile= + +When running with the profile callsite options (-pcs), Nashorn will +dump profiling data for all callsites to stderr as a shutdown hook. To +instead redirect this to a file, specify the path to the file using +this system property. + + +SYSTEM_PROPERTY: nashorn.regexp.impl=[jdk|joni] + +This property defines the regular expression engine to be used by +Nashorn. The default implementation is "jdk" which is based on the +JDK's java.util.regex package. Set this property to "joni" to install +an implementation based on Joni, the regular expression engine used by +the JRuby project. + + +=============== +2. The loggers. +=============== + +It is very simple to create your own logger. Use the DebugLogger class +and give the subsystem name as a constructor argument. + +The Nashorn loggers can be used to print per-module or per-subsystem +debug information with different levels of verbosity. The loggers for +a given subsystem are available are enabled by using + +--log=[:] + +on the command line. + +Here identifies the name of the subsystem to be logged +and the optional colon and level argument is a standard +java.util.logging.Level name (severe, warning, info, config, fine, +finer, finest). If the level is left out for a particular subsystem, +it defaults to "info". Any log message logged as the level or a level +that is more important will be output to stderr by the logger. + +Several loggers can be enabled by a single command line option, by +putting a comma after each subsystem/level tuple (or each subsystem if +level is unspecified). The --log option can also be given multiple +times on the same command line, with the same effect. + +For example: --log=codegen,fields:finest is equivalent to +--log=codegen:info --log=fields:finest + +The subsystems that currently support logging are: + + +* compiler + +The compiler is in charge of turning source code and function nodes +into byte code, and installs the classes into a class loader +controlled from the Context. Log messages are, for example, about +things like new compile units being allocated. The compiler has global +settings that all the tiers of codegen (e.g. Lower and CodeGenerator) +use.s + + +* codegen + +The code generator is the emitter stage of the code pipeline, and +turns the lowest tier of a FunctionNode into bytecode. Codegen logging +shows byte codes as they are being emitted, line number information +and jumps. It also shows the contents of the bytecode stack prior to +each instruction being emitted. This is a good debugging aid. For +example: + +[codegen] #41 line:2 (f)_afc824e +[codegen] #42 load symbol x slot=2 +[codegen] #43 {1:O} load int 0 +[codegen] #44 {2:I O} dynamic_runtime_call GT:ZOI_I args=2 returnType=boolean +[codegen] #45 signature (Ljava/lang/Object;I)Z +[codegen] #46 {1:Z} ifeq ternary_false_5402fe28 +[codegen] #47 load symbol x slot=2 +[codegen] #48 {1:O} goto ternary_exit_107c1f2f +[codegen] #49 ternary_false_5402fe28 +[codegen] #50 load symbol x slot=2 +[codegen] #51 {1:O} convert object -> double +[codegen] #52 {1:D} neg +[codegen] #53 {1:D} convert double -> object +[codegen] #54 {1:O} ternary_exit_107c1f2f +[codegen] #55 {1:O} return object + +shows a ternary node being generated for the sequence "return x > 0 ? +x : -x" + +The first number on the log line is a unique monotonically increasing +emission id per bytecode. There is no guarantee this is the same id +between runs. depending on non deterministic code +execution/compilation, but for small applications it usually is. If +the system variable -Dnashorn.codegen.debug.trace= is set, where x +is a bytecode emission id, a stack trace will be shown as the +particular bytecode is about to be emitted. This can be a quick way to +determine where it comes from without attaching the debugger. "Who +generated that neg?" + +The --log=codegen option is equivalent to setting the system variable +"nashorn.codegen.debug" to true. + + +* lower + +This is the first lowering pass. + +Lower is a code generation pass that turns high level IR nodes into +lower level one, for example substituting comparisons to RuntimeNodes +and inlining finally blocks. + +Lower is also responsible for determining control flow information +like end points. + + +* attr + +The lowering annotates a FunctionNode with symbols for each identifier +and transforms high level constructs into lower level ones, that the +CodeGenerator consumes. + +Lower logging typically outputs things like post pass actions, +insertions of casts because symbol types have been changed and type +specialization information. Currently very little info is generated by +this logger. This will probably change. + + +* finalize + +This --log=finalize log option outputs information for type finalization, +the third tier of the compiler. This means things like placement of +specialized scope nodes or explicit conversions. + + +* fields + +The --log=fields option (at info level) is equivalent to setting the +system variable "nashorn.fields.debug" to true. At the info level it +will only show info about type assumptions that were invalidated. If +the level is set to finest, it will also trace every AccessorProperty +getter and setter in the program, show arguments, return values +etc. It will also show the internal representation of respective field +(Object in the normal case, unless running with the dual field +representation) diff --git a/nashorn/docs/JavaScriptingProgrammersGuide.html b/nashorn/docs/JavaScriptingProgrammersGuide.html new file mode 100644 index 00000000000..cf248140c15 --- /dev/null +++ b/nashorn/docs/JavaScriptingProgrammersGuide.html @@ -0,0 +1,751 @@ + + + +Java Scripting Programmer's Guide + + + + + + + + +
+ +

Java Scripting Programmer's Guide

+ +
+ +

+ +

Who is the Java Scripting API For?

+Some useful characteristics of scripting languages +are: +
    +
  • Convenience: Most scripting languages are +dynamically typed. You can usually create new variables without +declaring the variable type, and you can reuse variables to store +objects of different types. Also, scripting languages tend to +perform many type conversions automatically, for example, +converting the number 10 to the text "10" as necessary.
  • +
  • Developing rapid prototypes: You can avoid the +edit-compile-run cycle and just use edit-run!
  • +
  • Application extension/customization: You can +"externalize" parts of your application - like configuration +scripts, business logic/rules and math expressions for financial +applications.
  • +
  • "Command line" shells for applications -for +debugging, runtime/deploy time configuration etc. Most applications +have a web-based GUI configuaration tool these days. But +sysadmins/deployers frequently prefer command line tools. Instead +of inventing ad-hoc scripting language for that purpose, a +"standard" scripting language can be used.
  • +
+

The JavaTM Scripting API +is a scripting language indepedent framework for using script +engines from Java code. With the Java Scripting API, it is possible +to write customizable/extendable applications in the Java language +and leave the customization scripting language choice to the end +user. The Java application developer need not choose the extension +language during development. If you write your application with +JSR-223 API, then your users can use any JSR-223 compliant +scripting language.

+
+ +

Scripting Package

+

The Java Scripting functionality is in the javax.script +package. This is a relatively small, simple API. The starting point +of the scripting API is the ScriptEngineManager class. +A ScriptEngineManager object can discover script engines through +the jar file service discovery mechanism. It can also instantiate +ScriptEngine objects that interpret scripts written in a specific +scripting language. The simplest way to use the scripting API is as +follows:

+
    +
  1. Create a ScriptEngineManager +object.
  2. +
  3. Get a ScriptEngine object from the +manager.
  4. +
  5. Evaluate script using the ScriptEngine's +eval methods.
  6. +
+

Now, it is time to look at some sample code. While it is +not mandatory, it may be useful to know a bit of JavaScript to read +these examples.

+
+ +

Examples

+ +

"Hello, World"

+

From the ScriptEngineManager instance, we +request a JavaScript engine instance using +getEngineByName method. On the script engine, the +eval method is called to execute a given String as +JavaScript code! For brevity, in this as well as in subsequent +examples, we have not shown exception handling. There are checked +and runtime exceptions thrown from javax.script API. +Needless to say, you have to handle the exceptions +appropriately.

+
+
+// EvalScript.java
+
+import javax.script.*;
+public class EvalScript {
+    public static void main(String[] args) throws Exception {
+        // create a script engine manager
+        ScriptEngineManager factory = new ScriptEngineManager();
+        // create a JavaScript engine
+        ScriptEngine engine = factory.getEngineByName("nashorn");
+        // evaluate JavaScript code from String
+        engine.eval("print('Hello, World')");
+    }
+}
+
+
+
+ +

Evaluating a Script File

+

In this example, we call the eval method that +accepts java.io.Reader for the input source. The +script read by the given reader is executed. This way it is +possible to execute scripts from files, URLs and resources by +wrapping the relevant input stream objects as readers.

+
+
+// EvalFile.java
+
+import javax.script.*;
+
+public class EvalFile {
+    public static void main(String[] args) throws Exception {
+        // create a script engine manager
+        ScriptEngineManager factory = new ScriptEngineManager();
+        // create JavaScript engine
+        ScriptEngine engine = factory.getEngineByName("nashorn");
+        // evaluate JavaScript code from given file - specified by first argument
+        engine.eval(new java.io.FileReader(args[0]));
+    }
+}
+
+
+Let us assume that we have the file named test.js with the +following text: +

+print("This is hello from test.js");
+
+
+We can run the above Java as +

+java EvalFile test.js
+
+
+
+ +

Script Variables

+

When you embed script engines and scripts with your Java +application, you may want to expose your application objects as +global variables to scripts. This example demonstrates how you can +expose your application objects as global variables to a script. We +create a java.io.File in the application and expose +the same as a global variable with the name "file". The script can +access the variable - for example, it can call public methods on +it. Note that the syntax to access Java objects, methods and fields +is dependent on the scripting language. JavaScript supports the +most "natural" Java-like syntax.

+

+// ScriptVars.java
+
+import javax.script.*;
+import java.io.*;
+
+public class ScriptVars { 
+    public static void main(String[] args) throws Exception {
+        ScriptEngineManager manager = new ScriptEngineManager();
+        ScriptEngine engine = manager.getEngineByName("nashorn");
+
+        File f = new File("test.txt");
+        // expose File object as variable to script
+        engine.put("file", f);
+
+        // evaluate a script string. The script accesses "file" 
+        // variable and calls method on it
+        engine.eval("print(file.getAbsolutePath())");
+    }
+}
+
+
+
+
+ +

Invoking Script Functions and Methods

+

Sometimes you may want to call a specific scripting function +repeatedly - for example, your application menu functionality might +be implemented by a script. In your menu's action event handler you +may want to call a specific script function. The following example +demonstrates invoking a specific script function from Java +code.

+

+// InvokeScriptFunction.java
+
+import javax.script.*;
+
+public class InvokeScriptFunction {
+    public static void main(String[] args) throws Exception {
+        ScriptEngineManager manager = new ScriptEngineManager();
+        ScriptEngine engine = manager.getEngineByName("nashorn");
+
+        // JavaScript code in a String
+        String script = "function hello(name) { print('Hello, ' + name); }";
+        // evaluate script
+        engine.eval(script);
+
+        // javax.script.Invocable is an optional interface.
+        // Check whether your script engine implements it or not!
+        // Note that the JavaScript engine implements Invocable interface.
+        Invocable inv = (Invocable) engine;
+
+        // invoke the global function named "hello"
+        inv.invokeFunction("hello", "Scripting!!" );
+    }
+}
+
+
+
+

If your scripting language is object based (like JavaScript) or +object-oriented, then you can invoke a script method on a script +object.

+

+// InvokeScriptMethod.java
+
+import javax.script.*;
+
+public class InvokeScriptMethod {
+    public static void main(String[] args) throws Exception {
+        ScriptEngineManager manager = new ScriptEngineManager();
+        ScriptEngine engine = manager.getEngineByName("nashorn");
+
+        // JavaScript code in a String. This code defines a script object 'obj'
+        // with one method called 'hello'.        
+        String script = "var obj = new Object(); obj.hello = function(name) { print('Hello, ' + name); }";
+        // evaluate script
+        engine.eval(script);
+
+        // javax.script.Invocable is an optional interface.
+        // Check whether your script engine implements or not!
+        // Note that the JavaScript engine implements Invocable interface.
+        Invocable inv = (Invocable) engine;
+
+        // get script object on which we want to call the method
+        Object obj = engine.get("obj");
+
+        // invoke the method named "hello" on the script object "obj"
+        inv.invokeMethod(obj, "hello", "Script Method !!" );
+    }
+}
+
+
+
+
+ +

Implementing Java Interfaces by Scripts

+

Instead of calling specific script functions from Java, +sometimes it is convenient to implement a Java interface by script +functions or methods. Also, by using interfaces we can avoid having +to use the javax.script API in many places. We can get +an interface implementor object and pass it to various Java APIs. +The following example demonstrates implementing the +java.lang.Runnable interface with a script.

+

+// RunnableImpl.java
+
+import javax.script.*;
+
+public class RunnableImpl {
+    public static void main(String[] args) throws Exception {
+        ScriptEngineManager manager = new ScriptEngineManager();
+        ScriptEngine engine = manager.getEngineByName("nashorn");
+
+        // JavaScript code in a String
+        String script = "function run() { print('run called'); }";
+
+        // evaluate script
+        engine.eval(script);
+
+        Invocable inv = (Invocable) engine;
+
+        // get Runnable interface object from engine. This interface methods
+        // are implemented by script functions with the matching name.
+        Runnable r = inv.getInterface(Runnable.class);
+
+        // start a new thread that runs the script implemented
+        // runnable interface
+        Thread th = new Thread(r);
+        th.start();
+        th.join();
+    }
+}
+
+
+

If your scripting language is object-based or object-oriented, +it is possible to implement a Java interface by script methods on +script objects. This avoids having to call script global functions +for interface methods. The script object can store the "state" +associated with the interface implementor.

+

+// RunnableImplObject.java
+
+import javax.script.*;
+
+public class RunnableImplObject {
+    public static void main(String[] args) throws Exception {
+        ScriptEngineManager manager = new ScriptEngineManager();
+        ScriptEngine engine = manager.getEngineByName("nashorn");
+
+        // JavaScript code in a String
+        String script = "var obj = new Object(); obj.run = function() { print('run method called'); }";
+
+        // evaluate script
+        engine.eval(script);
+
+        // get script object on which we want to implement the interface with
+        Object obj = engine.get("obj");
+
+        Invocable inv = (Invocable) engine;
+
+        // get Runnable interface object from engine. This interface methods
+        // are implemented by script methods of object 'obj'
+        Runnable r = inv.getInterface(obj, Runnable.class);
+
+        // start a new thread that runs the script implemented
+        // runnable interface
+        Thread th = new Thread(r);
+        th.start();
+        th.join();
+    }
+}
+
+
+
+ +

Multiple Scopes for Scripts

+

In the script variables example, we +saw how to expose application objects as script global variables. +It is possible to expose multiple global "scopes" for scripts. A +single scope is an instance of javax.script.Bindings. +This interface is derived from java.util.Map<String, +Object>. A scope a set of name-value pairs where name is +any non-empty, non-null String. +javax.script.ScriptContext interface supports multiple +scopes with associated Bindings for each +scope. By default, every script engine has a default script +context. The default script context has atleast one scope called +"ENGINE_SCOPE". Various scopes supported by a script context are +available through getScopes method.

+

+// MultiScopes.java
+
+import javax.script.*;
+
+public class MultiScopes {
+    public static void main(String[] args) throws Exception {
+        ScriptEngineManager manager = new ScriptEngineManager();
+        ScriptEngine engine = manager.getEngineByName("nashorn");
+
+        engine.put("x", "hello");
+        // print global variable "x"
+        engine.eval("print(x);");
+        // the above line prints "hello"
+
+        // Now, pass a different script context
+        ScriptContext newContext = new SimpleScriptContext();
+        newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
+        Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE);
+
+        // add new variable "x" to the new engineScope        
+        engineScope.put("x", "world");
+
+        // execute the same script - but this time pass a different script context
+        engine.eval("print(x);", newContext);
+        // the above line prints "world"
+    }
+}
+
+
+
+
+ +

JavaScript Script Engine

+

Oracle's implementation of JDK 8 is co-bundled with the Nashorn ECMAScript +script engine. +


+ +

JavaScript to Java Communication

+

For the most part, accessing Java classes, objects and methods +is straightforward. In particular field and method access from +JavaScript is the same as it is from Java. We highlight important +aspects of JavaScript Java access here. +The following examples are JavaScript snippets accessing Java. This +section requires knowledge of JavaScript. This section can be +skipped if you are planning to use some other JSR-223 scripting +language rather than JavaScript.

+
+ +

Accessing Java Classes

+
+
+// javatypes.js
+
+ var arrayListType = Java.type("java.util.ArrayList")
+ var intType = Java.type("int")
+ var stringArrayType = Java.type("java.lang.String[]")
+ var int2DArrayType = Java.type("int[][]")
+
+
+ +Note that the name of the type is always a string for a fully qualified name. You can use any of these types to create new instances, e.g.: + +

+ var anArrayList = new Java.type("java.util.ArrayList")
+
+ +or + +

+ var ArrayList = Java.type("java.util.ArrayList")
+ var anArrayList = new ArrayList
+ var anArrayListWithSize = new ArrayList(16)
+
+ +In the special case of inner classes, you need to use the JVM fully qualified name, meaning using $ sign in the class name: + +

+ var ftype = Java.type("java.awt.geom.Arc2D$Float")
+
+ + +However, once you retrieved the outer class, you can access the inner class as a property on it: + +

+ var arctype = Java.type("java.awt.geom.Arc2D")
+ var ftype = arctype.Float
+
+

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

+
+ +

Importing Java Packages, Classes

+

The built-in functions importPackage (in compatibility script) and +importClass can be used to import Java packages and +classes.

+

+
+// importpackageclass.js
+
+// load compatibility script
+load("nashorn:mozilla_compat.js");
+// Import Java packages and classes 
+// like import package.*; in Java
+importPackage(java.awt);
+// like import java.awt.Frame in Java
+importClass(java.awt.Frame);
+// Create Java Objects by "new ClassName"
+var frame = new java.awt.Frame("hello");
+// Call Java public methods from script
+frame.setVisible(true);
+// Access "JavaBean" properties like "fields"
+print(frame.title);
+
+
+

The Packages global variable can +be used to access Java packages. Examples: +Packages.java.util.Vector, +Packages.javax.swing.JFrame. Please note that "java" +is a shortcut for "Packages.java". There are equivalent shortcuts +for javax, org, edu, com, net prefixes, so pratically all JDK +platform classes can be accessed without the "Packages" prefix.

+

Note that java.lang is not imported by default (unlike Java) +because that would result in conflicts with JavaScript's built-in +Object, Boolean, Math and so on.

+

importPackage and importClass +functions "pollute" the global variable scope of JavaScript. To +avoid that, you may use JavaImporter.

+

+
+// javaimporter.js
+
+// create JavaImporter with specific packages and classes to import
+
+var SwingGui = new JavaImporter(javax.swing,
+                            javax.swing.event,
+                            javax.swing.border,
+                            java.awt.event);
+with (SwingGui) {
+    // within this 'with' statement, we can access Swing and AWT
+    // classes by unqualified (simple) names.
+
+    var mybutton = new JButton("test");
+    var myframe = new JFrame("test");
+}
+
+
+
+
+ +

Creating, Converting and Using Java Arrays

+

While creating a Java object is the same as in Java, to create +Java arrays in JavaScript we can use Java reflection +explicitly. But once created the element access or length access is +the same as in Java. Also, a script array can be used when a Java +method expects a Java array (auto conversion). So in most cases we +don't have to create Java arrays explicitly.

+

+// javaarray.js
+
+// create Java String array of 5 elements
+var a = java.lang.reflect.Array.newInstance(java.lang.String.class, 5);
+
+// Accessing elements and length access is by usual Java syntax
+a[0] = "scripting is great!";
+print(a.length);
+print(a[0]);
+
+
+

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

+

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

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

+

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

Implementing Java Interfaces

+

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

+

+// runnable.js
+
+var r  = new java.lang.Runnable() {
+    run: function() {
+        print("running...\n");
+    }
+};
+
+// "r" can be passed to Java methods that expect java.lang.Runnable
+var th = new java.lang.Thread(r);
+th.start();
+th.join();
+
+
+

When an interface with a single method is expected, you can pass +a script function directly.(auto conversion)

+

+// samfunc.js
+
+function func() {
+     print("I am func!");
+}
+
+// pass script function for java.lang.Runnable argument
+var th = new java.lang.Thread(func);
+th.start();
+th.join();
+
+
+
+ +

Extending Java classes

+

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

+ +

+ var TimerTask =  Java.type("java.util.TimerTask")
+ var task = new TimerTask({ run: function() { print("Hello World!") } })
+
+ +Nashorn supports a syntactic extension where a "new" expression followed by an argument is identical to invoking the constructor and passing the argument to it, so you can write the above example also as: + +

+ var task = new TimerTask {
+     run: function() {
+       print("Hello World!")
+     }
+ }
+
+ +which is very similar to Java anonymous inner class definition. On the other hand, if the type is an abstract type with a single abstract method (commonly referred to as a "SAM type") or all abstract methods it has share the same overloaded name), then instead of an object, you can just pass a function, so the above example can become even more simplified to: + +

+ var task = new TimerTask(function() { print("Hello World!") })
+
+ +

+Note that in every one of these cases if you are trying to instantiate an abstract class that has constructors that take some arguments, you can invoke those simply by specifying the arguments after the initial implementation object or function. +

+

+The use of functions can be taken even further; if you are invoking a Java method that takes a SAM type, you can just pass in a function object, and Nashorn will know what you meant: +

+
+ Java.type("java.util.Timer")
+ timer.schedule(function() { print("Hello World!") })
+
+ +Here, Timer.schedule() expects a TimerTask as its argument, so Nashorn creates an instance of a TimerTask subclass and uses the passed function to implement its only abstract method, run(). In this usage though, you can't use non-default constructors; the type must be either an interface, or must have a protected or public no-arg constructor. + +

+To extend a concrete Java class, you have to use Java.extend function. +Java.extend returns a type object for a subclass of the specified Java class (or implementation of the specified interface) that acts as a script-to-Java adapter for it. +

+

+// javaextend.js
+
+var ArrayList = Java.type("java.util.ArrayList")
+var ArrayListExtender = Java.extend(ArrayList)
+var printSizeInvokedArrayList = new ArrayListExtender() {
+    size: function() { print("size invoked!"); }
+}
+var printAddInvokedArrayList = new ArrayListExtender() {
+    add: function(x, y) {
+        if(typeof(y) === "undefined") {
+            print("add(e) invoked!");
+        } else {
+            print("add(i, e) invoked!");
+        }
+    }
+};
+printSizeInvokedArrayList.size();
+printAddInvokedArrayList.add(33, 33);
+
+
+ +

Overload Resolution

+

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

+

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

Implementing Your Own Script Engine

+

We will not cover implementation of JSR-223 compliant script +engines in detail. Minimally, you need to implement the +javax.script.ScriptEngine and +javax.script.ScriptEngineFactory interfaces. The +abstract class javax.script.AbstractScriptEngine +provides useful defaults for a few methods of the +ScriptEngine interface.

+

Before starting to implement a JSR-223 engine, you may want to +check http://java.net/projects/Scripting +project. This project maintains JSR-223 implementations for many +popular open source scripting languages.

+
+ +

References

+ + + + +

+ + + + + + + +
Oracle and/or its affiliates
+ Java Technology
+

+Copyright © 2013, Oracle and/or its affiliates. All rights reserved. +

+
+

Contact Us

+
+

+ + + + + + + + + + + + + + + diff --git a/nashorn/docs/genshelldoc.js b/nashorn/docs/genshelldoc.js new file mode 100644 index 00000000000..3d11a471a3e --- /dev/null +++ b/nashorn/docs/genshelldoc.js @@ -0,0 +1,90 @@ +/* + * 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. + */ + +/** + * Generate HTML documentation for shell tool. Re-run this tool to regenerate + * html doc when you change options. + * + * Usage: + * + * jjs -scripting genshelldoc.js > shell.html + */ + +var Options = Packages.jdk.nashorn.internal.runtime.options.Options; +var title = "Nashorn command line shell tool"; + +print(< + + +${title} + + + +

Usage

+

+ +jjs <options> <script-files> [ -- <script-arguments> ] + +

+ +

${title} options

+ + + + + + + + +PREFIX); + +for each (opt in Options.validOptions) { + +var isTimezone = (opt.type == "timezone"); +var defValue = opt.defaultValue; +if (defValue == null) { + defValue = "<none>"; +} + +if (isTimezone) { + // don't output current user's timezone + defValue = "<default-timezone>" +} + +print(< + + + + + +ROW); + +} + +print(< + + +SUFFIX); diff --git a/nashorn/docs/source/EvalFile.java b/nashorn/docs/source/EvalFile.java new file mode 100644 index 00000000000..6bb4e38118c --- /dev/null +++ b/nashorn/docs/source/EvalFile.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +import javax.script.*; + +public class EvalFile { + public static void main(String[] args) throws Exception { + // create a script engine manager + ScriptEngineManager factory = new ScriptEngineManager(); + // create JavaScript engine + ScriptEngine engine = factory.getEngineByName("nashorn"); + // evaluate JavaScript code from given file - specified by first argument + engine.eval(new java.io.FileReader(args[0])); + } +} + diff --git a/nashorn/docs/source/EvalScript.java b/nashorn/docs/source/EvalScript.java new file mode 100644 index 00000000000..7fcbe1cd879 --- /dev/null +++ b/nashorn/docs/source/EvalScript.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +import javax.script.*; + +public class EvalScript { + public static void main(String[] args) throws Exception { + // create a script engine manager + ScriptEngineManager factory = new ScriptEngineManager(); + // create a JavaScript engine + ScriptEngine engine = factory.getEngineByName("nashorn"); + // evaluate JavaScript code from String + engine.eval("print('Hello, World')"); + } +} + diff --git a/nashorn/docs/source/InvokeScriptFunction.java b/nashorn/docs/source/InvokeScriptFunction.java new file mode 100644 index 00000000000..26de36c4e94 --- /dev/null +++ b/nashorn/docs/source/InvokeScriptFunction.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +import javax.script.*; + +public class InvokeScriptFunction { + public static void main(String[] args) throws Exception { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName("nashorn"); + + // JavaScript code in a String + String script = "function hello(name) { print('Hello, ' + name); }"; + // evaluate script + engine.eval(script); + + // javax.script.Invocable is an optional interface. + // Check whether your script engine implements or not! + // Note that the JavaScript engine implements Invocable interface. + Invocable inv = (Invocable) engine; + + // invoke the global function named "hello" + inv.invokeFunction("hello", "Scripting!!" ); + } +} + + + diff --git a/nashorn/docs/source/InvokeScriptMethod.java b/nashorn/docs/source/InvokeScriptMethod.java new file mode 100644 index 00000000000..a3f5ece745f --- /dev/null +++ b/nashorn/docs/source/InvokeScriptMethod.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +import javax.script.*; + +public class InvokeScriptMethod { + public static void main(String[] args) throws Exception { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName("nashorn"); + + // JavaScript code in a String. This code defines a script object 'obj' + // with one method called 'hello'. + String script = "var obj = new Object(); obj.hello = function(name) { print('Hello, ' + name); }"; + // evaluate script + engine.eval(script); + + // javax.script.Invocable is an optional interface. + // Check whether your script engine implements or not! + // Note that the JavaScript engine implements Invocable interface. + Invocable inv = (Invocable) engine; + + // get script object on which we want to call the method + Object obj = engine.get("obj"); + + // invoke the method named "hello" on the script object "obj" + inv.invokeMethod(obj, "hello", "Script Method !!" ); + } +} diff --git a/nashorn/docs/source/MultiScopes.java b/nashorn/docs/source/MultiScopes.java new file mode 100644 index 00000000000..6c4fa2a27b6 --- /dev/null +++ b/nashorn/docs/source/MultiScopes.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +import javax.script.*; + +public class MultiScopes { + public static void main(String[] args) throws Exception { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName("nashorn"); + + engine.put("x", "hello"); + // print global variable "x" + engine.eval("print(x);"); + // the above line prints "hello" + + // Now, pass a different script context + ScriptContext newContext = new SimpleScriptContext(); + newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); + Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE); + + // add new variable "x" to the new engineScope + engineScope.put("x", "world"); + + // execute the same script - but this time pass a different script context + engine.eval("print(x);", newContext); + // the above line prints "world" + } +} + + diff --git a/nashorn/docs/source/RunnableImpl.java b/nashorn/docs/source/RunnableImpl.java new file mode 100644 index 00000000000..1d858d40cd8 --- /dev/null +++ b/nashorn/docs/source/RunnableImpl.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +import javax.script.*; + +public class RunnableImpl { + public static void main(String[] args) throws Exception { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName("nashorn"); + + // JavaScript code in a String + String script = "function run() { print('run called'); }"; + + // evaluate script + engine.eval(script); + + Invocable inv = (Invocable) engine; + + // get Runnable interface object from engine. This interface methods + // are implemented by script functions with the matching name. + Runnable r = inv.getInterface(Runnable.class); + + // start a new thread that runs the script implemented + // runnable interface + Thread th = new Thread(r); + th.start(); + th.join(); + } +} diff --git a/nashorn/docs/source/RunnableImplObject.java b/nashorn/docs/source/RunnableImplObject.java new file mode 100644 index 00000000000..877f8c15e17 --- /dev/null +++ b/nashorn/docs/source/RunnableImplObject.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +import javax.script.*; + +public class RunnableImplObject { + public static void main(String[] args) throws Exception { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName("nashorn"); + + // JavaScript code in a String + String script = "var obj = new Object(); obj.run = function() { print('run method called'); }"; + + // evaluate script + engine.eval(script); + + // get script object on which we want to implement the interface with + Object obj = engine.get("obj"); + + Invocable inv = (Invocable) engine; + + // get Runnable interface object from engine. This interface methods + // are implemented by script methods of object 'obj' + Runnable r = inv.getInterface(obj, Runnable.class); + + // start a new thread that runs the script implemented + // runnable interface + Thread th = new Thread(r); + th.start(); + th.join(); + } +} diff --git a/nashorn/docs/source/ScriptVars.java b/nashorn/docs/source/ScriptVars.java new file mode 100644 index 00000000000..7e16cfca09e --- /dev/null +++ b/nashorn/docs/source/ScriptVars.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +import javax.script.*; +import java.io.*; + +public class ScriptVars { + public static void main(String[] args) throws Exception { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName("nashorn"); + + File f = new File("test.txt"); + // expose File object as variable to script + engine.put("file", f); + + // evaluate a script string. The script accesses "file" + // variable and calls method on it + engine.eval("print(file.getAbsolutePath())"); + } +} + + + diff --git a/nashorn/docs/source/importpackageclass.js b/nashorn/docs/source/importpackageclass.js new file mode 100644 index 00000000000..afc02a9bf37 --- /dev/null +++ b/nashorn/docs/source/importpackageclass.js @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +// load compatibility script +load("nashorn:mozilla_compat.js"); + +// Import Java packages and classes +// like import package.*; in Java +importPackage(java.awt); +// like import java.awt.Frame in Java +importClass(java.awt.Frame); +// Create Java Objects by "new ClassName" +var frame = new java.awt.Frame("hello"); +// Call Java public methods from script +frame.setVisible(true); +// Access "JavaBean" properties like "fields" +print(frame.title); diff --git a/nashorn/docs/source/javaarray.js b/nashorn/docs/source/javaarray.js new file mode 100644 index 00000000000..b9d93f0d42c --- /dev/null +++ b/nashorn/docs/source/javaarray.js @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +// create Java String array of 5 elements +var a = java.lang.reflect.Array.newInstance(java.lang.String.class, 5); + +// Accessing elements and length access is by usual Java syntax +a[0] = "scripting is great!"; +print(a.length); +print(a[0]); + +// convert a script array to Java array +var anArray = [1, "13", false]; +var javaIntArray = Java.toJavaArray(anArray, "int"); +print(javaIntArray[0]);// prints 1 +print(javaIntArray[1]); // prints 13, as string "13" was converted to number 13 as per ECMAScript ToNumber conversion +print(javaIntArray[2]);// prints 0, as boolean false was converted to number 0 as per ECMAScript ToNumber conversion + +// convert a Java array to a JavaScript array +var File = Java.type("java.io.File"); +var listCurDir = new File(".").listFiles(); +var jsList = Java.toJavaScriptArray(listCurDir); +print(jsList); diff --git a/nashorn/docs/source/javaextend.js b/nashorn/docs/source/javaextend.js new file mode 100644 index 00000000000..408da320a19 --- /dev/null +++ b/nashorn/docs/source/javaextend.js @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +var ArrayList = Java.type("java.util.ArrayList") +var ArrayListExtender = Java.extend(ArrayList) +var printSizeInvokedArrayList = new ArrayListExtender() { + size: function() { print("size invoked!"); } +} +var printAddInvokedArrayList = new ArrayListExtender() { + add: function(x, y) { + if(typeof(y) === "undefined") { + print("add(e) invoked!"); + } else { + print("add(i, e) invoked!"); + } + } +}; +printSizeInvokedArrayList.size(); +printAddInvokedArrayList.add(33, 33); diff --git a/nashorn/docs/source/javaimporter.js b/nashorn/docs/source/javaimporter.js new file mode 100644 index 00000000000..3bd07988d21 --- /dev/null +++ b/nashorn/docs/source/javaimporter.js @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +// create JavaImporter with specific packages and classes to import + +var SwingGui = new JavaImporter(javax.swing, + javax.swing.event, + javax.swing.border, + java.awt.event); +with (SwingGui) { + // within this 'with' statement, we can access Swing and AWT + // classes by unqualified (simple) names. + + var mybutton = new JButton("test"); + print(mybutton); + var myframe = new JFrame("test"); + print(myframe); +} + + diff --git a/nashorn/docs/source/javatypes.js b/nashorn/docs/source/javatypes.js new file mode 100644 index 00000000000..e0b6f07b137 --- /dev/null +++ b/nashorn/docs/source/javatypes.js @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + + +// accessing java types +var arrayListType = Java.type("java.util.ArrayList") +var intType = Java.type("int") +var stringArrayType = Java.type("java.lang.String[]") +var int2DArrayType = Java.type("int[][]") + +// Using java types +var ArrayList = Java.type("java.util.ArrayList") +var anArrayList = new ArrayList +var anArrayListWithSize = new ArrayList(16) + +// fully qualified name +var ftype = Java.type("java.awt.geom.Arc2D$Float") + +// inner class property +var arctype = Java.type("java.awt.geom.Arc2D") +var ftype = arctype.Float + diff --git a/nashorn/docs/source/overload.js b/nashorn/docs/source/overload.js new file mode 100644 index 00000000000..2407d0c5a5c --- /dev/null +++ b/nashorn/docs/source/overload.js @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +var out = java.lang.System.out; + +// select a particular print function +out["println(java.lang.Object)"]("hello"); + diff --git a/nashorn/docs/source/runnable.js b/nashorn/docs/source/runnable.js new file mode 100644 index 00000000000..67cd31c67cf --- /dev/null +++ b/nashorn/docs/source/runnable.js @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +var r = new java.lang.Runnable() { + run: function() { + print("running...\n"); + } +}; + +// "r" can be passed to Java methods that expect java.lang.Runnable +var th = new java.lang.Thread(r); +th.start(); +th.join(); diff --git a/nashorn/docs/source/samfunc.js b/nashorn/docs/source/samfunc.js new file mode 100644 index 00000000000..c870076e1fd --- /dev/null +++ b/nashorn/docs/source/samfunc.js @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +function func() { + print("I am func!"); +} + +// pass script function for java.lang.Runnable argument +var th = new java.lang.Thread(func); +th.start(); +th.join(); diff --git a/nashorn/docs/source/test.js b/nashorn/docs/source/test.js new file mode 100644 index 00000000000..6323c386479 --- /dev/null +++ b/nashorn/docs/source/test.js @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +print("This is hello from test.js"); diff --git a/nashorn/make/Makefile b/nashorn/make/Makefile new file mode 100644 index 00000000000..443f8db6c67 --- /dev/null +++ b/nashorn/make/Makefile @@ -0,0 +1,59 @@ +# +# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# + +# +# On Solaris, the standard 'make' utility will not work with these makefiles. +# This little rule is only understood by Solaris make, and is harmless +# when seen by the GNU make tool. If using Solaris make, this causes the +# make command to fail. +# +SUN_MAKE_TEST:sh = @echo "ERROR: PLEASE USE GNU VERSION OF MAKE"; exit 33 + + +# Default target and expected 'do everything' target +all: + echo Nashorn can only be built with NEWBUILD=true + +# Standard make clobber target +clobber: + +#------------------------------------------------------------------- +# +# Targets for Oracle's internal JPRT build system + +CD = cd +ZIP = zip + +JPRT_ARCHIVE_BUNDLE=$(ABS_OUTPUTDIR)/$(JPRT_BUILD_FLAVOR)-bundle.zip + +jprt_build_product jprt_build_debug jprt_build_fastdebug: all + ( $(CD) $(OUTPUTDIR) && \ + $(ZIP) -q -r $(JPRT_ARCHIVE_BUNDLE) build dist ) + +#------------------------------------------------------------------- + +# Declare these phony (not filenames) +.PHONY: $(ANT_TARGETS) all clobber \ + jprt_build_product jprt_build_debug jprt_build_fastdebug diff --git a/nashorn/make/build-benchmark.xml b/nashorn/make/build-benchmark.xml new file mode 100644 index 00000000000..d28de93df79 --- /dev/null +++ b/nashorn/make/build-benchmark.xml @@ -0,0 +1,412 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nashorn/make/build-nasgen.xml b/nashorn/make/build-nasgen.xml new file mode 100644 index 00000000000..5797befaba8 --- /dev/null +++ b/nashorn/make/build-nasgen.xml @@ -0,0 +1,86 @@ + + + + Builds and runs nasgen. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml new file mode 100644 index 00000000000..34f56e4602b --- /dev/null +++ b/nashorn/make/build.xml @@ -0,0 +1,472 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${run.test.jvmargs.main} ${run.test.cc.jvmargs} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${line.separator} + + + + + + + + + + + +
+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \/ + /// + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Representation test failed - output differs! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/nashorn/make/code_coverage.xml b/nashorn/make/code_coverage.xml new file mode 100644 index 00000000000..41d85ff3ef1 --- /dev/null +++ b/nashorn/make/code_coverage.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nashorn/make/java.security.override b/nashorn/make/java.security.override new file mode 100644 index 00000000000..0021985287e --- /dev/null +++ b/nashorn/make/java.security.override @@ -0,0 +1,14 @@ +# We would like to avoid references from anywhere outside nashorn +# to codegen, IR and parser packages, in particular script generated classes. +# We ensure that by overriding "package.access" security property. + +# The following "package.access" value was copied from default java.security +# of jre/lib/security and appended with nashorn IR, Codegen and Parser packages. + +# +# List of comma-separated packages that start with or equal this string +# will cause a security exception to be thrown when +# passed to checkPackageAccess unless the +# corresponding RuntimePermission ("accessClassInPackage."+package) has +# been granted. +package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.org.apache.xerces.internal.utils.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.glassfish.external.,com.sun.org.glassfish.gmbal.,jdk.internal.,jdk.nashorn.internal.ir., jdk.nashorn.internal.codegen., jdk.nashorn.internal.lookup., jdk.nashorn.internal.parser. diff --git a/nashorn/make/nbproject/ide-file-targets.xml b/nashorn/make/nbproject/ide-file-targets.xml new file mode 100644 index 00000000000..cb017bb21d4 --- /dev/null +++ b/nashorn/make/nbproject/ide-file-targets.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + Must set property 'debug.class' + + + + + + + + + + + + + + + + + Must set property 'run.class' + + + + + + + + + diff --git a/nashorn/make/nbproject/ide-targets.xml b/nashorn/make/nbproject/ide-targets.xml new file mode 100644 index 00000000000..70b3e68fcb7 --- /dev/null +++ b/nashorn/make/nbproject/ide-targets.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/nashorn/make/nbproject/jdk.xml b/nashorn/make/nbproject/jdk.xml new file mode 100644 index 00000000000..2fabe8c9e3d --- /dev/null +++ b/nashorn/make/nbproject/jdk.xml @@ -0,0 +1,179 @@ + + + + + + Permits selection of a JDK to use when building and running project. + See: http://www.netbeans.org/issues/show_bug.cgi?id=64160 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nbjdk.active=${nbjdk.active} nbjdk.home=${nbjdk.home} nbjdk.java=${nbjdk.java} nbjdk.javac=${nbjdk.javac} nbjdk.javadoc=${nbjdk.javadoc} nbjdk.bootclasspath=${nbjdk.bootclasspath} nbjdk.valid=${nbjdk.valid} have-jdk-1.4=${have-jdk-1.4} have-jdk-1.5=${have-jdk-1.5} + + + + + Warning: nbjdk.active=${nbjdk.active} or nbjdk.home=${nbjdk.home} is an invalid Java platform; ignoring and using ${jdkhome.presumed} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/langtools/test/tools/javap/PublicInterfaceTest.sh b/nashorn/make/nbproject/nbjdk.properties similarity index 51% rename from langtools/test/tools/javap/PublicInterfaceTest.sh rename to nashorn/make/nbproject/nbjdk.properties index 0d8d441be39..8809e40bff4 100644 --- a/langtools/test/tools/javap/PublicInterfaceTest.sh +++ b/nashorn/make/nbproject/nbjdk.properties @@ -1,62 +1,24 @@ -#!/bin/sh - # -# Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# +# # This code is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License version 2 only, as # published by the Free Software Foundation. -# +# # This code is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # version 2 for more details (a copy is included in the LICENSE file that # accompanied this code). -# +# # You should have received a copy of the GNU General Public License version # 2 along with this work; if not, write to the Free Software Foundation, # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# +# # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. # +nbjdk.active=JDK_1.8 -# @test -# @bug 4866831 -# @build NotPackagePrivateInterface -# @run shell PublicInterfaceTest.sh -# @summary Verify that javap marks public interfaces as public -# @author Joseph D. Darcy - -# Verify directory context variables are set -if [ "${TESTJAVA}" = "" ] -then - echo "TESTJAVA not set. Test cannot execute. Failed." - exit 1 -fi - -if [ "${TESTCLASSES}" = "" ] -then - echo "TESTCLASSES not set. Test cannot execute. Failed." - exit 1 -fi - -JAVAP="${TESTJAVA}/bin/javap" - -"$JAVAP" ${TESTTOOLVMOPTS} -classpath "${TESTCLASSES}" NotPackagePrivateInterface | grep public - -# If the exit status of grep is 0, then "public" was correctly found -# in the output of javap. - -RESULT=$? -case "$RESULT" in - 0 ) - exit 0; - ;; - - * ) - echo "The javap tool did not output \"public\" for a public interface." - exit 1 -esac diff --git a/nashorn/make/nbproject/nbjdk.xml b/nashorn/make/nbproject/nbjdk.xml new file mode 100644 index 00000000000..102045e3ef1 --- /dev/null +++ b/nashorn/make/nbproject/nbjdk.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nashorn/make/nbproject/project.xml b/nashorn/make/nbproject/project.xml new file mode 100644 index 00000000000..828dc29d16b --- /dev/null +++ b/nashorn/make/nbproject/project.xml @@ -0,0 +1,176 @@ + + + + org.netbeans.modules.ant.freeform + + + nashorn + + + + nashorn + + + + + . + UTF-8 + + + + ../src + + + + ../test/src + + + + ../buildtools/nasgen/src + + + + java + ../test/src + UTF-8 + + + + java + ../src + UTF-8 + + + + java + ../buildtools/nasgen/src + UTF-8 + + + + + + jar + + + + clean + + + + javadoc + + + + test + + + + clean + jar + + + + run + + + + debug-nb + + + + debug-selected-file-in-src + + debug.class + test/src + \.java$ + java-name + + + + + + + + run-selected-file-in-src + + run.class + test/src + \.java$ + java-name + + + + + + + + + + + ../test/src + + + + ../src + + + + ../buildtools/nasgen/src + + + build.xml + + + + + + + + + + + + + + + + + ../test/src + + ../test/lib/testng.jar:../build/classes:../src + 1.7 + + + ../src + 1.7 + + + ../buildtools/nasgen/src + ../build/classes:../src + 1.7 + + + + diff --git a/nashorn/make/project.properties b/nashorn/make/project.properties new file mode 100644 index 00000000000..c4d0b943cd7 --- /dev/null +++ b/nashorn/make/project.properties @@ -0,0 +1,244 @@ +# +# 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. +# + +application.title=nashorn + +# location of JDK embedded ASM sources +jdk.asm.src.dir=../jdk/src/share/classes/jdk/internal/org/objectweb/asm + +# source and target levels +build.compiler=modern +javac.source=1.7 +javac.target=1.7 + +# nashorn version information +nashorn.version=0.1 +nashorn.fullversion=0.1 +nashorn.product.name=Oracle Nashorn + +# This directory is removed when the project is cleaned: +build.dir=build +build.classes.dir=${build.dir}/classes +build.zip=${build.dir}/nashorn.zip +build.gzip=${build.dir}/nashorn.tar.gz + +# nashorn Shell tool +nashorn.shell.tool=jdk.nashorn.tools.Shell + +# nasgen tool +nasgen.tool=jdk.nashorn.internal.tools.nasgen.Main + +# parallel test runner tool +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 + +# test results directory +build.test.results.dir=${build.dir}/test/reports + +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/nashorn.jar +dist.javadoc.dir=${dist.dir}/javadoc + +# jars refererred +file.reference.testng.jar=test/lib/testng.jar + +# Set testng verbose level +# From TestNG docs: "the verbosity level (0 to 10 where 10 is most detailed) +# Actually, this is a lie: you can specify -1 and this will put TestNG in +# debug mode (no longer slicing off stack traces and all)." + +testng.verbose=2 + +# TestNG listeners - we want to replace TestNG's own JUnit +# reporter, but want everything else provided by default +# Unfortunately, we've to clone the other default reporters here. + +testng.listeners=\ + org.testng.reporters.SuiteHTMLReporter, \ + org.testng.reporters.jq.Main, \ + org.testng.reporters.FailedReporter, \ + org.testng.reporters.XMLReporter \ + org.testng.reporters.EmailableReporter, \ + jdk.nashorn.internal.test.framework.JSJUnitReportReporter + +javac.debug=true +javac.encoding=ascii +javac.classpath=\ + ${build.classes.dir} +javac.test.classpath=\ + ${build.classes.dir}:\ + ${build.test.classes.dir}:\ + ${file.reference.testng.jar} + +meta.inf.dir=${src.dir}/META-INF + +run.classpath=\ + ${build.classes.dir} + +# test scripts to run +test.dir=test +test.script.dir=test/script +test.basic.dir=test/script/basic +test.error.dir=test/script/error +test.sandbox.dir=test/script/sandbox +test.trusted.dir=test/script/trusted +test.external.dir=test/script/external +test262.dir=${test.external.dir}/test262 +test262.suite.dir=${test262.dir}/test/suite + +test-sys-prop.test.dir=${test.dir} +test-sys-prop.test.js.roots=${test.basic.dir} ${test.error.dir} ${test.sandbox.dir} ${test.trusted.dir} +test-sys-prop.test262.suite.dir=${test262.suite.dir} +test-sys-prop.es5conform.testcases.dir=${test.external.dir}/ES5Conform/TestCases +test-sys-prop.test.basic.dir=${test.basic.dir} + +# framework root for our script tests +test-sys-prop.test.js.framework=${test.script.dir}/assert.js + +# Control the verbosity of ParserTest +test-sys-prop.parsertest.verbose=false + +# turn on/off scripting mode for parser tests +test-sys-prop.parsertest.scripting=true + +# turn on/off test262 scripts for parser tests +test-sys-prop.parsertest.test262=false + +# Control the verbosity of the CompilerTest +test-sys-prop.compilertest.verbose=false + +# turn on/off scripting mode for compiler tests +test-sys-prop.compilertest.scripting=true + +# turn on/off test262 scripts for compiler tests +test-sys-prop.compilertest.test262=false + +# test directory to be excluded. +test-sys-prop.test.js.exclude.dir=${test.script.dir}/currently-failing ${test.external.dir} + +# run everything that's js in here, without checking file headers for test annotations +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? +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/ + +# framework root for sunspider +sunspider-test-sys-prop.test.js.framework=${test.basic.dir}/runsunspider.js + +# list of tests to be excluded +sunspider-test-sys-prop.test.js.exclude.list= + +# execute our script tests in shared nashorn context or not? +test-sys-prop.test.js.shared.context=false + +# execute test262 tests in shared nashorn context or not? +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 + +# file containing test262 tests to be excluded +# test262-test-sys-prop.test.js.excludes.file=${test262.dir}/test/config/excludelist.xml + +# list of test262 test dirs to be excluded +test262-test-sys-prop.test.js.exclude.dir=\ + ${test262.suite.dir}/intl402/ + +# test262 test frameworks +test262-test-sys-prop.test.js.framework=\ + -timezone=PST \ + ${test.script.dir}/test262.js \ + ${test262.dir}/test/harness/framework.js \ + ${test262.dir}/test/harness/sta.js + +run.test.classpath=\ + ${file.reference.testng.jar}:\ + ${nashorn.internal.tests.jar}:\ + ${nashorn.api.tests.jar} + +src.dir=src +test.src.dir=test/src + +run.test.xmx=3G +run.test.xms=2G + +# -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods +# add '-Dtest.js.outofprocess' to run each test in a new sub-process +run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:-TieredCompilation -esa -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8 +#-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M +run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs} + +run.test.jvmsecurityargs=-Xverify:all -Djava.security.properties=${basedir}/make/java.security.override -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy + +# path of rhino.jar for benchmarks +rhino.jar= + +v8.shell=d8 + +#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 +make.code.coverage=false + #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!!! +cc.dir=${basedir}/../Codecoverage_Nashorn +cc.result.file.name=cc_nashorn.xml + #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\.* +cc.exclude=jdk\.nashorn\.internal\.scripts\.* +cc.dynamic.args=-javaagent:${jcov.jar}=include=${cc.include},exclude=${cc.exclude},type=all,verbose=0,file=${cc.dir}/${cc.result.file.name} diff --git a/nashorn/makefiles/BuildNashorn.gmk b/nashorn/makefiles/BuildNashorn.gmk new file mode 100644 index 00000000000..d08f7e8fa6f --- /dev/null +++ b/nashorn/makefiles/BuildNashorn.gmk @@ -0,0 +1,115 @@ +# +# 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 must be the first rule +default: all + +-include $(SPEC) +include MakeBase.gmk +include JavaCompilation.gmk + +JDK_CLASSES := $(JDK_OUTPUTDIR)/classes + +NASHORN_JAR := $(NASHORN_DIST)/nashorn.jar +NASHORN_VERSION := $(JDK_VERSION) +NASHORN_FULL_VERSION := $(FULL_VERSION) + +ifdef MILESTONE + ifeq ($(MILESTONE),internal) + NASHORN_VERSION = $(FULL_VERSION) + endif +endif + +# Need to use source and target 7 for nasgen to work. +$(eval $(call SetupJavaCompiler,GENERATE_NEWBYTECODE_DEBUG,\ + JVM:=$(JAVA),\ + JAVAC:=$(NEW_JAVAC),\ + FLAGS:=-g -source 7 -target 7 -bootclasspath $(JDK_CLASSES),\ + SERVER_DIR:=$(SJAVAC_SERVER_DIR),\ + SERVER_JVM:=$(SJAVAC_SERVER_JAVA))) + +# Build nashorn into intermediate directory +$(eval $(call SetupJavaCompilation,BUILD_NASHORN,\ + SETUP:=GENERATE_NEWBYTECODE_DEBUG,\ + SRC:=$(NASHORN_TOPDIR)/src,\ + COPY:=.properties .js,\ + BIN:=$(NASHORN_OUTPUTDIR)/nashorn_classes)) + +NASGEN_SRC := $(NASHORN_TOPDIR)/buildtools/nasgen/src +ASM_SRC := $(JDK_TOPDIR)/src/share/classes/jdk/internal/org/objectweb/asm + +# Build nasgen +$(eval $(call SetupJavaCompilation,BUILD_NASGEN,\ + SETUP:=GENERATE_NEWBYTECODE_DEBUG,\ + SRC:=$(NASGEN_SRC) $(ASM_SRC), \ + BIN:=$(NASHORN_OUTPUTDIR)/nasgen_classes,\ + ADD_JAVAC_FLAGS:=-cp $(NASHORN_OUTPUTDIR)/nashorn_classes)) + +# Nasgen needs nashorn classes +$(BUILD_NASGEN): $(BUILD_NASHORN) + +# Copy classes to final classes dir and run nasgen to modify classes in jdk.nashorn.internal.objects package +# Finally rename classes in jdk.nashorn.internal.objects package +$(NASHORN_OUTPUTDIR)/classes/_the.nasgen.run: $(BUILD_NASGEN) + $(ECHO) Running nasgen + $(MKDIR) -p $(@D) + $(RM) -rf $(@D)/jdk $(@D)/netscape + $(CP) -R -p $(NASHORN_OUTPUTDIR)/nashorn_classes/* $(@D)/ + $(FIXPATH) $(JAVA) \ + -cp "$(NASHORN_OUTPUTDIR)/nasgen_classes$(PATH_SEP)$(NASHORN_OUTPUTDIR)/nashorn_classes" \ + jdk.nashorn.internal.tools.nasgen.Main $(@D) jdk.nashorn.internal.objects $(@D) + for f in `$(FIND) $(@D)/jdk/nashorn/internal/objects/ -name "*.class"`; do \ + mv "$$f" `$(ECHO) "$$f" | $(SED) "s/\.class$$/\.clazz/"`; \ + done + $(TOUCH) $@ + +# Version file needs to be processed with version numbers +VERSION_FILE := $(NASHORN_OUTPUTDIR)/classes/jdk/nashorn/internal/runtime/resources/version.properties +# Needs to happen after nasgen run since nasgen run deletes it +$(VERSION_FILE): $(NASHORN_OUTPUTDIR)/classes/_the.nasgen.run +$(VERSION_FILE): $(NASHORN_TOPDIR)/src/jdk/nashorn/internal/runtime/resources/version.properties-template + $(ECHO) Creating version.properties + $(MKDIR) -p $(@D) + $(CAT) $< | $(SED) -e 's/$$(FULL_VERSION)/$(NASHORN_FULL_VERSION)/g' \ + -e 's/$$(RELEASE)/$(NASHORN_VERSION)/g' \ + -e '/^#.*$$/d' -e '/^$$/d' > $@ + + +MANIFEST_ATTRIBUTES:=Name: jdk/nashorn/\nImplementation-Title: Oracle Nashorn\nImplementation-Version: $(NASHORN_FULL_VERSION) + +# Create nashorn.jar from the final classes dir +$(eval $(call SetupArchive,BUILD_NASHORN_JAR,\ + $(NASHORN_OUTPUTDIR)/classes/_the.nasgen.run \ + $(VERSION_FILE),\ + SRCS:=$(NASHORN_OUTPUTDIR)/classes,\ + SUFFIXES:=.class .clazz .js .properties Factory,\ + MANIFEST:=$(NASHORN_TOPDIR)/src/META-INF/MANIFEST.MF,\ + EXTRA_MANIFEST_ATTR:=$(MANIFEST_ATTRIBUTES),\ + SKIP_METAINF:=true,\ + JAR:=$(NASHORN_JAR))) + +all: $(NASHORN_JAR) + +.PHONY: all diff --git a/nashorn/makefiles/Makefile b/nashorn/makefiles/Makefile new file mode 100644 index 00000000000..9539fe0e255 --- /dev/null +++ b/nashorn/makefiles/Makefile @@ -0,0 +1,49 @@ +# +# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# + +# Locate this Makefile +ifeq ($(filter /%,$(lastword $(MAKEFILE_LIST))),) + makefile_path:=$(CURDIR)/$(lastword $(MAKEFILE_LIST)) +else + makefile_path:=$(lastword $(MAKEFILE_LIST)) +endif +repo_dir:=$(patsubst %/makefiles/Makefile,%,$(makefile_path)) + +# What is the name of this subsystem (langtools, corba, etc)? +subsystem_name:=$(notdir $(repo_dir)) + +# Try to locate top-level makefile +top_level_makefile:=$(repo_dir)/../common/makefiles/Makefile +ifneq ($(wildcard $(top_level_makefile)),) + $(info Will run $(subsystem_name) target on top-level Makefile) + $(info WARNING: This is a non-recommended way of building!) + $(info ===================================================) +else + $(info Cannot locate top-level Makefile. Is this repo not checked out as part of a complete forest?) + $(error Build from top-level Makefile instead) +endif + +all: + @$(MAKE) -f $(top_level_makefile) $(subsystem_name) diff --git a/nashorn/samples/counters.js b/nashorn/samples/counters.js new file mode 100644 index 00000000000..226ec3dea33 --- /dev/null +++ b/nashorn/samples/counters.js @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +/** + * This file can be run along with any script you want to run + * to print aggregate stat counters from nashorn. + * + * Usage: jjs counters.js + */ + +Debug.dumpCounters(); diff --git a/nashorn/samples/letter.js b/nashorn/samples/letter.js new file mode 100644 index 00000000000..cbee92d0084 --- /dev/null +++ b/nashorn/samples/letter.js @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +/** + * Demonstrates "heredoc" feature with "scripting" mode. + * + * Usage: jjs -scripting letter.js -- + */ + +# This is shell-style line comment +var obj = { sender: $ARG[0], recipient: $ARG[1] }; + +// JavaScript style line comment is ok too. +print(<"); +} + +with (imports) { + var reader = new BufferedReader(new InputStreamReader(System["in"])); + var line = null; + prompt(); + while ((line = reader.readLine()) != null) { + if (line != "") { + var args = line.split(" "); + try { + if (args[0] == "eval") { + var code = line.substring("eval".length); + var res = eval(code); + if (res != undefined) { + print(res); + } + } else { + var argList = new ArrayList(); + for (i in args) { argList.add(args[i]); } + var procBuilder = new ProcessBuilder(argList); + procBuilder.redirectErrorStream(); + var proc = procBuilder.start(); + var out = new BufferedReader(new InputStreamReader(proc.getInputStream())); + var line = null; + while ((line = out.readLine()) != null) { + System.out.println(line); + } + proc.waitFor(); + } + } catch (e) { + print(e); + } + } + prompt(); + } +} diff --git a/nashorn/samples/test.js b/nashorn/samples/test.js new file mode 100644 index 00000000000..e2f8c934c92 --- /dev/null +++ b/nashorn/samples/test.js @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +print("Hello World"); diff --git a/nashorn/samples/uniq.js b/nashorn/samples/uniq.js new file mode 100644 index 00000000000..3da8480b108 --- /dev/null +++ b/nashorn/samples/uniq.js @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 Oracle nor the names of its + * 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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS 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. + */ + +/** + * Prints unique lines from a given file. + */ + +if (arguments.length != 1) { + print("Usage: jjs uniq.js -- "); + java.lang.System.exit(1); +} + +var imports = new JavaImporter(java.io); + +var uniqueLines = {}; +with (imports) { + var reader = new BufferedReader(new FileReader(arguments[0])); + while ((line = reader.readLine()) != null) { + // using a JS object as a map... + uniqueLines[line] = true; + } +} + +// now print the collected lines +for (i in uniqueLines) { + print(i); +} diff --git a/nashorn/src/META-INF/MANIFEST.MF b/nashorn/src/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..b61190e5ba9 --- /dev/null +++ b/nashorn/src/META-INF/MANIFEST.MF @@ -0,0 +1,5 @@ +Manifest-Version: 1.0 +Main-Class: jdk.nashorn.tools.Shell + +Name: jdk/nashorn/ +Implementation-Vendor: Oracle Corporation diff --git a/nashorn/src/META-INF/services/javax.script.ScriptEngineFactory b/nashorn/src/META-INF/services/javax.script.ScriptEngineFactory new file mode 100644 index 00000000000..60a8f56b8b5 --- /dev/null +++ b/nashorn/src/META-INF/services/javax.script.ScriptEngineFactory @@ -0,0 +1,25 @@ +# +# 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. +# +jdk.nashorn.api.scripting.NashornScriptEngineFactory diff --git a/nashorn/src/jdk/internal/dynalink/CallSiteDescriptor.java b/nashorn/src/jdk/internal/dynalink/CallSiteDescriptor.java new file mode 100644 index 00000000000..c2bf93be328 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/CallSiteDescriptor.java @@ -0,0 +1,174 @@ +/* + * 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 java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; + +/** + * An immutable descriptor of a call site. It is an immutable object that contains all the information about a call + * site: the class performing the lookups, the name of the method being invoked, and the method signature. The library + * has a default {@link CallSiteDescriptorFactory} for descriptors that you can use, or you can create your own + * descriptor classes, especially if you need to add further information (values passed in additional parameters to the + * bootstrap method) to them. Call site descriptors are used in this library in place of passing a real call site to + * guarding linkers so they aren't tempted to directly manipulate the call sites. The constructors of built-in + * {@link RelinkableCallSite} implementations all need a call site descriptor. Even if you create your own call site + * descriptors consider using {@link CallSiteDescriptorFactory#tokenizeName(String)} in your implementation. + * + * @author Attila Szegedi + */ +public interface CallSiteDescriptor { + /** + * The index of the name token that will carry the operation scheme prefix (usually, "dyn"). + */ + public static final int SCHEME = 0; + /** + * The index of the name token that will usually carry the operation name. + */ + + public static final int OPERATOR=1; + /** + * The index of the name token that will usually carry a name of an operand (of a property, method, etc.) + */ + + public static final int NAME_OPERAND=2; + + /** + * Character used to delimit tokens in an call site name. + */ + public static final String TOKEN_DELIMITER = ":"; + + /** + * Character used to delimit operation names in a composite operation specification. + */ + public static final String OPERATOR_DELIMITER = "|"; + + /** + * Returns the number of tokens in the name of the method at the call site. Method names are tokenized with the + * colon ":" character, i.e. "dyn:getProp:color" would be the name used to describe a method that retrieves the + * property named "color" on the object it is invoked on. + * @return the number of tokens in the name of the method at the call site. + */ + public int getNameTokenCount(); + + /** + * Returns the ith token in the method name at the call site. Method names are tokenized with the + * colon ":" character. + * @param i the index of the token. Must be between 0 (inclusive) and {@link #getNameTokenCount()} (exclusive) + * @throws IllegalArgumentException if the index is outside the allowed range. + * @return the ith token in the method name at the call site. The returned strings are interned. + */ + public String getNameToken(int i); + + /** + * Returns the name of the method at the call site. Note that the object internally only stores the tokenized name, + * and has to reconstruct the full name from tokens on each invocation. + * @return the name of the method at the call site. + */ + public String getName(); + + /** + * The type of the method at the call site. + * + * @return type of the method at the call site. + */ + public MethodType getMethodType(); + + /** + * Returns the lookup passed to the bootstrap method. + * @return the lookup passed to the bootstrap method. + */ + public Lookup getLookup(); + + /** + * Creates a new call site descriptor from this descriptor, which is identical to this, except it changes the method + * type. + * + * @param newMethodType the new method type + * @return a new call site descriptor, with the method type changed. + */ + public CallSiteDescriptor changeMethodType(MethodType newMethodType); + +} diff --git a/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java b/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java new file mode 100644 index 00000000000..c242fedfbb9 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java @@ -0,0 +1,211 @@ +/* + * 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 java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.concurrent.atomic.AtomicReference; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.support.AbstractRelinkableCallSite; + +/** + * A relinkable call site that maintains a chain of linked method handles. In the default implementation, up to 8 method + * handles can be chained, cascading from one to the other through + * {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)}. When this call site has to link a new + * method handle and the length of the chain is already at the maximum, it will throw away the oldest method handle. + * Switchpoint-invalidated handles in the chain are removed eagerly (on each linking request, and whenever a + * switchpoint-invalidated method handle is traversed during invocation). There is currently no profiling + * attached to the handles in the chain, so they are never reordered based on usage; the most recently linked method + * handle is always at the start of the chain. + */ +public class ChainedCallSite extends AbstractRelinkableCallSite { + private final AtomicReference> invocations = new AtomicReference<>(); + + /** + * Creates a new chained call site. + * @param descriptor the descriptor for the call site. + */ + public ChainedCallSite(CallSiteDescriptor descriptor) { + super(descriptor); + } + + /** + * The maximum number of method handles in the chain. Defaults to 8. You can override it in a subclass if you need + * to change the value. If your override returns a value less than 1, the code will break. + * @return the maximum number of method handles in the chain. + */ + @SuppressWarnings("static-method") + protected int getMaxChainLength() { + return 8; + } + + @Override + public void relink(GuardedInvocation guardedInvocation, MethodHandle fallback) { + relinkInternal(guardedInvocation, fallback, false); + } + + @Override + public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle fallback) { + relinkInternal(guardedInvocation, fallback, true); + } + + private MethodHandle relinkInternal(GuardedInvocation invocation, MethodHandle relink, boolean reset) { + final LinkedList currentInvocations = invocations.get(); + @SuppressWarnings({ "unchecked", "rawtypes" }) + final LinkedList newInvocations = + currentInvocations == null || reset ? new LinkedList<>() : (LinkedList)currentInvocations.clone(); + + // First, prune the chain of invalidated switchpoints. + for(Iterator it = newInvocations.iterator(); it.hasNext();) { + if(it.next().hasBeenInvalidated()) { + it.remove(); + } + } + + // prune() is allowed to invoke this method with invocation == null meaning we're just pruning the chain and not + // adding any new invocations to it. + if(invocation != null) { + // Remove oldest entry if we're at max length + if(newInvocations.size() == getMaxChainLength()) { + newInvocations.removeFirst(); + } + newInvocations.addLast(invocation); + } + + // 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); + + // Fold the new chain + MethodHandle target = relink; + for(GuardedInvocation inv: newInvocations) { + target = inv.compose(pruneAndInvoke, target); + } + + // If nobody else updated the call site while we were rebuilding the chain, set the target to our chain. In case + // we lost the race for multithreaded update, just do nothing. Either the other thread installed the same thing + // we wanted to install, or otherwise, we'll be asked to relink again. + if(invocations.compareAndSet(currentInvocations, newInvocations)) { + setTarget(target); + } + return target; + } + + /** + * 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) { + // Bind prune to (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 + return MethodHandles.foldArguments(MethodHandles.exactInvoker(type()), ignoreArgsPrune); + } + + @SuppressWarnings("unused") + private MethodHandle prune(MethodHandle relink) { + return relinkInternal(null, relink, false); + } + + private static final MethodHandle PRUNE; + static { + try { + PRUNE = MethodHandles.lookup().findSpecial(ChainedCallSite.class, "prune", MethodType.methodType( + MethodHandle.class, MethodHandle.class), ChainedCallSite.class); + // NOTE: using two catch blocks so we don't introduce a reference to 1.7 ReflectiveOperationException, allowing + // Dynalink to be used on 1.6 JVMs with Remi's backport library. + } catch(IllegalAccessException e) { + throw new AssertionError(e.getMessage(), e); // Can not happen + } catch(NoSuchMethodException e) { + throw new AssertionError(e.getMessage(), e); // Can not happen + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/DefaultBootstrapper.java b/nashorn/src/jdk/internal/dynalink/DefaultBootstrapper.java new file mode 100644 index 00000000000..c62afe60213 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/DefaultBootstrapper.java @@ -0,0 +1,143 @@ +/* + * 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 java.lang.invoke.CallSite; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; + +/** + * A convenience default bootstrapper that exposes static bootstrap methods which language runtimes that need the very + * default behavior can use with minimal setup. When first referenced, it will create a dynamic linker with default + * settings for the {@link DynamicLinkerFactory}, and its bootstrap methods will create {@link MonomorphicCallSite} for + * all call sites. It has two bootstrap methods: one creates call sites that use the + * {@link MethodHandles#publicLookup()} as the lookup for all call sites and disregard the one passed in as the caller, + * and one that just uses the passed caller as the lookup scope. Using the public lookup one is advised if your language + * runtime has no concept of interacting with Java visibility scopes, as it results in a more lightweight runtime + * information. + * + * @author Attila Szegedi + */ +public class DefaultBootstrapper { + private static final DynamicLinker dynamicLinker = new DynamicLinkerFactory().createLinker(); + + private DefaultBootstrapper() { + } + + /** + * Use this method as your bootstrap method (see the documentation of the java.lang.invoke package for how to do + * this). In case your language runtime doesn't have a concept of interaction with Java access scopes, you might + * want to consider using + * {@link #publicBootstrap(java.lang.invoke.MethodHandles.Lookup, String, MethodType)} instead. + * + * @param caller the caller's lookup + * @param name the name of the method at the call site + * @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) { + return bootstrapInternal(caller, name, type); + } + + /** + * Use this method as your bootstrap method (see the documentation of the java.lang.invoke package for how to do + * this) when your language runtime doesn't have a concept of interaction with Java access scopes. If you need to + * preserve the different caller Lookup objects in the call sites, use + * {@link #bootstrap(java.lang.invoke.MethodHandles.Lookup, String, MethodType)} instead + * + * @param caller the caller's lookup. It is ignored as the call sites will be created with + * {@link MethodHandles#publicLookup()} instead. + * @param name the name of the method at the call site + * @param type the method signature at the call site + * @return a new {@link MonomorphicCallSite} linked with the default dynamic linker. + */ + public static CallSite publicBootstrap(@SuppressWarnings("unused") MethodHandles.Lookup caller, String name, MethodType type) { + return bootstrapInternal(MethodHandles.publicLookup(), name, type); + } + + private static CallSite bootstrapInternal(MethodHandles.Lookup caller, String name, MethodType type) { + return dynamicLinker.link(new MonomorphicCallSite(CallSiteDescriptorFactory.create(caller, name, type))); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/DynamicLinker.java b/nashorn/src/jdk/internal/dynalink/DynamicLinker.java new file mode 100644 index 00000000000..c0930dae790 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/DynamicLinker.java @@ -0,0 +1,281 @@ +/* + * 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 java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.MutableCallSite; +import java.util.List; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; +import jdk.internal.dynalink.support.LinkRequestImpl; +import jdk.internal.dynalink.support.Lookup; +import jdk.internal.dynalink.support.RuntimeContextLinkRequestImpl; + +/** + * The linker for {@link RelinkableCallSite} objects. Users of it (scripting frameworks and language runtimes) have to + * create a linker using the {@link DynamicLinkerFactory} and invoke its link method from the invokedynamic bootstrap + * methods to set the target of all the call sites in the code they generate. Usual usage would be to create one class + * per language runtime to contain one linker instance as: + * + *
+ * class MyLanguageRuntime {
+ *     private static final GuardingDynamicLinker myLanguageLinker = new MyLanguageLinker();
+ *     private static final DynamicLinker dynamicLinker = createDynamicLinker();
+ *
+ *     private static DynamicLinker createDynamicLinker() {
+ *         final DynamicLinkerFactory factory = new DynamicLinkerFactory();
+ *         factory.setPrioritizedLinker(myLanguageLinker);
+ *         return factory.createLinker();
+ *     }
+ *
+ *     public static CallSite bootstrap(MethodHandles.Lookup caller, String name, MethodType type) {
+ *         return dynamicLinker.link(new MonomorphicCallSite(CallSiteDescriptorFactory.create(lookup, name, type)));
+ *     }
+ * }
+ * 
+ * + * Note how there are three components you will need to provide here: + *
    + *
  • You're expected to provide a {@link GuardingDynamicLinker} for your own language. If your runtime doesn't + * have its own language and/or object model (i.e. it's a generic scripting shell), you don't need to implement a + * dynamic linker; you would simply not invoke the {@code setPrioritizedLinker} method on the factory, or even better, + * simply use {@link DefaultBootstrapper}.
  • + *
  • The performance of the programs can depend on your choice of the class to represent call sites. The above + * example used {@link MonomorphicCallSite}, but you might want to use {@link ChainedCallSite} instead. You'll need to + * experiment and decide what fits your language runtime the best. You can subclass either of these or roll your own if + * you need to.
  • + *
  • You also need to provide {@link CallSiteDescriptor}s to your call sites. They are immutable objects that contain + * all the information about the call site: the class performing the lookups, the name of the method being invoked, and + * the method signature. The library has a default {@link CallSiteDescriptorFactory} for descriptors that you can use, + * or you can create your own descriptor classes, especially if you need to add further information (values passed in + * additional parameters to the bootstrap method) to them.
  • + *
+ * + * @author Attila Szegedi + */ +public class DynamicLinker { + + private static final String CLASS_NAME = DynamicLinker.class.getName(); + private static final String RELINK_METHOD_NAME = "relink"; + + private final LinkerServices linkerServices; + private final int runtimeContextArgCount; + private final boolean syncOnRelink; + private final int unstableRelinkThreshold; + + /** + * Creates a new dynamic linker. + * + * @param linkerServices the linkerServices used by the linker, created by the factory. + * @param runtimeContextArgCount see {@link DynamicLinkerFactory#setRuntimeContextArgCount(int)} + */ + DynamicLinker(LinkerServices linkerServices, int runtimeContextArgCount, boolean syncOnRelink, + 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.syncOnRelink = syncOnRelink; + this.unstableRelinkThreshold = unstableRelinkThreshold; + } + + /** + * Links an invokedynamic call site. It will install a method handle into the call site that invokes the relinking + * mechanism of this linker. Next time the call site is invoked, it will be linked for the actual arguments it was + * invoked with. + * + * @param callSite the call site to link. + * @return the callSite, for easy call chaining. + */ + public T link(final T callSite) { + callSite.initialize(createRelinkAndInvokeMethod(callSite, 0)); + return callSite; + } + + /** + * Returns the object representing the lower level linker services of this class that are normally exposed to + * individual language-specific linkers. While as a user of this class you normally only care about the + * {@link #link(RelinkableCallSite)} method, in certain circumstances you might want to use the lower level services + * directly; either to lookup specific method handles, to access the type converters, and so on. + * @return the object representing the linker services of this class. + */ + public LinkerServices getLinkerServices() { + return linkerServices; + } + + 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) { + // Make a bound MH of invoke() for this linker and call site + final MethodHandle boundRelinker = MethodHandles.insertArguments(RELINK, 0, this, callSite, Integer.valueOf( + relinkCount)); + // Make a MH that gathers all arguments to the invocation into an Object[] + final MethodType type = callSite.getDescriptor().getMethodType(); + final MethodHandle collectingRelinker = boundRelinker.asCollector(Object[].class, type.parameterCount()); + return MethodHandles.foldArguments(MethodHandles.exactInvoker(type), collectingRelinker.asType( + type.changeReturnType(MethodHandle.class))); + } + + /** + * Relinks a call site conforming to the invocation arguments. + * + * @param callSite the call site itself + * @param arguments arguments to the invocation + * @return return the method handle for the invocation + * @throws Exception rethrows any exception thrown by the linkers + */ + @SuppressWarnings("unused") + private MethodHandle relink(RelinkableCallSite callSite, int relinkCount, 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); + + // Find a suitable method handle with a guard + GuardedInvocation guardedInvocation = linkerServices.getGuardedInvocation(linkRequest); + + // None found - throw an exception + if(guardedInvocation == null) { + throw new NoSuchDynamicMethodException(callSiteDescriptor.toString()); + } + + // If our call sites have a runtime context, and the linker produced a context-stripped invocation, adapt the + // produced invocation into contextual invocation (by dropping the context...) + if(runtimeContextArgCount > 0) { + final MethodType origType = callSiteDescriptor.getMethodType(); + final MethodHandle invocation = guardedInvocation.getInvocation(); + if(invocation.type().parameterCount() == origType.parameterCount() - runtimeContextArgCount) { + final List> prefix = origType.parameterList().subList(1, runtimeContextArgCount + 1); + final MethodHandle guard = guardedInvocation.getGuard(); + guardedInvocation = guardedInvocation.dropArguments(1, prefix); + } + } + + 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 + // has already executed once for the unstable call site; we only want the call site to throw away its current + // linkage once, when it transitions to unstable. + if(unstableDetectionEnabled && newRelinkCount <= unstableRelinkThreshold && newRelinkCount++ == unstableRelinkThreshold) { + callSite.resetAndRelink(guardedInvocation, createRelinkAndInvokeMethod(callSite, newRelinkCount)); + } else { + callSite.relink(guardedInvocation, createRelinkAndInvokeMethod(callSite, newRelinkCount)); + } + if(syncOnRelink) { + MutableCallSite.syncAll(new MutableCallSite[] { (MutableCallSite)callSite }); + } + return guardedInvocation.getInvocation(); + } + + /** + * Returns a stack trace element describing the location of the call site currently being relinked on the current + * thread. The operation internally creates a Throwable object and inspects its stack trace, so it's potentially + * expensive. The recommended usage for it is in writing diagnostics code. + * @return a stack trace element describing the location of the call site currently being relinked, or null if it is + * not invoked while a call site is being relinked. + */ + public static StackTraceElement getRelinkedCallSiteLocation() { + final StackTraceElement[] trace = new Throwable().getStackTrace(); + for(int i = 0; i < trace.length - 1; ++i) { + final StackTraceElement frame = trace[i]; + if(RELINK_METHOD_NAME.equals(frame.getMethodName()) && CLASS_NAME.equals(frame.getClassName())) { + return trace[i + 1]; + } + } + return null; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java b/nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java new file mode 100644 index 00000000000..0f0a347be5a --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java @@ -0,0 +1,312 @@ +/* + * 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 java.lang.invoke.MutableCallSite; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import jdk.internal.dynalink.beans.BeansLinker; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.support.AutoDiscovery; +import jdk.internal.dynalink.support.BottomGuardingDynamicLinker; +import jdk.internal.dynalink.support.CompositeGuardingDynamicLinker; +import jdk.internal.dynalink.support.CompositeTypeBasedGuardingDynamicLinker; +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. + * + * @author Attila Szegedi + */ +public class DynamicLinkerFactory { + + /** + * Default value for {@link #setUnstableRelinkThreshold(int) unstable relink threshold}. + */ + public static final int DEFAULT_UNSTABLE_RELINK_THRESHOLD = 8; + + private ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + private List prioritizedLinkers; + private List fallbackLinkers; + private int runtimeContextArgCount = 0; + private boolean syncOnRelink = false; + private int unstableRelinkThreshold = DEFAULT_UNSTABLE_RELINK_THRESHOLD; + + /** + * Sets the class loader for automatic discovery of available linkers. If not set explicitly, then the thread + * context class loader at the time of the constructor invocation will be used. + * + * @param classLoader the class loader used for the autodiscovery of available linkers. + */ + public void setClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + /** + * Sets the prioritized linkers. Language runtimes using this framework will usually precreate at least the linker + * for their own language. These linkers will be consulted first in the resulting dynamic linker, before any + * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the prioritized + * linkers, it will be ignored and the explicit prioritized instance will be used. + * + * @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 prioritizedLinkers) { + this.prioritizedLinkers = + prioritizedLinkers == null ? null : new ArrayList<>(prioritizedLinkers); + } + + /** + * Sets the prioritized linkers. Language runtimes using this framework will usually precreate at least the linker + * for their own language. These linkers will be consulted first in the resulting dynamic linker, before any + * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the prioritized + * linkers, it will be ignored and the explicit prioritized instance will be used. + * + * @param prioritizedLinkers a list of prioritized linkers. + */ + public void setPrioritizedLinkers(GuardingDynamicLinker... prioritizedLinkers) { + setPrioritizedLinkers(Arrays.asList(prioritizedLinkers)); + } + + /** + * Sets a single prioritized linker. Identical to calling {@link #setPrioritizedLinkers(List)} with a single-element + * list. + * + * @param prioritizedLinker the single prioritized linker. Must not be null. + * @throws IllegalArgumentException if null is passed. + */ + public void setPrioritizedLinker(GuardingDynamicLinker prioritizedLinker) { + if(prioritizedLinker == null) { + throw new IllegalArgumentException("prioritizedLinker == null"); + } + this.prioritizedLinkers = Collections.singletonList(prioritizedLinker); + } + + /** + * Sets the fallback linkers. These linkers will be consulted last in the resulting composite linker, after any + * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the fallback + * linkers, it will be ignored and the explicit fallback instance will be used. + * + * @param fallbackLinkers the list of fallback linkers. Can be empty to indicate the caller wishes to set no + * fallback linkers. + */ + public void setFallbackLinkers(List fallbackLinkers) { + this.fallbackLinkers = fallbackLinkers == null ? null : new ArrayList<>(fallbackLinkers); + } + + /** + * Sets the fallback linkers. These linkers will be consulted last in the resulting composite linker, after any + * autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the fallback + * linkers, it will be ignored and the explicit fallback instance will be used. + * + * @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) { + setFallbackLinkers(Arrays.asList(fallbackLinkers)); + } + + /** + * Sets the number of arguments in the call sites that represent the stack context of the language runtime creating + * the linker. If the language runtime uses no context information passed on stack, then it should be zero + * (the default value). If it is set to nonzero value, then every dynamic call site emitted by this runtime must + * have the argument list of the form: {@code (this, contextArg1[, contextArg2[, ...]], normalArgs)}. It is + * advisable to only pass one context-specific argument, though, of an easily recognizable, runtime specific type + * encapsulating the runtime thread local state. + * + * @param runtimeContextArgCount the number of language runtime context arguments in call sites. + */ + public void setRuntimeContextArgCount(int runtimeContextArgCount) { + if(runtimeContextArgCount < 0) { + throw new IllegalArgumentException("runtimeContextArgCount < 0"); + } + this.runtimeContextArgCount = runtimeContextArgCount; + } + + /** + * Sets whether the linker created by this factory will invoke {@link MutableCallSite#syncAll(MutableCallSite[])} + * after a call site is relinked. Defaults to false. You probably want to set it to true if your runtime supports + * multithreaded execution of dynamically linked code. + * @param syncOnRelink true for invoking sync on relink, false otherwise. + */ + public void setSyncOnRelink(boolean syncOnRelink) { + this.syncOnRelink = syncOnRelink; + } + + /** + * Sets the unstable relink threshold; the number of times a call site is relinked after which it will be + * considered unstable, and subsequent link requests for it will indicate this. + * @param unstableRelinkThreshold the new threshold. Must not be less than zero. The value of zero means that + * call sites will never be considered unstable. + * @see LinkRequest#isCallSiteUnstable() + */ + public void setUnstableRelinkThreshold(int unstableRelinkThreshold) { + if(unstableRelinkThreshold < 0) { + throw new IllegalArgumentException("unstableRelinkThreshold < 0"); + } + this.unstableRelinkThreshold = unstableRelinkThreshold; + } + + /** + * Creates a new dynamic linker consisting of all the prioritized, autodiscovered, and fallback linkers. + * + * @return the new dynamic Linker + */ + public DynamicLinker createLinker() { + // Treat nulls appropriately + if(prioritizedLinkers == null) { + prioritizedLinkers = Collections.emptyList(); + } + if(fallbackLinkers == null) { + fallbackLinkers = Collections.singletonList(new BeansLinker()); + } + + // Gather classes of all precreated (prioritized and fallback) linkers. + // We'll filter out any discovered linkers of the same class. + final Set> knownLinkerClasses = + new HashSet<>(); + addClasses(knownLinkerClasses, prioritizedLinkers); + addClasses(knownLinkerClasses, fallbackLinkers); + + final List discovered = AutoDiscovery.loadLinkers(classLoader); + // Now, concatenate ... + final List linkers = + new ArrayList<>(prioritizedLinkers.size() + discovered.size() + + fallbackLinkers.size()); + // ... prioritized linkers, ... + linkers.addAll(prioritizedLinkers); + // ... filtered discovered linkers, ... + for(GuardingDynamicLinker linker: discovered) { + if(!knownLinkerClasses.contains(linker.getClass())) { + linkers.add(linker); + } + } + // ... and finally fallback linkers. + linkers.addAll(fallbackLinkers); + final List optimized = CompositeTypeBasedGuardingDynamicLinker.optimize(linkers); + final GuardingDynamicLinker composite; + switch(linkers.size()) { + case 0: { + composite = BottomGuardingDynamicLinker.INSTANCE; + break; + } + case 1: { + composite = optimized.get(0); + break; + } + default: { + composite = new CompositeGuardingDynamicLinker(optimized); + break; + } + } + + final List typeConverters = new LinkedList<>(); + for(GuardingDynamicLinker linker: linkers) { + if(linker instanceof GuardingTypeConverterFactory) { + typeConverters.add((GuardingTypeConverterFactory)linker); + } + } + + return new DynamicLinker(new LinkerServicesImpl(new TypeConverterFactory(typeConverters), composite), + runtimeContextArgCount, syncOnRelink, unstableRelinkThreshold); + } + + private static void addClasses(Set> knownLinkerClasses, + List linkers) { + for(GuardingDynamicLinker linker: linkers) { + knownLinkerClasses.add(linker.getClass()); + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/MonomorphicCallSite.java b/nashorn/src/jdk/internal/dynalink/MonomorphicCallSite.java new file mode 100644 index 00000000000..7f1bbedebaf --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/MonomorphicCallSite.java @@ -0,0 +1,115 @@ +/* + * 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 java.lang.invoke.MethodHandle; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.support.AbstractRelinkableCallSite; + +/** + * A relinkable call site that implements monomorphic inline caching strategy. After it linked a method, it will keep it + * until either its guard evaluates to false, or its switchpoint is invalidated, at which time it will throw away the + * previous linkage, and trigger relinking with its associated {@link DynamicLinker}. + * + * @author Attila Szegedi + */ +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) { + super(descriptor); + } + + @Override + public void relink(GuardedInvocation guardedInvocation, MethodHandle relink) { + setTarget(guardedInvocation.compose(relink)); + } + + @Override + public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle relink) { + relink(guardedInvocation, relink); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/NoSuchDynamicMethodException.java b/nashorn/src/jdk/internal/dynalink/NoSuchDynamicMethodException.java new file mode 100644 index 00000000000..8a73af922ea --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/NoSuchDynamicMethodException.java @@ -0,0 +1,103 @@ +/* + * 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.GuardingDynamicLinker; + +/** + * Thrown at the invocation if the call site can not be linked by any available {@link GuardingDynamicLinker}. + * + * @author Attila Szegedi + */ +public class NoSuchDynamicMethodException extends RuntimeException { + private static final long serialVersionUID = 1L; + + /** + * Creates a new NoSuchDynamicMethodException + * @param message the message of the exception. + */ + public NoSuchDynamicMethodException(String message) { + super(message); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/RelinkableCallSite.java b/nashorn/src/jdk/internal/dynalink/RelinkableCallSite.java new file mode 100644 index 00000000000..4b680459229 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/RelinkableCallSite.java @@ -0,0 +1,147 @@ +/* + * 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 java.lang.invoke.CallSite; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MutableCallSite; +import java.lang.invoke.VolatileCallSite; +import jdk.internal.dynalink.linker.GuardedInvocation; + +/** + * Interface for relinkable call sites. Language runtimes wishing to use this framework must use subclasses of + * {@link CallSite} that also implement this interface as their call sites. There is a readily usable + * {@link MonomorphicCallSite} subclass that implements monomorphic inline caching strategy as well as a + * {@link ChainedCallSite} that retains a chain of already linked method handles. The reason this is defined as an + * interface instead of a concrete, albeit abstract class is that it allows independent implementations to choose + * between {@link MutableCallSite} and {@link VolatileCallSite} as they see fit. + * + * @author Attila Szegedi + */ +public interface RelinkableCallSite { + /** + * Initializes the relinkable call site by setting a relink-and-invoke method handle. The call site implementation + * is supposed to set this method handle as its target. + * @param relinkAndInvoke a relink-and-invoke method handle supplied by the {@link DynamicLinker}. + */ + public void initialize(MethodHandle relinkAndInvoke); + + /** + * Returns the descriptor for this call site. + * + * @return the descriptor for this call site. + */ + public CallSiteDescriptor getDescriptor(); + + /** + * This method will be called by the dynamic linker every time the call site is normally relinked. It will be passed + * a {@code GuardedInvocation} that the call site should incorporate into its target method handle. When this method + * is called, the call site is allowed to keep other non-invalidated invocations around for implementation of + * polymorphic inline caches and compose them with this invocation to form its final target. + * + * @param guardedInvocation the guarded invocation that the call site should incorporate into its target method + * handle. + * @param fallback the fallback method. This is a method matching the method type of the call site that is supplied + * by the {@link DynamicLinker} to be used by this call site as a fallback when it can't invoke its target with the + * passed arguments. The fallback method is such that when it's invoked, it'll try to discover the adequate target + * for the invocation, subsequently invoke {@link #relink(GuardedInvocation, MethodHandle)} or + * {@link #resetAndRelink(GuardedInvocation, MethodHandle)}, and finally invoke the target. + */ + public void relink(GuardedInvocation guardedInvocation, MethodHandle fallback); + + /** + * This method will be called by the dynamic linker every time the call site is relinked and the linker wishes the + * call site to throw away any prior linkage state. It will be passed a {@code GuardedInvocation} that the call site + * should use to build its target method handle. When this method is called, the call site is discouraged from + * keeping previous state around, and is supposed to only link the current invocation. + * + * @param guardedInvocation the guarded invocation that the call site should use to build its target method handle. + * @param fallback the fallback method. This is a method matching the method type of the call site that is supplied + * by the {@link DynamicLinker} to be used by this call site as a fallback when it can't invoke its target with the + * passed arguments. The fallback method is such that when it's invoked, it'll try to discover the adequate target + * for the invocation, subsequently invoke {@link #relink(GuardedInvocation, MethodHandle)} or + * {@link #resetAndRelink(GuardedInvocation, MethodHandle)}, and finally invoke the target. + */ + public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle fallback); +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java b/nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java new file mode 100644 index 00000000000..702c1509fd4 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java @@ -0,0 +1,701 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +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; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.support.CallSiteDescriptorFactory; +import jdk.internal.dynalink.support.Guards; +import jdk.internal.dynalink.support.Lookup; + +/** + * A base class for both {@link StaticClassLinker} and {@link BeanLinker}. Deals with common aspects of property + * exposure and method calls for both static and instance facets of a class. + * + * @author Attila Szegedi + */ +abstract class AbstractJavaLinker implements GuardingDynamicLinker { + final Class clazz; + private final MethodHandle classGuard; + private final MethodHandle assignableGuard; + private final Map propertyGetters = new HashMap<>(); + private final Map propertySetters = new HashMap<>(); + private final Map methods = new HashMap<>(); + + AbstractJavaLinker(Class clazz, MethodHandle classGuard) { + this(clazz, classGuard, classGuard); + } + + AbstractJavaLinker(Class clazz, MethodHandle classGuard, MethodHandle assignableGuard) { + this.clazz = clazz; + this.classGuard = classGuard; + this.assignableGuard = assignableGuard; + + final FacetIntrospector introspector = createFacetIntrospector(); + // Add methods and properties + for(Method method: introspector.getMethods()) { + final String name = method.getName(); + final MethodHandle methodHandle = introspector.unreflect(method); + // Add method + addMember(name, methodHandle, methods); + // Add the method as a property getter and/or setter + if(name.startsWith("get") && name.length() > 3 && method.getParameterTypes().length == 0) { + // Property getter + setPropertyGetter(decapitalize(name.substring(3)), introspector.unreflect( + getMostGenericGetter(method)), ValidationType.INSTANCE_OF); + } else if(name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0 && + method.getReturnType() == boolean.class) { + // Boolean property getter + setPropertyGetter(decapitalize(name.substring(2)), introspector.unreflect( + getMostGenericGetter(method)), ValidationType.INSTANCE_OF); + } else if(name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1) { + // Property setter + addMember(decapitalize(name.substring(3)), methodHandle, propertySetters); + } + } + + // Add field getter/setters as property getters/setters. + for(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)) { + setPropertyGetter(name, introspector.unreflectGetter(field), ValidationType.EXACT_CLASS); + } + if(!(Modifier.isFinal(field.getModifiers()) || propertySetters.containsKey(name))) { + addMember(name, introspector.unreflectSetter(field), propertySetters); + } + } + + // Add inner classes, but only those for which we don't hide a property with it + for(Map.Entry innerClassSpec: introspector.getInnerClassGetters().entrySet()) { + final String name = innerClassSpec.getKey(); + if(!propertyGetters.containsKey(name)) { + setPropertyGetter(name, innerClassSpec.getValue(), ValidationType.EXACT_CLASS); + } + } + } + + private static String decapitalize(String str) { + assert str != null; + if(str.isEmpty()) { + return str; + } + + final char c0 = str.charAt(0); + if(Character.isLowerCase(c0)) { + return str; + } + + // If it has two consecutive upper-case characters, i.e. "URL", don't decapitalize + if(str.length() > 1 && Character.isUpperCase(str.charAt(1))) { + return str; + } + + final char c[] = str.toCharArray(); + c[0] = Character.toLowerCase(c0); + return new String(c); + } + + abstract FacetIntrospector createFacetIntrospector(); + + void setPropertyGetter(String name, MethodHandle handle, ValidationType validationType) { + propertyGetters.put(name, new AnnotatedMethodHandle(handle, validationType)); + } + + private void addMember(String name, MethodHandle mh, Map methodMap) { + final DynamicMethod existingMethod = methodMap.get(name); + final DynamicMethod newMethod = addMember(mh, existingMethod, clazz, name); + if(newMethod != existingMethod) { + methodMap.put(name, newMethod); + } + } + + static DynamicMethod createDynamicMethod(Iterable methodHandles, Class clazz, String name) { + DynamicMethod dynMethod = null; + for(MethodHandle methodHandle: methodHandles) { + dynMethod = addMember(methodHandle, dynMethod, clazz, name); + } + return dynMethod; + } + + private static DynamicMethod addMember(MethodHandle mh, DynamicMethod existing, Class clazz, String name) { + if(existing == null) { + return new SimpleDynamicMethod(mh, clazz, name); + } else if(existing.contains(mh)) { + return existing; + } else if(existing instanceof SimpleDynamicMethod) { + final OverloadedDynamicMethod odm = new OverloadedDynamicMethod(clazz, name); + odm.addMethod(((SimpleDynamicMethod)existing)); + odm.addMethod(mh); + return odm; + } else if(existing instanceof OverloadedDynamicMethod) { + ((OverloadedDynamicMethod)existing).addMethod(mh); + return existing; + } + throw new AssertionError(); + } + + @Override + public GuardedInvocation getGuardedInvocation(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". + final CallSiteDescriptor callSiteDescriptor = ncrequest.getCallSiteDescriptor(); + final String op = callSiteDescriptor.getNameToken(CallSiteDescriptor.OPERATOR); + // Either dyn:callMethod:name(this[,args]) or dyn:callMethod(this,name[,args]). + if("callMethod" == op) { + return getCallPropWithThis(callSiteDescriptor, linkerServices); + } + List operations = CallSiteDescriptorFactory.tokenizeOperators(callSiteDescriptor); + while(!operations.isEmpty()) { + final GuardedInvocationComponent gic = getGuardedInvocationComponent(callSiteDescriptor, linkerServices, + operations); + if(gic != null) { + return gic.getGuardedInvocation(); + } + operations = pop(operations); + } + return null; + } + + protected GuardedInvocationComponent getGuardedInvocationComponent(CallSiteDescriptor callSiteDescriptor, + LinkerServices linkerServices, List operations) throws Exception { + if(operations.isEmpty()) { + return null; + } + final String op = operations.get(0); + // Either dyn:getProp:name(this) or dyn:getProp(this, name) + if("getProp".equals(op)) { + return getPropertyGetter(callSiteDescriptor, linkerServices, pop(operations)); + } + // Either dyn:setProp:name(this, value) or dyn:setProp(this, name, value) + if("setProp".equals(op)) { + return getPropertySetter(callSiteDescriptor, linkerServices, pop(operations)); + } + // Either dyn:getMethod:name(this), or dyn:getMethod(this, name) + if("getMethod".equals(op)) { + return getMethodGetter(callSiteDescriptor, linkerServices, pop(operations)); + } + return null; + } + + static final List pop(List l) { + return l.subList(1, l.size()); + } + + MethodHandle getClassGuard(CallSiteDescriptor desc) { + return getClassGuard(desc.getMethodType()); + } + + MethodHandle getClassGuard(MethodType type) { + return Guards.asType(classGuard, type); + } + + GuardedInvocationComponent getClassGuardedInvocationComponent(MethodHandle invocation, MethodType type) { + return new GuardedInvocationComponent(invocation, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); + } + + private MethodHandle getAssignableGuard(MethodType type) { + return Guards.asType(assignableGuard, type); + } + + private GuardedInvocation getCallPropWithThis(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) { + switch(callSiteDescriptor.getNameTokenCount()) { + case 3: { + return createGuardedDynamicMethodInvocation(callSiteDescriptor.getMethodType(), linkerServices, + callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), methods); + } + default: { + return null; + } + } + } + + private GuardedInvocation createGuardedDynamicMethodInvocation(MethodType callSiteType, + LinkerServices linkerServices, String methodName, Map methodMap){ + final MethodHandle inv = getDynamicMethodInvocation(callSiteType, linkerServices, methodName, methodMap); + return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteType)); + } + + private static MethodHandle getDynamicMethodInvocation(MethodType callSiteType, LinkerServices linkerServices, + String methodName, Map methodMap) { + final DynamicMethod dynaMethod = getDynamicMethod(methodName, methodMap); + return dynaMethod != null ? dynaMethod.getInvocation(callSiteType, linkerServices) : null; + } + + private static DynamicMethod getDynamicMethod(String methodName, Map methodMap) { + final DynamicMethod dynaMethod = methodMap.get(methodName); + return dynaMethod != null ? dynaMethod : getExplicitSignatureDynamicMethod(methodName, methodMap); + } + + private static SimpleDynamicMethod getExplicitSignatureDynamicMethod(String methodName, + Map 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 + // conversions with a radically dynamic language, most overloaded methods will end up being constantly selected + // at invocation time, so a programmer knowledgable of the situation might choose to pin down an exact overload + // for performance reasons. + + // Is the method name lexically of the form "name(types)"? + final int lastChar = methodName.length() - 1; + if(methodName.charAt(lastChar) != ')') { + return null; + } + final int openBrace = methodName.indexOf('('); + if(openBrace == -1) { + return null; + } + + // Find an existing method for the "name" part + final DynamicMethod simpleNamedMethod = methodsMap.get(methodName.substring(0, openBrace)); + if(simpleNamedMethod == null) { + return null; + } + + // Try to get a narrowed dynamic method for the explicit parameter types. + return simpleNamedMethod.getMethodForExactParamTypes(methodName.substring(openBrace + 1, lastChar)); + } + + private static final MethodHandle IS_METHOD_HANDLE_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType( + boolean.class, MethodHandle.class)); + 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 operations) throws Exception { + final MethodType type = callSiteDescriptor.getMethodType(); + switch(callSiteDescriptor.getNameTokenCount()) { + case 2: { + // Must have three arguments: target object, property name, and property value. + assertParameterCount(callSiteDescriptor, 3); + + // What's below is basically: + // foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation), + // get_setter_handle(type, linkerServices)) + // only with a bunch of method signature adjustments. Basically, retrieve method setter + // MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next + // 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)" + 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) + final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0, setterType, + linkerServices); + + // Cast getter to MethodHandle(O, N, V) + final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType( + MethodHandle.class)); + + // Handle to invoke the setter R(MethodHandle, O, V) + final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType); + // Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V) + final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType( + 1)); + final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, + linkerServices, operations); + + final MethodHandle fallbackFolded; + if(nextComponent == null) { + // Object(MethodHandle)->R(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 + // extra argument resulting from fold + fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(), + 0, MethodHandle.class); + } + + // fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V)) + final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( + IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); + if(nextComponent == null) { + return getClassGuardedInvocationComponent(compositeSetter, type); + } + return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); + } + case 3: { + // Must have two arguments: target object and property value + assertParameterCount(callSiteDescriptor, 2); + final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor.getMethodType(), + linkerServices, callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), + propertySetters); + // If we have a property setter with this name, this composite operation will always stop here + if(gi != null) { + return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS); + } + // If we don't have a property setter with this name, always fall back to the next operation in the + // composite (if any) + return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations); + } + default: { + // More than two name components; don't know what to do with it. + return null; + } + } + } + + private static final Lookup privateLookup = new Lookup(MethodHandles.lookup()); + + private static final MethodHandle IS_ANNOTATED_HANDLE_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType( + boolean.class, AnnotatedMethodHandle.class)); + private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_HANDLE = MethodHandles.dropArguments( + MethodHandles.constant(Object.class, null), 0, AnnotatedMethodHandle.class); + private static final MethodHandle GET_ANNOTATED_HANDLE = privateLookup.findGetter(AnnotatedMethodHandle.class, + "handle", MethodHandle.class); + private static final MethodHandle GENERIC_PROPERTY_GETTER_HANDLER_INVOKER = MethodHandles.filterArguments( + MethodHandles.invoker(MethodType.methodType(Object.class, Object.class)), 0, GET_ANNOTATED_HANDLE); + + private GuardedInvocationComponent getPropertyGetter(CallSiteDescriptor callSiteDescriptor, + LinkerServices linkerServices, List ops) throws Exception { + final MethodType type = callSiteDescriptor.getMethodType(); + switch(callSiteDescriptor.getNameTokenCount()) { + case 2: { + // Must have exactly two arguments: receiver and name + assertParameterCount(callSiteDescriptor, 2); + + // What's below is basically: + // foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle) + // only with a bunch of method signature adjustments. Basically, retrieve method getter + // AnnotatedMethodHandle; if it is non-null, invoke its "handle" field, otherwise either return null, + // or delegate to next component's invocation. + + final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType( + AnnotatedMethodHandle.class)); + // Object(AnnotatedMethodHandle, Object)->R(AnnotatedMethodHandle, T0) + final MethodHandle invokeHandleTyped = linkerServices.asType(GENERIC_PROPERTY_GETTER_HANDLER_INVOKER, + MethodType.methodType(type.returnType(), AnnotatedMethodHandle.class, type.parameterType(0))); + // Since it's in the target of a fold, drop the unnecessary second argument + // R(AnnotatedMethodHandle, T0)->R(AnnotatedMethodHandle, T0, T1) + final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2, + type.parameterType(1)); + final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, + linkerServices, ops); + + final MethodHandle fallbackFolded; + if(nextComponent == null) { + // Object(AnnotatedMethodHandle)->R(AnnotatedMethodHandle, T0, T1); returns constant null + fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_HANDLE, 1, + type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedMethodHandle.class)); + } else { + // R(T0, T1)->R(AnnotatedMethodHAndle, T0, T1); adapts the next component's invocation to drop the + // extra argument resulting from fold + fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(), + 0, AnnotatedMethodHandle.class); + } + + // fold(R(AnnotatedMethodHandle, T0, T1), AnnotatedMethodHandle(T0, T1)) + final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( + IS_ANNOTATED_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); + if(nextComponent == null) { + return getClassGuardedInvocationComponent(compositeGetter, type); + } + return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); + } + case 3: { + // Must have exactly one argument: receiver + assertParameterCount(callSiteDescriptor, 1); + // Fixed name + final AnnotatedMethodHandle annGetter = propertyGetters.get(callSiteDescriptor.getNameToken( + CallSiteDescriptor.NAME_OPERAND)); + if(annGetter == null) { + // We have no such property, always delegate to the next component operation + return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops); + } + final MethodHandle getter = annGetter.handle; + // NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being + // overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the + // method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If + // we're linking against a field getter, don't make the assumption. + // NOTE: No delegation to the next component operation if we have a property with this name, even if its + // value is null. + final ValidationType validationType = annGetter.validationType; + return new GuardedInvocationComponent(linkerServices.asType(getter, type), getGuard(validationType, + type), clazz, validationType); + } + default: { + // Can't do anything with more than 3 name components + return null; + } + } + } + + private MethodHandle getGuard(ValidationType validationType, MethodType methodType) { + switch(validationType) { + case EXACT_CLASS: { + return getClassGuard(methodType); + } + case INSTANCE_OF: { + return getAssignableGuard(methodType); + } + case IS_ARRAY: { + return Guards.isArray(0, methodType); + } + case NONE: { + return null; + } + default: { + throw new AssertionError(); + } + } + } + + 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 GuardedInvocationComponent getMethodGetter(CallSiteDescriptor callSiteDescriptor, + LinkerServices linkerServices, List ops) throws Exception { + final MethodType type = callSiteDescriptor.getMethodType(); + 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. + return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type); + } + + // What's below is basically: + // foldArguments(guardWithTest(isNotNull, identity, nextComponent.invocation), getter) only with a + // 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)); + // 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)); + final MethodHandle nextComponentInvocation = nextComponent.getGuardedInvocation().getInvocation(); + // The assumption is that getGuardedInvocationComponent() already asType()'d it correctly + assert nextComponentInvocation.type().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); + // 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); + + return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); + } + case 3: { + // Must have exactly one argument: receiver + assertParameterCount(callSiteDescriptor, 1); + final DynamicMethod method = getDynamicMethod(callSiteDescriptor.getNameToken( + CallSiteDescriptor.NAME_OPERAND)); + if(method == null) { + // We have no such method, always delegate to the next component + return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops); + } + // 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); + } + default: { + // Can't do anything with more than 3 name components + return null; + } + } + } + + private static void assertParameterCount(CallSiteDescriptor descriptor, int paramCount) { + if(descriptor.getMethodType().parameterCount() != paramCount) { + throw new BootstrapMethodError(descriptor.getName() + " must have exactly " + paramCount + " parameters."); + } + } + + private static MethodHandle GET_PROPERTY_GETTER_HANDLE = MethodHandles.dropArguments(privateLookup.findOwnSpecial( + "getPropertyGetterHandle", Object.class, Object.class), 1, Object.class); + private final MethodHandle getPropertyGetterHandle = GET_PROPERTY_GETTER_HANDLE.bindTo(this); + + /** + * @param id the property ID + * @return the method handle for retrieving the property, or null if the property does not exist + */ + @SuppressWarnings("unused") + private Object getPropertyGetterHandle(Object id) { + return propertyGetters.get(id); + } + + // Type is MethodHandle(BeanLinker, MethodType, LinkerServices, Object, String, Object), of which the two "Object" + // args are dropped; this makes handles with first three args conform to "Object, String, Object" though, which is + // a typical property setter with variable name signature (target, name, value). + private static final MethodHandle GET_PROPERTY_SETTER_HANDLE = MethodHandles.dropArguments(MethodHandles.dropArguments( + privateLookup.findOwnSpecial("getPropertySetterHandle", MethodHandle.class, MethodType.class, + LinkerServices.class, Object.class), 3, Object.class), 5, Object.class); + // Type is MethodHandle(MethodType, LinkerServices, Object, String, Object) + private final MethodHandle getPropertySetterHandle = GET_PROPERTY_SETTER_HANDLE.bindTo(this); + + @SuppressWarnings("unused") + private MethodHandle getPropertySetterHandle(MethodType setterType, LinkerServices linkerServices, Object id) { + return getDynamicMethodInvocation(setterType, linkerServices, String.valueOf(id), propertySetters); + } + + private static MethodHandle GET_DYNAMIC_METHOD = MethodHandles.dropArguments(privateLookup.findOwnSpecial( + "getDynamicMethod", DynamicMethod.class, Object.class), 1, Object.class); + private final MethodHandle getDynamicMethod = GET_DYNAMIC_METHOD.bindTo(this); + + @SuppressWarnings("unused") + private DynamicMethod getDynamicMethod(Object name) { + return getDynamicMethod(String.valueOf(name), methods); + } + + /** + * Returns a dynamic method of the specified name. + * + * @param name name of the method + * @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) { + return getDynamicMethod(name, methods); + } + + /** + * Find the most generic superclass that declares this getter. Since getters have zero args (aside from the + * receiver), they can't be overloaded, so we're free to link with an instanceof guard for the most generic one, + * creating more stable call sites. + * @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) { + return getMostGenericGetter(getter.getName(), getter.getReturnType(), getter.getDeclaringClass()); + } + + private static Method getMostGenericGetter(String name, Class returnType, Class declaringClass) { + if(declaringClass == null) { + return null; + } + // Prefer interfaces + for(Class itf: declaringClass.getInterfaces()) { + final Method itfGetter = getMostGenericGetter(name, returnType, itf); + if(itfGetter != null) { + return itfGetter; + } + } + final Method superGetter = getMostGenericGetter(name, returnType, declaringClass.getSuperclass()); + if(superGetter != null) { + return superGetter; + } + if(!CheckRestrictedPackage.isRestrictedClass(declaringClass)) { + try { + return declaringClass.getMethod(name); + } catch(NoSuchMethodException e) { + // Intentionally ignored, meant to fall through + } + } + return null; + } + + private static final class AnnotatedMethodHandle { + final MethodHandle handle; + /*private*/ final ValidationType validationType; + + AnnotatedMethodHandle(MethodHandle handle, ValidationType validationType) { + this.handle = handle; + this.validationType = validationType; + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/AccessibleMembersLookup.java b/nashorn/src/jdk/internal/dynalink/beans/AccessibleMembersLookup.java new file mode 100644 index 00000000000..c82e334acde --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/AccessibleMembersLookup.java @@ -0,0 +1,262 @@ +/* + * 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.beans; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +/** + * Utility class for discovering accessible methods and inner classes. Normally, a public member declared on a class is + * accessible (that is, it can be invoked from anywhere). However, this is not the case if the class itself is not + * public, or belongs to a restricted-access package. In that case, it is required to lookup a member in a publicly + * accessible superclass or implemented interface of the class, and use it instead of the member discovered on the + * class. + * + * @author Attila Szegedi + */ +class AccessibleMembersLookup { + private final Map methods; + private final Set> innerClasses; + private boolean instance; + + /** + * Creates a mapping for all accessible methods and inner classes on a class. + * + * @param clazz the inspected class + * @param instance true to inspect instance methods, false to inspect static methods. + */ + AccessibleMembersLookup(final Class clazz, boolean instance) { + this.methods = new HashMap<>(); + this.innerClasses = new LinkedHashSet<>(); + this.instance = instance; + lookupAccessibleMembers(clazz); + } + + /** + * Returns an accessible method equivalent of a method. + * + * @param m the method whose accessible equivalent is requested. + * @return the accessible equivalent for the method (can be the same as the passed in method), or null if there is + * no accessible method equivalent. + */ + Method getAccessibleMethod(final Method m) { + return m == null ? null : methods.get(new MethodSignature(m)); + } + + Collection getMethods() { + return methods.values(); + } + + Class[] getInnerClasses() { + return innerClasses.toArray(new Class[innerClasses.size()]); + } + + /** + * A helper class that represents a method signature - name and argument types. + * + * @author Attila Szegedi + */ + static final class MethodSignature { + private final String name; + private final Class[] args; + + /** + * Creates a new method signature from arbitrary data. + * + * @param name the name of the method this signature represents. + * @param args the argument types of the method. + */ + MethodSignature(String name, Class[] args) { + this.name = name; + this.args = args; + } + + /** + * Creates a signature for the given method. + * + * @param method the method for which a signature is created. + */ + MethodSignature(final Method method) { + this(method.getName(), method.getParameterTypes()); + } + + /** + * Compares this object to another object + * + * @param o the other object + * @return true if the other object is also a method signature with the same name, same number of arguments, and + * same types of arguments. + */ + @Override + public boolean equals(final Object o) { + if(o instanceof MethodSignature) { + final MethodSignature ms = (MethodSignature)o; + return ms.name.equals(name) && Arrays.equals(args, ms.args); + } + return false; + } + + /** + * Returns a hash code, consistent with the overridden {@link #equals(Object)}. + */ + @Override + public int hashCode() { + return name.hashCode() ^ Arrays.hashCode(args); + } + + @Override + public String toString() { + final StringBuilder b = new StringBuilder(); + b.append("[MethodSignature ").append(name).append('('); + if(args.length > 0) { + b.append(args[0].getCanonicalName()); + for(int i = 1; i < args.length; ++i) { + b.append(", ").append(args[i].getCanonicalName()); + } + } + return b.append(")]").toString(); + } + } + + private void lookupAccessibleMembers(final Class clazz) { + boolean searchSuperTypes; + + if(!CheckRestrictedPackage.isRestrictedClass(clazz)) { + searchSuperTypes = false; + for(Method method: clazz.getMethods()) { + if(instance != Modifier.isStatic(method.getModifiers())) { + final MethodSignature sig = new MethodSignature(method); + if(!methods.containsKey(sig)) { + final Class declaringClass = method.getDeclaringClass(); + if(declaringClass != clazz && CheckRestrictedPackage.isRestrictedClass(declaringClass)) { + //Sometimes, the declaring class of a method (Method.getDeclaringClass()) + //retrieved through Class.getMethods() for a public class will be a + //non-public superclass. For such a method, we need to find a method with + //the same name and signature in a public superclass or implemented + //interface. + //This typically doesn't happen with classes emitted by a reasonably modern + //javac, as it'll create synthetic delegator methods in all public + //immediate subclasses of the non-public class. We have, however, observed + //this in the wild with class files compiled with older javac that doesn't + //generate the said synthetic delegators. + searchSuperTypes = true; + } else { + methods.put(sig, method); + } + } + } + } + for(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 + // were not yet loaded, they'll only get loaded in a non-resolved state; no static initializers for + // them will trigger just by doing this. + innerClasses.add(innerClass); + } + } else { + searchSuperTypes = true; + } + + if(searchSuperTypes) { + // If we reach here, the class is either not public, or it is in a restricted package. Alternatively, it is + // public, but some of its methods claim that their declaring class is non-public. We'll try superclasses + // and implemented interfaces then looking for public ones. + final Class[] interfaces = clazz.getInterfaces(); + for(int i = 0; i < interfaces.length; i++) { + lookupAccessibleMembers(interfaces[i]); + } + final Class superclass = clazz.getSuperclass(); + if(superclass != null) { + lookupAccessibleMembers(superclass); + } + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java b/nashorn/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java new file mode 100644 index 00000000000..a232caf137a --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java @@ -0,0 +1,220 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.LinkedList; +import java.util.List; +import jdk.internal.dynalink.support.TypeUtilities; + +/** + * Represents overloaded methods applicable to a specific call site signature. + * + * @author Attila Szegedi + */ +class ApplicableOverloadedMethods { + private final List methods; + private final boolean varArgs; + + /** + * Creates a new ApplicableOverloadedMethods instance + * + * @param methods a list of all overloaded methods with the same name for a class. + * @param callSiteType the type of the call site + * @param test applicability test. One of {@link #APPLICABLE_BY_SUBTYPING}, + * {@link #APPLICABLE_BY_METHOD_INVOCATION_CONVERSION}, or {@link #APPLICABLE_BY_VARIABLE_ARITY}. + */ + ApplicableOverloadedMethods(final List methods, final MethodType callSiteType, + final ApplicabilityTest test) { + this.methods = new LinkedList<>(); + for(MethodHandle m: methods) { + if(test.isApplicable(callSiteType, m)) { + this.methods.add(m); + } + } + varArgs = test == APPLICABLE_BY_VARIABLE_ARITY; + } + + /** + * Retrieves all the methods this object holds. + * + * @return list of all methods. + */ + List getMethods() { + return methods; + } + + /** + * Returns a list of all methods in this objects that are maximally specific. + * + * @return a list of maximally specific methods. + */ + List findMaximallySpecificMethods() { + return MaximallySpecific.getMaximallySpecificMethods(methods, varArgs); + } + + abstract static class ApplicabilityTest { + abstract boolean isApplicable(MethodType callSiteType, MethodHandle method); + } + + /** + * Implements the applicability-by-subtyping test from JLS 15.12.2.2. + */ + static final ApplicabilityTest APPLICABLE_BY_SUBTYPING = new ApplicabilityTest() { + @Override + boolean isApplicable(MethodType callSiteType, MethodHandle method) { + final MethodType methodType = method.type(); + final int methodArity = methodType.parameterCount(); + if(methodArity != callSiteType.parameterCount()) { + return false; + } + // 0th arg is receiver; it doesn't matter for overload + // resolution. + for(int i = 1; i < methodArity; ++i) { + if(!TypeUtilities.isSubtype(callSiteType.parameterType(i), methodType.parameterType(i))) { + return false; + } + } + return true; + } + }; + + /** + * Implements the applicability-by-method-invocation-conversion test from JLS 15.12.2.3. + */ + static final ApplicabilityTest APPLICABLE_BY_METHOD_INVOCATION_CONVERSION = new ApplicabilityTest() { + @Override + boolean isApplicable(MethodType callSiteType, MethodHandle method) { + final MethodType methodType = method.type(); + final int methodArity = methodType.parameterCount(); + if(methodArity != callSiteType.parameterCount()) { + return false; + } + // 0th arg is receiver; it doesn't matter for overload + // resolution. + for(int i = 1; i < methodArity; ++i) { + if(!TypeUtilities.isMethodInvocationConvertible(callSiteType.parameterType(i), + methodType.parameterType(i))) { + return false; + } + } + return true; + } + }; + + /** + * Implements the applicability-by-variable-arity test from JLS 15.12.2.4. + */ + static final ApplicabilityTest APPLICABLE_BY_VARIABLE_ARITY = new ApplicabilityTest() { + @Override + boolean isApplicable(MethodType callSiteType, MethodHandle method) { + if(!method.isVarargsCollector()) { + return false; + } + final MethodType methodType = method.type(); + final int methodArity = methodType.parameterCount(); + final int fixArity = methodArity - 1; + final int callSiteArity = callSiteType.parameterCount(); + if(fixArity > callSiteArity) { + return false; + } + // 0th arg is receiver; it doesn't matter for overload + // resolution. + for(int i = 1; i < fixArity; ++i) { + if(!TypeUtilities.isMethodInvocationConvertible(callSiteType.parameterType(i), + methodType.parameterType(i))) { + return false; + } + } + final Class varArgType = methodType.parameterType(fixArity).getComponentType(); + for(int i = fixArity; i < callSiteArity; ++i) { + if(!TypeUtilities.isMethodInvocationConvertible(callSiteType.parameterType(i), varArgType)) { + return false; + } + } + return true; + } + }; +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/BeanIntrospector.java b/nashorn/src/jdk/internal/dynalink/beans/BeanIntrospector.java new file mode 100644 index 00000000000..fc54e353a6e --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/BeanIntrospector.java @@ -0,0 +1,104 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import java.util.Collections; +import java.util.Map; + +class BeanIntrospector extends FacetIntrospector { + BeanIntrospector(Class clazz) { + super(clazz, true); + } + + @Override + Map getInnerClassGetters() { + return Collections.emptyMap(); // NOTE: non-static inner classes are also on StaticClassIntrospector. + } + + @Override + MethodHandle editMethodHandle(MethodHandle mh) { + return mh; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/BeanLinker.java b/nashorn/src/jdk/internal/dynalink/beans/BeanLinker.java new file mode 100644 index 00000000000..519036b37cc --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/BeanLinker.java @@ -0,0 +1,492 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Array; +import java.util.Collection; +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; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.support.Guards; +import jdk.internal.dynalink.support.Lookup; +import jdk.internal.dynalink.support.TypeUtilities; + +/** + * A class that provides linking capabilities for a single POJO class. Normally not used directly, but managed by + * {@link BeansLinker}. + * + * @author Attila Szegedi + */ +class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicLinker { + BeanLinker(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 + // explicit property is beneficial for them. + // REVISIT: is it maybe a code smell that "dyn:getLength" is not needed? + setPropertyGetter("length", GET_ARRAY_LENGTH, ValidationType.IS_ARRAY); + } + } + + @Override + public boolean canLinkType(Class type) { + return type == clazz; + } + + @Override + FacetIntrospector createFacetIntrospector() { + return new BeanIntrospector(clazz); + } + + @Override + protected GuardedInvocationComponent getGuardedInvocationComponent(CallSiteDescriptor callSiteDescriptor, + LinkerServices linkerServices, List operations) throws Exception { + final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(callSiteDescriptor, + linkerServices, operations); + if(superGic != null) { + return superGic; + } + if(operations.isEmpty()) { + return null; + } + final String op = operations.get(0); + // dyn:getElem(this, id) + // id is typically either an int (for arrays and lists) or an object (for maps). linkerServices can provide + // conversion from call site argument type though. + if("getElem".equals(op)) { + return getElementGetter(callSiteDescriptor, linkerServices, pop(operations)); + } + if("setElem".equals(op)) { + return getElementSetter(callSiteDescriptor, linkerServices, pop(operations)); + } + // dyn:getLength(this) (works on Java arrays, collections, and maps) + if("getLength".equals(op)) { + return getLengthGetter(callSiteDescriptor); + } + return null; + } + + private static MethodHandle GET_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "get", + MethodType.methodType(Object.class, int.class)); + + private static MethodHandle GET_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "get", + MethodType.methodType(Object.class, Object.class)); + + private static MethodHandle LIST_GUARD = Guards.getInstanceOfGuard(List.class); + private static MethodHandle MAP_GUARD = Guards.getInstanceOfGuard(Map.class); + + private GuardedInvocationComponent getElementGetter(final CallSiteDescriptor callSiteDescriptor, + final LinkerServices linkerServices, List operations) throws Exception { + final MethodType callSiteType = callSiteDescriptor.getMethodType(); + final Class declaredType = callSiteType.parameterType(0); + final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, + linkerServices, operations); + + // If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing + // is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're + // dealing with an array, or a list or map, but hey... + // Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers + // in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices. + final GuardedInvocationComponent gic; + final boolean isMap; + if(declaredType.isArray()) { + gic = new GuardedInvocationComponent(MethodHandles.arrayElementGetter(declaredType)); + isMap = false; + } else if(List.class.isAssignableFrom(declaredType)) { + gic = new GuardedInvocationComponent(GET_LIST_ELEMENT); + isMap = false; + } else if(Map.class.isAssignableFrom(declaredType)) { + gic = new GuardedInvocationComponent(GET_MAP_ELEMENT); + isMap = true; + } else if(clazz.isArray()) { + gic = getClassGuardedInvocationComponent(MethodHandles.arrayElementGetter(clazz), callSiteType); + isMap = false; + } else if(List.class.isAssignableFrom(clazz)) { + gic = new GuardedInvocationComponent(GET_LIST_ELEMENT, Guards.asType(LIST_GUARD, callSiteType), List.class, + ValidationType.INSTANCE_OF); + isMap = false; + } else if(Map.class.isAssignableFrom(clazz)) { + gic = new GuardedInvocationComponent(GET_MAP_ELEMENT, Guards.asType(MAP_GUARD, callSiteType), Map.class, + ValidationType.INSTANCE_OF); + isMap = true; + } else { + // Can't retrieve elements for objects that are neither arrays, nor list, nor maps. + return nextComponent; + } + + // We can have "dyn:getElem:foo", especially in composites, i.e. "dyn:getElem|getProp|getMethod:foo" + final String fixedKey = getFixedKey(callSiteDescriptor); + // Convert the key to a number if we're working with a list or array + final Object typedFixedKey; + if(!isMap && fixedKey != null) { + typedFixedKey = convertKeyToInteger(fixedKey, linkerServices); + if(typedFixedKey == null) { + // key is not numeric, it can never succeed + return nextComponent; + } + } else { + typedFixedKey = fixedKey; + } + + final GuardedInvocation gi = gic.getGuardedInvocation(); + final Binder binder = new Binder(linkerServices, callSiteType, typedFixedKey); + final MethodHandle invocation = gi.getInvocation(); + + if(nextComponent == null) { + return gic.replaceInvocation(binder.bind(invocation)); + } + + final MethodHandle checkGuard; + if(invocation == GET_LIST_ELEMENT) { + checkGuard = convertArgToInt(RANGE_CHECK_LIST, linkerServices, callSiteDescriptor); + } else if(invocation == GET_MAP_ELEMENT) { + // TODO: A more complex solution could be devised for maps, one where we do a get() first, and fold it + // into a GWT that tests if it returned null, and if it did, do another GWT with containsKey() + // that returns constant null (on true), or falls back to next component (on false) + checkGuard = CONTAINS_MAP; + } else { + checkGuard = convertArgToInt(RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor); + } + return nextComponent.compose(MethodHandles.guardWithTest(binder.bindTest(checkGuard), + binder.bind(invocation), nextComponent.getGuardedInvocation().getInvocation()), gi.getGuard(), + gic.getValidatorClass(), gic.getValidationType()); + } + + private static String getFixedKey(final CallSiteDescriptor callSiteDescriptor) { + return callSiteDescriptor.getNameTokenCount() == 2 ? null : callSiteDescriptor.getNameToken( + CallSiteDescriptor.NAME_OPERAND); + } + + private static Object convertKeyToInteger(String fixedKey, LinkerServices linkerServices) throws Exception { + try { + if(linkerServices.canConvert(String.class, Number.class)) { + try { + final Object val = linkerServices.getTypeConverter(String.class, Number.class).invoke(fixedKey); + if(!(val instanceof Number)) { + return null; // not a number + } + final Number n = (Number)val; + if(n instanceof Integer) { + return n; + } + final int intIndex = n.intValue(); + final double doubleValue = n.doubleValue(); + if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinites trigger IOOBE + return null; // not an exact integer + } + return Integer.valueOf(intIndex); + } catch(Exception|Error e) { + throw e; + } catch(Throwable t) { + throw new RuntimeException(t); + } + } + return Integer.valueOf(fixedKey); + } catch(NumberFormatException e) { + // key is not a number + return null; + } + } + + private static MethodHandle convertArgToInt(MethodHandle mh, LinkerServices ls, CallSiteDescriptor desc) { + final Class sourceType = desc.getMethodType().parameterType(1); + if(TypeUtilities.isMethodInvocationConvertible(sourceType, Number.class)) { + return mh; + } else if(ls.canConvert(sourceType, Number.class)) { + final MethodHandle converter = ls.getTypeConverter(sourceType, Number.class); + return MethodHandles.filterArguments(mh, 1, converter.asType(converter.type().changeReturnType( + mh.type().parameterType(1)))); + } + return mh; + } + + /** + * Contains methods to adapt an item getter/setter method handle to the requested type, optionally binding it to a + * fixed key first. + * @author Attila Szegedi + * @version $Id: $ + */ + private static class Binder { + private final LinkerServices linkerServices; + private final MethodType methodType; + private final Object fixedKey; + + Binder(LinkerServices linkerServices, MethodType methodType, 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 bindTest(MethodHandle handle) { + return bindToFixedKey(Guards.asType(handle, methodType)); + } + + private MethodHandle bindToFixedKey(MethodHandle handle) { + return fixedKey == null ? handle : MethodHandles.insertArguments(handle, 1, fixedKey); + } + } + + private static MethodHandle RANGE_CHECK_ARRAY = findRangeCheck(Object.class); + private static MethodHandle RANGE_CHECK_LIST = findRangeCheck(List.class); + private static MethodHandle CONTAINS_MAP = Lookup.PUBLIC.findVirtual(Map.class, "containsKey", + MethodType.methodType(boolean.class, Object.class)); + + private static MethodHandle findRangeCheck(Class collectionType) { + return Lookup.findOwnStatic(MethodHandles.lookup(), "rangeCheck", boolean.class, collectionType, Object.class); + } + + @SuppressWarnings("unused") + private static final boolean rangeCheck(Object array, Object index) { + if(!(index instanceof Number)) { + return false; + } + final Number n = (Number)index; + final int intIndex = n.intValue(); + final double doubleValue = n.doubleValue(); + if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinite trigger IOOBE + return false; + } + if(0 <= intIndex && intIndex < Array.getLength(array)) { + return true; + } + throw new ArrayIndexOutOfBoundsException("Array index out of range: " + n); + } + + @SuppressWarnings("unused") + private static final boolean rangeCheck(List list, Object index) { + if(!(index instanceof Number)) { + return false; + } + final Number n = (Number)index; + final int intIndex = n.intValue(); + final double doubleValue = n.doubleValue(); + if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinite trigger IOOBE + return false; + } + if(0 <= intIndex && intIndex < list.size()) { + return true; + } + throw new IndexOutOfBoundsException("Index: " + n + ", Size: " + list.size()); + } + + private static MethodHandle SET_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "set", + MethodType.methodType(Object.class, int.class, Object.class)); + + 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 operations) throws Exception { + final MethodType callSiteType = callSiteDescriptor.getMethodType(); + final Class declaredType = callSiteType.parameterType(0); + + final GuardedInvocationComponent gic; + // If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing + // is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're + // dealing with an array, or a list or map, but hey... + // Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers + // in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices. + final boolean isMap; + if(declaredType.isArray()) { + gic = new GuardedInvocationComponent(MethodHandles.arrayElementSetter(declaredType)); + isMap = false; + } else if(List.class.isAssignableFrom(declaredType)) { + gic = new GuardedInvocationComponent(SET_LIST_ELEMENT); + isMap = false; + } else if(Map.class.isAssignableFrom(declaredType)) { + gic = new GuardedInvocationComponent(PUT_MAP_ELEMENT); + isMap = true; + } else if(clazz.isArray()) { + gic = getClassGuardedInvocationComponent(MethodHandles.arrayElementSetter(clazz), callSiteType); + isMap = false; + } else if(List.class.isAssignableFrom(clazz)) { + gic = new GuardedInvocationComponent(SET_LIST_ELEMENT, Guards.asType(LIST_GUARD, callSiteType), List.class, + ValidationType.INSTANCE_OF); + isMap = false; + } else if(Map.class.isAssignableFrom(clazz)) { + gic = new GuardedInvocationComponent(PUT_MAP_ELEMENT, Guards.asType(MAP_GUARD, callSiteType), Map.class, + ValidationType.INSTANCE_OF); + isMap = true; + } else { + // Can't set elements for objects that are neither arrays, nor list, nor maps. + gic = null; + isMap = false; + } + + // In contrast to, say, getElementGetter, we only compute the nextComponent if the target object is not a map, + // as maps will always succeed in setting the element and will never need to fall back to the next component + // operation. + final GuardedInvocationComponent nextComponent = isMap ? null : getGuardedInvocationComponent( + callSiteDescriptor, linkerServices, operations); + if(gic == null) { + return nextComponent; + } + + // We can have "dyn:setElem:foo", especially in composites, i.e. "dyn:setElem|setProp:foo" + final String fixedKey = getFixedKey(callSiteDescriptor); + // Convert the key to a number if we're working with a list or array + final Object typedFixedKey; + if(!isMap && fixedKey != null) { + typedFixedKey = convertKeyToInteger(fixedKey, linkerServices); + if(typedFixedKey == null) { + // key is not numeric, it can never succeed + return nextComponent; + } + } else { + typedFixedKey = fixedKey; + } + + final GuardedInvocation gi = gic.getGuardedInvocation(); + final Binder binder = new Binder(linkerServices, callSiteType, typedFixedKey); + final MethodHandle invocation = gi.getInvocation(); + + if(nextComponent == null) { + return gic.replaceInvocation(binder.bind(invocation)); + } + + 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(), + gic.getValidatorClass(), gic.getValidationType()); + } + + private static MethodHandle GET_ARRAY_LENGTH = Lookup.PUBLIC.findStatic(Array.class, "getLength", + MethodType.methodType(int.class, Object.class)); + + private static MethodHandle GET_COLLECTION_LENGTH = Lookup.PUBLIC.findVirtual(Collection.class, "size", + MethodType.methodType(int.class)); + + private static MethodHandle GET_MAP_LENGTH = Lookup.PUBLIC.findVirtual(Map.class, "size", + MethodType.methodType(int.class)); + + private static MethodHandle COLLECTION_GUARD = Guards.getInstanceOfGuard(Collection.class); + + private GuardedInvocationComponent getLengthGetter(CallSiteDescriptor callSiteDescriptor) { + assertParameterCount(callSiteDescriptor, 1); + final MethodType callSiteType = callSiteDescriptor.getMethodType(); + final Class declaredType = callSiteType.parameterType(0); + // If declared type of receiver at the call site is already an array, collection, or map, bind without guard. + // Thing is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance + // they're dealing with an array, collection, or map, but hey... + if(declaredType.isArray()) { + return new GuardedInvocationComponent(GET_ARRAY_LENGTH.asType(callSiteType)); + } else if(Collection.class.isAssignableFrom(declaredType)) { + return new GuardedInvocationComponent(GET_COLLECTION_LENGTH.asType(callSiteType)); + } else if(Map.class.isAssignableFrom(declaredType)) { + return new GuardedInvocationComponent(GET_MAP_LENGTH.asType(callSiteType)); + } + + // Otherwise, create a binding based on the actual type of the argument with an appropriate guard. + if(clazz.isArray()) { + return new GuardedInvocationComponent(GET_ARRAY_LENGTH.asType(callSiteType), Guards.isArray(0, + callSiteType), ValidationType.IS_ARRAY); + } if(Collection.class.isAssignableFrom(clazz)) { + return new GuardedInvocationComponent(GET_COLLECTION_LENGTH.asType(callSiteType), Guards.asType( + COLLECTION_GUARD, callSiteType), Collection.class, ValidationType.INSTANCE_OF); + } if(Map.class.isAssignableFrom(clazz)) { + return new GuardedInvocationComponent(GET_MAP_LENGTH.asType(callSiteType), Guards.asType(MAP_GUARD, + callSiteType), Map.class, ValidationType.INSTANCE_OF); + } + // Can't retrieve length for objects that are neither arrays, nor collections, nor maps. + return null; + } + + private static void assertParameterCount(CallSiteDescriptor descriptor, int paramCount) { + if(descriptor.getMethodType().parameterCount() != paramCount) { + throw new BootstrapMethodError(descriptor.getName() + " must have exactly " + paramCount + " parameters."); + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/BeansLinker.java b/nashorn/src/jdk/internal/dynalink/beans/BeansLinker.java new file mode 100644 index 00000000000..85811235699 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/BeansLinker.java @@ -0,0 +1,186 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandles; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.DynamicLinkerFactory; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; + +/** + * A linker for POJOs. Normally used as the ultimate fallback linker by the {@link DynamicLinkerFactory} so it is given + * the chance to link calls to all objects that no other language runtime recognizes. Specifically, this linker will: + *
    + *
  • expose all public methods of form {@code setXxx()}, {@code getXxx()}, and {@code isXxx()} as property setters and + * getters for {@code dyn:setProp} and {@code dyn:getProp} operations;
  • + *
  • expose all public methods for invocation through {@code dyn:callMethod} operation;
  • + *
  • expose all public methods for retrieval for {@code dyn:getMethod} operation; the methods thus retrieved can then + * be invoked using {@code dyn:call};
  • + *
  • expose all public fields as properties, unless there are getters or setters for the properties of the same name;
  • + *
  • expose {@code dyn:getLength}, {@code dyn:getElem} and {@code dyn:setElem} on native Java arrays, as well as + * {@link java.util.List} and {@link java.util.Map} objects; ({@code dyn:getLength} works on any + * {@link java.util.Collection});
  • + *
  • expose a virtual property named {@code length} on Java arrays;
  • + *
  • expose {@code dyn:new} on instances of {@link StaticClass} as calls to constructors, including those static class + * objects that represent Java arrays (their constructors take a single {@code int} parameter representing the length of + * the array to create);
  • + *
  • expose static methods, fields, and properties of classes in a similar manner to how instance method, fields, and + * properties are exposed, on {@link StaticClass} objects.
  • + *
  • expose a virtual property named {@code static} on instances of {@link java.lang.Class} to access their + * {@link StaticClass}.
  • + *
+ *

Overloaded method resolution is performed automatically for property setters, methods, and + * constructors. Additionally, manual overloaded method selection is supported by having a call site specify a name for + * a method that contains an explicit signature, i.e. {@code dyn:getMethod:parseInt(String,int)}. You can use + * non-qualified class names in such signatures regardless of those classes' packages, they will match any class with + * the same non-qualified name. You only have to use a fully qualified class name in case non-qualified class names + * would cause selection ambiguity (that is extremely rare).

+ *

Variable argument invocation is handled for both methods and constructors.

+ *

Currently, only public fields and methods are supported. Any Lookup objects passed in the + * {@link LinkRequest}s are ignored and {@link MethodHandles#publicLookup()} is used instead.

+ * + * @author Attila Szegedi + */ +public class BeansLinker implements GuardingDynamicLinker { + private static final ClassValue linkers = new ClassValue() { + @Override + protected TypeBasedGuardingDynamicLinker computeValue(Class clazz) { + // If ClassValue.put() were public, we could just pre-populate with these known mappings... + return + clazz == Class.class ? new ClassLinker() : + clazz == StaticClass.class ? new StaticClassLinker() : + DynamicMethod.class.isAssignableFrom(clazz) ? new DynamicMethodLinker() : + new BeanLinker(clazz); + } + }; + + /** + * Creates a new POJO linker. + */ + public BeansLinker() { + } + + /** + * Returns a bean linker for a particular single class. Useful when you need to override or extend the behavior of + * linking for some classes in your language runtime's linker, but still want to delegate to the default behavior in + * some cases. + * @param clazz the class + * @return a bean linker for that class + */ + public static TypeBasedGuardingDynamicLinker getLinkerForClass(Class clazz) { + return linkers.get(clazz); + } + + /** + * Returns true if the object is a Dynalink Java dynamic method. + * + * @param obj the object we want to test for being a dynamic method + * @return true if it is a dynamic method, false otherwise. + */ + public static boolean isDynamicMethod(final Object obj) { + return obj instanceof DynamicMethod; + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest request, final LinkerServices linkerServices) + throws Exception { + final CallSiteDescriptor callSiteDescriptor = request.getCallSiteDescriptor(); + final int l = callSiteDescriptor.getNameTokenCount(); + // All names conforming to the dynalang MOP should have at least two tokens, the first one being "dyn" + if(l < 2 || "dyn" != callSiteDescriptor.getNameToken(CallSiteDescriptor.SCHEME)) { + return null; + } + + final Object receiver = request.getReceiver(); + if(receiver == null) { + // Can't operate on null + return null; + } + return getLinkerForClass(receiver.getClass()).getGuardedInvocation(request, linkerServices); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/CheckRestrictedPackage.java b/nashorn/src/jdk/internal/dynalink/beans/CheckRestrictedPackage.java new file mode 100644 index 00000000000..360759f8674 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/CheckRestrictedPackage.java @@ -0,0 +1,138 @@ +/* + * 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.beans; + +import java.lang.reflect.Modifier; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.Permissions; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; + +/** + * A utility class to check whether a given class is in a package with restricted access e.g. "sun.*" etc. + */ +class CheckRestrictedPackage { + private static final AccessControlContext NO_PERMISSIONS_CONTEXT = createNoPermissionsContext(); + + /** + * Returns true if the class is either not public, or it resides in a package with restricted access. + * @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) { + if(!Modifier.isPublic(clazz.getModifiers())) { + // Non-public classes are always restricted + return true; + } + final SecurityManager sm = System.getSecurityManager(); + if(sm == null) { + // No further restrictions if we don't have a security manager + return false; + } + final String name = clazz.getName(); + final int i = name.lastIndexOf('.'); + if (i == -1) { + // Classes in default package are never restricted + return false; + } + // Do a package access check from within an access control context with no permissions + try { + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Void run() { + sm.checkPackageAccess(name.substring(0, i)); + return null; + } + }, NO_PERMISSIONS_CONTEXT); + } catch(SecurityException e) { + return true; + } + return false; + } + + private static AccessControlContext createNoPermissionsContext() { + return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) }); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/ClassLinker.java b/nashorn/src/jdk/internal/dynalink/beans/ClassLinker.java new file mode 100644 index 00000000000..15c9e18d891 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/ClassLinker.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType; +import jdk.internal.dynalink.support.Lookup; + +/** + * A linker for java.lang.Class objects. Provides a synthetic property "static" that allows access to static fields and + * methods on the class (respecting property getter/setter conventions). Note that Class objects are not recognized by + * the Dynalink as constructors for the instances of the class, {@link StaticClass} is used for this purpose. + * @author Attila Szegedi + */ +class ClassLinker extends BeanLinker { + + ClassLinker() { + super(Class.class); + // Map "classObject.static" to StaticClass.forClass(classObject). Can use EXACT_CLASS since class Class is final. + setPropertyGetter("static", FOR_CLASS, ValidationType.EXACT_CLASS); + } + + private static final MethodHandle FOR_CLASS = new Lookup(MethodHandles.lookup()).findStatic(StaticClass.class, + "forClass", MethodType.methodType(StaticClass.class, Class.class)); + +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/ClassString.java b/nashorn/src/jdk/internal/dynalink/beans/ClassString.java new file mode 100644 index 00000000000..d6c6da08933 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/ClassString.java @@ -0,0 +1,208 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.LinkedList; +import java.util.List; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.support.Guards; +import jdk.internal.dynalink.support.TypeUtilities; + +/** + * + * @author Attila Szegedi + */ +final class ClassString { + private final Class[] classes; + private int hashCode; + + ClassString(Class[] classes) { + this.classes = classes; + } + + ClassString(MethodType type) { + this(type.parameterArray()); + } + + Class[] getClasses() { + return classes; + } + + @Override + public boolean equals(Object other) { + if(!(other instanceof ClassString)) { + return false; + } + final Class[] otherClasses = ((ClassString)other).classes; + if(otherClasses.length != classes.length) { + return false; + } + for(int i = 0; i < otherClasses.length; ++i) { + if(otherClasses[i] != classes[i]) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + if(hashCode == 0) { + int h = 0; + for(int i = 0; i < classes.length; ++i) { + h ^= classes[i].hashCode(); + } + hashCode = h; + } + return hashCode; + } + + boolean isVisibleFrom(final ClassLoader classLoader) { + for(int i = 0; i < classes.length; ++i) { + if(!Guards.canReferenceDirectly(classLoader, classes[i].getClassLoader())) { + return false; + } + } + return true; + } + + List getMaximallySpecifics(List methods, LinkerServices linkerServices, boolean varArg) { + return MaximallySpecific.getMaximallySpecificMethods(getApplicables(methods, linkerServices, varArg), varArg, + classes, linkerServices); + } + + /** + * Returns all methods that are applicable to actual parameter classes represented by this ClassString object. + */ + LinkedList getApplicables(List methods, LinkerServices linkerServices, boolean varArg) { + final LinkedList list = new LinkedList<>(); + for(final MethodHandle member: methods) { + if(isApplicable(member, linkerServices, varArg)) { + list.add(member); + } + } + return list; + } + + /** + * Returns true if the supplied method is applicable to actual parameter classes represented by this ClassString + * object. + * + */ + private boolean isApplicable(MethodHandle method, LinkerServices linkerServices, boolean varArg) { + final Class[] formalTypes = method.type().parameterArray(); + final int cl = classes.length; + final int fl = formalTypes.length - (varArg ? 1 : 0); + if(varArg) { + if(cl < fl) { + return false; + } + } else { + if(cl != fl) { + return false; + } + } + // Starting from 1 as we ignore the receiver type + for(int i = 1; i < fl; ++i) { + if(!canConvert(linkerServices, classes[i], formalTypes[i])) { + return false; + } + } + if(varArg) { + final Class varArgType = formalTypes[fl].getComponentType(); + for(int i = fl; i < cl; ++i) { + if(!canConvert(linkerServices, classes[i], varArgType)) { + return false; + } + } + } + return true; + } + + private static boolean canConvert(LinkerServices ls, Class from, Class to) { + return ls == null ? TypeUtilities.isMethodInvocationConvertible(from, to) : ls.canConvert(from, to); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/DynamicMethod.java b/nashorn/src/jdk/internal/dynalink/beans/DynamicMethod.java new file mode 100644 index 00000000000..aee69ff722e --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/DynamicMethod.java @@ -0,0 +1,168 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.StringTokenizer; +import jdk.internal.dynalink.linker.LinkerServices; + +/** + * Represents a single dynamic method. A "dynamic" method can be bound to a single Java method, or can be bound to all + * overloaded methods of the same name on a class. Getting an invocation of a dynamic method bound to multiple + * overloaded methods will perform overload resolution (actually, it will perform partial overloaded resolution at link + * time, but if that fails to identify exactly one target method, it will generate a method handle that will perform the + * rest of the overload resolution at invocation time for actual argument types). + * + * @author Attila Szegedi + */ +abstract class DynamicMethod { + private final String name; + + DynamicMethod(String name) { + this.name = name; + } + + String getName() { + return name; + } + + /** + * Creates an invocation for the dynamic method. If the method is overloaded, it will perform overloaded method + * resolution based on the specified method type. The resulting resolution can either identify a single method to be + * invoked among the overloads, or it can identify multiple ones. In the latter case, the returned method handle + * will perform further overload resolution among these candidates at every invocation. If the method to be invoked + * is a variable arguments (vararg) method, it will pack the extra arguments in an array before the invocation of + * the underlying method if it is not already done. + * + * @param callSiteType the method type at a call site + * @param linkerServices linker services. Used for language-specific type conversions. + * @return an invocation suitable for calling the method from the specified call site. + */ + abstract MethodHandle getInvocation(MethodType callSiteType, LinkerServices linkerServices); + + /** + * Returns a simple dynamic method representing a single underlying Java method (possibly selected among several + * overloads) with formal parameter types exactly matching the passed signature. + * @param paramTypes the comma-separated list of requested parameter type names. The names will match both + * qualified and unqualified type names. + * @return a simple dynamic method representing a single underlying Java method, or null if none of the Java methods + * behind this dynamic method exactly match the requested parameter types. + */ + abstract SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes); + + /** + * True if this dynamic method already contains a method handle with an identical signature as the passed in method + * handle. + * @param mh the method handle to check + * @return true if it already contains an equivalent method handle. + */ + abstract boolean contains(MethodHandle mh); + + static boolean typeMatchesDescription(String paramTypes, 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)))) { + return false; + } + } + return !tok.hasMoreTokens(); + } + + private static boolean typeNameMatches(String typeName, Class type) { + final int lastDot = typeName.lastIndexOf('.'); + final String fullTypeName = type.getCanonicalName(); + return lastDot != -1 && fullTypeName.endsWith(typeName.substring(lastDot)) || typeName.equals(fullTypeName); + } + + static String getClassAndMethodName(Class clazz, String name) { + final String clazzName = clazz.getCanonicalName(); + return (clazzName == null ? clazz.getName() : clazzName) + "." + name; + } + + @Override + public String toString() { + return "[" + getClass().getName() + " " + getName() + "]"; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java b/nashorn/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java new file mode 100644 index 00000000000..d8ceeea0045 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java @@ -0,0 +1,129 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.support.Guards; + +/** + * Simple linker that implements the "dyn:call" operation for {@link DynamicMethod} objects - the objects returned by + * "dyn:getMethod" from {@link AbstractJavaLinker}. + */ +class DynamicMethodLinker implements TypeBasedGuardingDynamicLinker { + @Override + public boolean canLinkType(Class type) { + return DynamicMethod.class.isAssignableFrom(type); + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, LinkerServices linkerServices) { + final Object receiver = linkRequest.getReceiver(); + if(!(receiver instanceof DynamicMethod)) { + return null; + } + final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor(); + if(desc.getNameTokenCount() != 2 && desc.getNameToken(CallSiteDescriptor.SCHEME) != "dyn") { + return null; + } + final String operator = desc.getNameToken(CallSiteDescriptor.OPERATOR); + if(operator == "call") { + final MethodType type = desc.getMethodType(); + final MethodHandle invocation = ((DynamicMethod)receiver).getInvocation(type.dropParameterTypes(0, 1), + linkerServices); + if(invocation == null) { + return null; + } + return new GuardedInvocation(MethodHandles.dropArguments(invocation, 0, type.parameterType(0)), + Guards.getIdentityGuard(receiver)); + } + return null; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java b/nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java new file mode 100644 index 00000000000..f4fbd8244f1 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java @@ -0,0 +1,182 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +/** + * Base for classes that expose class field and method information to an {@link AbstractJavaLinker}. There are + * subclasses for instance (bean) and static facet of a class. + * @author Attila Szegedi + */ +abstract class FacetIntrospector { + private final Class clazz; + private final boolean instance; + private final boolean isRestricted; + + protected final AccessibleMembersLookup membersLookup; + + FacetIntrospector(Class clazz, boolean instance) { + this.clazz = clazz; + this.instance = instance; + isRestricted = CheckRestrictedPackage.isRestrictedClass(clazz); + membersLookup = new AccessibleMembersLookup(clazz, instance); + } + + /** + * Returns getters for inner classes. + * @return getters for inner classes. + */ + abstract Map getInnerClassGetters(); + + /** + * Returns the fields for the class facet. + * @return the fields for the class facet. + */ + Collection getFields() { + if(isRestricted) { + // NOTE: we can't do anything here. Unlike with methods in AccessibleMethodsLookup, we can't just return + // the fields from a public superclass, because this class might define same-named fields which will shadow + // the superclass fields, and we have no way to know if they do, since we're denied invocation of + // getFields(). Therefore, the only correct course of action is to not expose any public fields from a class + // defined in a restricted package. + return Collections.emptySet(); + } + + final Field[] fields = clazz.getFields(); + final Collection cfields = new ArrayList<>(fields.length); + for(Field field: fields) { + if(instance != Modifier.isStatic(field.getModifiers()) && isAccessible(field)) { + cfields.add(field); + } + } + return cfields; + } + + boolean isAccessible(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 + // a potentially expensive restricted-package check. + return declaring == clazz || !CheckRestrictedPackage.isRestrictedClass(declaring); + } + + /** + * Returns all the methods in the facet. + * @return all the methods in the facet. + */ + Collection getMethods() { + return membersLookup.getMethods(); + } + + + MethodHandle unreflectGetter(Field field) { + return editMethodHandle(SafeUnreflector.unreflectGetter(field)); + } + + MethodHandle unreflectSetter(Field field) { + return editMethodHandle(SafeUnreflector.unreflectSetter(field)); + } + + MethodHandle unreflect(Method method) { + return editMethodHandle(SafeUnreflector.unreflect(method)); + } + + /** + * Returns an edited method handle. A facet might need to edit an unreflected method handle before it is usable with + * the facet. By default, returns the passed method handle unchanged. The class' static facet will introduce a + * dropArguments. + * @param mh the method handle to edit. + * @return the edited method handle. + */ + abstract MethodHandle editMethodHandle(MethodHandle mh); +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/GuardedInvocationComponent.java b/nashorn/src/jdk/internal/dynalink/beans/GuardedInvocationComponent.java new file mode 100644 index 00000000000..f2c76dba828 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/GuardedInvocationComponent.java @@ -0,0 +1,252 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import jdk.internal.dynalink.linker.GuardedInvocation; + +/** + * Represents one component for a GuardedInvocation of a potentially composite operation of an + * {@link AbstractJavaLinker}. In addition to holding a guarded invocation, it holds semantic information about its + * guard. All guards produced in the AbstractJavaLinker are either "Class.isInstance()" or "getClass() == clazz" + * expressions. This allows choosing the most restrictive guard as the guard for the composition of two components. + * @author Attila Szegedi + * @version $Id: $ + */ +class GuardedInvocationComponent { + enum ValidationType { + NONE, // No guard; the operation can be linked unconditionally (quite rare); least strict. + INSTANCE_OF, // "validatorClass.isInstance(obj)" guard + EXACT_CLASS, // "obj.getClass() == validatorClass" guard; most strict. + IS_ARRAY, // "obj.getClass().isArray()" + } + + private final GuardedInvocation guardedInvocation; + private final Validator validator; + + GuardedInvocationComponent(MethodHandle invocation) { + this(invocation, null, ValidationType.NONE); + } + + GuardedInvocationComponent(MethodHandle invocation, MethodHandle guard, ValidationType validationType) { + this(invocation, guard, null, validationType); + } + + GuardedInvocationComponent(MethodHandle invocation, MethodHandle guard, Class validatorClass, + ValidationType validationType) { + this(invocation, guard, new Validator(validatorClass, validationType)); + } + + GuardedInvocationComponent(GuardedInvocation guardedInvocation, Class validatorClass, + ValidationType validationType) { + this(guardedInvocation, new Validator(validatorClass, validationType)); + } + + GuardedInvocationComponent replaceInvocation(MethodHandle newInvocation) { + return replaceInvocation(newInvocation, guardedInvocation.getGuard()); + } + + GuardedInvocationComponent replaceInvocation(MethodHandle newInvocation, MethodHandle newGuard) { + return new GuardedInvocationComponent(guardedInvocation.replaceMethods(newInvocation, + newGuard), validator); + } + + private GuardedInvocationComponent(MethodHandle invocation, MethodHandle guard, Validator validator) { + this(new GuardedInvocation(invocation, guard), validator); + } + + private GuardedInvocationComponent(GuardedInvocation guardedInvocation, Validator validator) { + this.guardedInvocation = guardedInvocation; + this.validator = validator; + } + + GuardedInvocation getGuardedInvocation() { + return guardedInvocation; + } + + Class getValidatorClass() { + return validator.validatorClass; + } + + ValidationType getValidationType() { + return validator.validationType; + } + + GuardedInvocationComponent compose(MethodHandle compositeInvocation, MethodHandle otherGuard, + Class otherValidatorClass, 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); + } + + private static class Validator { + /*private*/ final Class validatorClass; + /*private*/ final ValidationType validationType; + + Validator(Class validatorClass, ValidationType validationType) { + this.validatorClass = validatorClass; + this.validationType = validationType; + } + + Validator compose(Validator other) { + if(other.validationType == ValidationType.NONE) { + return this; + } + switch(validationType) { + case NONE: + return other; + case INSTANCE_OF: + switch(other.validationType) { + case INSTANCE_OF: + if(isAssignableFrom(other)) { + return other; + } else if(other.isAssignableFrom(this)) { + return this; + } + break; + case EXACT_CLASS: + if(isAssignableFrom(other)) { + return other; + } + break; + case IS_ARRAY: + if(validatorClass.isArray()) { + return this; + } + break; + default: + throw new AssertionError(); + } + break; + case EXACT_CLASS: + switch(other.validationType) { + case INSTANCE_OF: + if(other.isAssignableFrom(this)) { + return this; + } + break; + case EXACT_CLASS: + if(validatorClass == other.validatorClass) { + return this; + } + break; + case IS_ARRAY: + if(validatorClass.isArray()) { + return this; + } + break; + default: + throw new AssertionError(); + } + break; + case IS_ARRAY: + switch(other.validationType) { + case INSTANCE_OF: + case EXACT_CLASS: + if(other.validatorClass.isArray()) { + return other; + } + break; + case IS_ARRAY: + return this; + default: + throw new AssertionError(); + } + break; + default: + throw new AssertionError(); + } + throw new AssertionError("Incompatible composition " + this + " vs " + other); + } + + private boolean isAssignableFrom(Validator other) { + return validatorClass.isAssignableFrom(other.validatorClass); + } + + @Override + public String toString() { + return "Validator[" + validationType + (validatorClass == null ? "" : (" " + validatorClass.getName())) + "]"; + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/MaximallySpecific.java b/nashorn/src/jdk/internal/dynalink/beans/MaximallySpecific.java new file mode 100644 index 00000000000..182fd01695d --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/MaximallySpecific.java @@ -0,0 +1,214 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import jdk.internal.dynalink.linker.ConversionComparator.Comparison; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.support.TypeUtilities; + +/** + * Utility class that encapsulates the algorithm for choosing the maximally specific methods. + * + * @author Attila Szegedi + */ +class MaximallySpecific { + /** + * Given a list of methods, returns a list of maximally specific methods. + * + * @param methods the list of methods + * @param varArgs whether to assume the methods are varargs + * @return the list of maximally specific methods. + */ + static List getMaximallySpecificMethods(List methods, boolean varArgs) { + return getMaximallySpecificMethods(methods, varArgs, null, null); + } + + /** + * Given a list of methods, returns a list of maximally specific methods, applying language-runtime specific + * conversion preferences. + * + * @param methods the list of methods + * @param varArgs whether to assume the methods are varargs + * @param argTypes concrete argument types for the invocation + * @return the list of maximally specific methods. + */ + static List getMaximallySpecificMethods(List methods, boolean varArgs, + Class[] argTypes, LinkerServices ls) { + if(methods.size() < 2) { + return methods; + } + final LinkedList maximals = new LinkedList<>(); + for(MethodHandle m: methods) { + final MethodType methodType = m.type(); + boolean lessSpecific = false; + for(Iterator maximal = maximals.iterator(); maximal.hasNext();) { + final MethodHandle max = maximal.next(); + switch(isMoreSpecific(methodType, max.type(), varArgs, argTypes, ls)) { + case TYPE_1_BETTER: { + maximal.remove(); + break; + } + case TYPE_2_BETTER: { + lessSpecific = true; + break; + } + case INDETERMINATE: { + // do nothing + break; + } + default: { + throw new AssertionError(); + } + } + } + if(!lessSpecific) { + maximals.addLast(m); + } + } + return maximals; + } + + private static Comparison isMoreSpecific(MethodType t1, MethodType t2, boolean varArgs, Class[] argTypes, + LinkerServices ls) { + final int pc1 = t1.parameterCount(); + final int pc2 = t2.parameterCount(); + assert varArgs || (pc1 == pc2) && (argTypes == null || argTypes.length == pc1); + assert (argTypes == null) == (ls == null); + final int maxPc = Math.max(Math.max(pc1, pc2), argTypes == null ? 0 : argTypes.length); + boolean t1MoreSpecific = false; + boolean t2MoreSpecific = false; + // NOTE: Starting from 1 as overloaded method resolution doesn't depend on 0th element, which is the type of + // 'this'. We're only dealing with instance methods here, not static methods. Actually, static methods will have + // a fake 'this' of type StaticClass. + for(int i = 1; i < maxPc; ++i) { + final Class c1 = getParameterClass(t1, pc1, i, varArgs); + final Class c2 = getParameterClass(t2, pc2, i, varArgs); + if(c1 != c2) { + final Comparison cmp = compare(c1, c2, argTypes, i, ls); + if(cmp == Comparison.TYPE_1_BETTER && !t1MoreSpecific) { + t1MoreSpecific = true; + if(t2MoreSpecific) { + return Comparison.INDETERMINATE; + } + } + if(cmp == Comparison.TYPE_2_BETTER && !t2MoreSpecific) { + t2MoreSpecific = true; + if(t1MoreSpecific) { + return Comparison.INDETERMINATE; + } + } + } + } + if(t1MoreSpecific) { + return Comparison.TYPE_1_BETTER; + } else if(t2MoreSpecific) { + return Comparison.TYPE_2_BETTER; + } + return Comparison.INDETERMINATE; + } + + private static Comparison compare(Class c1, Class c2, Class[] argTypes, int i, LinkerServices cmp) { + if(cmp != null) { + final Comparison c = cmp.compareConversion(argTypes[i], c1, c2); + if(c != Comparison.INDETERMINATE) { + return c; + } + } + if(TypeUtilities.isSubtype(c1, c2)) { + return Comparison.TYPE_1_BETTER; + } if(TypeUtilities.isSubtype(c2, c1)) { + return Comparison.TYPE_2_BETTER; + } + return Comparison.INDETERMINATE; + } + + private static Class getParameterClass(MethodType t, int l, int i, boolean varArgs) { + return varArgs && i >= l - 1 ? t.parameterType(l - 1).getComponentType() : t.parameterType(i); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java b/nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java new file mode 100644 index 00000000000..7873cf1520e --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java @@ -0,0 +1,320 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import jdk.internal.dynalink.beans.ApplicableOverloadedMethods.ApplicabilityTest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.support.TypeUtilities; + +/** + * Represents an overloaded method. + * + * @author Attila Szegedi + */ +class OverloadedDynamicMethod extends DynamicMethod { + /** + * Holds a list of all methods. + */ + private final LinkedList methods; + private final ClassLoader classLoader; + + /** + * Creates a new overloaded dynamic method. + * + * @param clazz the class this method belongs to + * @param name the name of the method + */ + OverloadedDynamicMethod(Class clazz, String name) { + this(new LinkedList(), clazz.getClassLoader(), getClassAndMethodName(clazz, name)); + } + + private OverloadedDynamicMethod(LinkedList methods, ClassLoader classLoader, String name) { + super(name); + this.methods = methods; + this.classLoader = classLoader; + } + + @Override + SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes) { + final LinkedList matchingMethods = new LinkedList<>(); + for(MethodHandle method: methods) { + if(typeMatchesDescription(paramTypes, method.type())) { + matchingMethods.add(method); + } + } + switch(matchingMethods.size()) { + case 0: { + return null; + } + case 1: { + final MethodHandle target = matchingMethods.get(0); + return new SimpleDynamicMethod(target, SimpleDynamicMethod.getMethodNameWithSignature(target, getName())); + } + default: { + throw new BootstrapMethodError("Can't choose among " + matchingMethods + " for argument types " + + paramTypes + " for method " + getName()); + } + } + } + + @Override + public MethodHandle getInvocation(final MethodType callSiteType, final LinkerServices linkerServices) { + // First, find all methods applicable to the call site by subtyping (JLS 15.12.2.2) + final ApplicableOverloadedMethods subtypingApplicables = getApplicables(callSiteType, + ApplicableOverloadedMethods.APPLICABLE_BY_SUBTYPING); + // Next, find all methods applicable by method invocation conversion to the call site (JLS 15.12.2.3). + final ApplicableOverloadedMethods methodInvocationApplicables = getApplicables(callSiteType, + ApplicableOverloadedMethods.APPLICABLE_BY_METHOD_INVOCATION_CONVERSION); + // Finally, find all methods applicable by variable arity invocation. (JLS 15.12.2.4). + final ApplicableOverloadedMethods variableArityApplicables = getApplicables(callSiteType, + ApplicableOverloadedMethods.APPLICABLE_BY_VARIABLE_ARITY); + + // Find the methods that are maximally specific based on the call site signature + List maximallySpecifics = subtypingApplicables.findMaximallySpecificMethods(); + if(maximallySpecifics.isEmpty()) { + maximallySpecifics = methodInvocationApplicables.findMaximallySpecificMethods(); + if(maximallySpecifics.isEmpty()) { + maximallySpecifics = variableArityApplicables.findMaximallySpecificMethods(); + } + } + + // Now, get a list of the rest of the methods; those that are *not* applicable to the call site signature based + // on JLS rules. As paradoxical as that might sound, we have to consider these for dynamic invocation, as they + // might match more concrete types passed in invocations. That's why we provisionally call them "invokables". + // This is typical for very generic signatures at call sites. Typical example: call site specifies + // (Object, Object), and we have a method whose parameter types are (String, int). None of the JLS applicability + // rules will trigger, but we must consider the method, as it can be the right match for a concrete invocation. + @SuppressWarnings({ "unchecked", "rawtypes" }) + final List invokables = (List)methods.clone(); + invokables.removeAll(subtypingApplicables.getMethods()); + invokables.removeAll(methodInvocationApplicables.getMethods()); + invokables.removeAll(variableArityApplicables.getMethods()); + for(final Iterator it = invokables.iterator(); it.hasNext();) { + final MethodHandle m = it.next(); + if(!isApplicableDynamically(linkerServices, callSiteType, m)) { + it.remove(); + } + } + + // If no additional methods can apply at invocation time, and there's more than one maximally specific method + // based on call site signature, that is a link-time ambiguity. In a static scenario, javac would report an + // ambiguity error. + if(invokables.isEmpty() && maximallySpecifics.size() > 1) { + throw new BootstrapMethodError("Can't choose among " + maximallySpecifics + " for argument types " + + callSiteType); + } + + // Merge them all. + invokables.addAll(maximallySpecifics); + switch(invokables.size()) { + case 0: { + // No overloads can ever match the call site type + return null; + } + 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 a SimpleDynamicMethod. + final MethodHandle mh = invokables.iterator().next(); + return new SimpleDynamicMethod(mh).getInvocation(callSiteType, linkerServices); + } + default: { + // We have more than one candidate. We have no choice but to link to a method that resolves overloads on + // every invocation (alternatively, we could opportunistically link the one method that resolves for the + // current arguments, but we'd need to install a fairly complex guard for that and when it'd fail, we'd + // go back all the way to candidate selection. + // TODO: cache per call site type + return new OverloadedMethod(invokables, this, callSiteType, linkerServices).getInvoker(); + } + } + + } + + @Override + public boolean contains(MethodHandle mh) { + final MethodType type = mh.type(); + for(MethodHandle method: methods) { + if(typesEqualNoReceiver(type, method.type())) { + return true; + } + } + return false; + } + + private static boolean typesEqualNoReceiver(MethodType type1, MethodType type2) { + final int pc = type1.parameterCount(); + if(pc != type2.parameterCount()) { + return false; + } + for(int i = 1; i < pc; ++i) { // i = 1: ignore receiver + if(type1.parameterType(i) != type2.parameterType(i)) { + return false; + } + } + return true; + } + + ClassLoader getClassLoader() { + return classLoader; + } + + private static boolean isApplicableDynamically(LinkerServices linkerServices, MethodType callSiteType, + MethodHandle m) { + final MethodType methodType = m.type(); + final boolean varArgs = m.isVarargsCollector(); + final int fixedArgLen = methodType.parameterCount() - (varArgs ? 1 : 0); + final int callSiteArgLen = callSiteType.parameterCount(); + + // Arity checks + if(varArgs) { + if(callSiteArgLen < fixedArgLen) { + return false; + } + } else if(callSiteArgLen != fixedArgLen) { + return false; + } + + // Fixed arguments type checks, starting from 1, as receiver type doesn't participate + for(int i = 1; i < fixedArgLen; ++i) { + if(!isApplicableDynamically(linkerServices, callSiteType.parameterType(i), methodType.parameterType(i))) { + return false; + } + } + if(!varArgs) { + // Not vararg; both arity and types matched. + return true; + } + + final Class varArgArrayType = methodType.parameterType(fixedArgLen); + final Class varArgType = varArgArrayType.getComponentType(); + + if(fixedArgLen == callSiteArgLen - 1) { + // Exactly one vararg; check both array type matching and array component type matching. + final Class callSiteArgType = callSiteType.parameterType(fixedArgLen); + return isApplicableDynamically(linkerServices, callSiteArgType, varArgArrayType) + || isApplicableDynamically(linkerServices, callSiteArgType, varArgType); + } + + // Either zero, or more than one vararg; check if all actual vararg types match the vararg array component type. + for(int i = fixedArgLen; i < callSiteArgLen; ++i) { + if(!isApplicableDynamically(linkerServices, callSiteType.parameterType(i), varArgType)) { + return false; + } + } + + return true; + } + + private static boolean isApplicableDynamically(LinkerServices linkerServices, Class callSiteType, + Class methodType) { + return TypeUtilities.isPotentiallyConvertible(callSiteType, methodType) + || linkerServices.canConvert(callSiteType, methodType); + } + + private ApplicableOverloadedMethods getApplicables(MethodType callSiteType, ApplicabilityTest test) { + return new ApplicableOverloadedMethods(methods, callSiteType, test); + } + + /** + * Add a method identified by a {@link SimpleDynamicMethod} to this overloaded method's set. + * + * @param method the method to add. + */ + void addMethod(SimpleDynamicMethod method) { + addMethod(method.getTarget()); + } + + /** + * Add a method to this overloaded method's set. + * + * @param method a method to add + */ + public void addMethod(MethodHandle method) { + methods.add(method); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java b/nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java new file mode 100644 index 00000000000..d001516284f --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java @@ -0,0 +1,265 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.support.Lookup; + +/** + * Represents a subset of overloaded methods for a certain method name on a certain class. It can be either a fixarg or + * a vararg subset depending on the subclass. The method is for a fixed number of arguments though (as it is generated + * for a concrete call site). As such, all methods in the subset can be invoked with the specified number of arguments + * (exactly matching for fixargs, or having less than or equal fixed arguments, for varargs). + * + * @author Attila Szegedi + */ +class OverloadedMethod { + private final Map argTypesToMethods = new ConcurrentHashMap<>(); + private final OverloadedDynamicMethod parent; + private final MethodType callSiteType; + private final MethodHandle invoker; + private final LinkerServices linkerServices; + private final ArrayList fixArgMethods; + private final ArrayList varArgMethods; + + OverloadedMethod(List methodHandles, OverloadedDynamicMethod parent, MethodType callSiteType, + LinkerServices linkerServices) { + this.parent = parent; + this.callSiteType = callSiteType; + this.linkerServices = linkerServices; + + fixArgMethods = new ArrayList<>(methodHandles.size()); + varArgMethods = new ArrayList<>(methodHandles.size()); + final int argNum = callSiteType.parameterCount(); + for(MethodHandle mh: methodHandles) { + if(mh.isVarargsCollector()) { + final MethodHandle asFixed = mh.asFixedArity(); + if(argNum == asFixed.type().parameterCount()) { + fixArgMethods.add(asFixed); + } + varArgMethods.add(mh); + } else { + fixArgMethods.add(mh); + } + } + fixArgMethods.trimToSize(); + varArgMethods.trimToSize(); + + final MethodHandle bound = SELECT_METHOD.bindTo(this); + final MethodHandle collecting = SimpleDynamicMethod.collectArguments(bound, argNum).asType( + callSiteType.changeReturnType(MethodHandle.class)); + invoker = MethodHandles.foldArguments(MethodHandles.exactInvoker(callSiteType), collecting); + } + + MethodHandle getInvoker() { + return invoker; + } + + private static final MethodHandle SELECT_METHOD = Lookup.findOwnSpecial(MethodHandles.lookup(), "selectMethod", + MethodHandle.class, Object[].class); + + @SuppressWarnings("unused") + private MethodHandle selectMethod(Object[] args) throws NoSuchMethodException { + final Class[] argTypes = new Class[args.length]; + for(int i = 0; i < argTypes.length; ++i) { + final Object arg = args[i]; + argTypes[i] = arg == null ? callSiteType.parameterType(i) : arg.getClass(); + } + final ClassString classString = new ClassString(argTypes); + MethodHandle method = argTypesToMethods.get(classString); + if(method == null) { + List methods = classString.getMaximallySpecifics(fixArgMethods, linkerServices, false); + if(methods.isEmpty()) { + methods = classString.getMaximallySpecifics(varArgMethods, linkerServices, true); + } + switch(methods.size()) { + case 0: { + method = getNoSuchMethodThrower(argTypes); + break; + } + case 1: { + method = new SimpleDynamicMethod(methods.get(0)).getInvocation(callSiteType, linkerServices); + break; + } + default: { + // This is unfortunate - invocation time ambiguity. We can still save the day if + method = getAmbiguousMethodThrower(argTypes, methods); + break; + } + } + // Avoid keeping references to unrelated classes; this ruins the performance a bit, but avoids class loader + // memory leaks. + if(classString.isVisibleFrom(parent.getClassLoader())) { + argTypesToMethods.put(classString, method); + } + } + return method; + } + + private MethodHandle getNoSuchMethodThrower(Class[] argTypes) { + return adaptThrower(MethodHandles.insertArguments(THROW_NO_SUCH_METHOD, 0, this, argTypes)); + } + + private static final MethodHandle THROW_NO_SUCH_METHOD = Lookup.findOwnSpecial(MethodHandles.lookup(), + "throwNoSuchMethod", void.class, Class[].class); + + @SuppressWarnings("unused") + private void throwNoSuchMethod(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)); + } + throw new NoSuchMethodException("None of the fixed arity signatures " + getSignatureList(fixArgMethods) + + " or the variable arity signatures " + getSignatureList(varArgMethods) + " of the method " + + parent.getName() + " match the argument types " + argTypesString(argTypes)); + } + + private MethodHandle getAmbiguousMethodThrower(Class[] argTypes, List methods) { + return adaptThrower(MethodHandles.insertArguments(THROW_AMBIGUOUS_METHOD, 0, this, argTypes, methods)); + } + + private MethodHandle adaptThrower(MethodHandle rawThrower) { + return MethodHandles.dropArguments(rawThrower, 0, callSiteType.parameterList()).asType(callSiteType); + } + + private static final MethodHandle THROW_AMBIGUOUS_METHOD = Lookup.findOwnSpecial(MethodHandles.lookup(), + "throwAmbiguousMethod", void.class, Class[].class, List.class); + + @SuppressWarnings("unused") + private void throwAmbiguousMethod(Class[] argTypes, List 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) { + final StringBuilder b = new StringBuilder().append('['); + appendTypes(b, classes, false); + return b.append(']').toString(); + } + + private static String getSignatureList(List methods) { + final StringBuilder b = new StringBuilder().append('['); + final Iterator it = methods.iterator(); + if(it.hasNext()) { + appendSig(b, it.next()); + while(it.hasNext()) { + appendSig(b.append(", "), it.next()); + } + } + return b.append(']').toString(); + } + + private static void appendSig(StringBuilder b, MethodHandle m) { + b.append('('); + appendTypes(b, m.type().parameterArray(), m.isVarargsCollector()); + b.append(')'); + } + + private static void appendTypes(StringBuilder b, Class[] classes, boolean varArg) { + final int l = classes.length; + if(!varArg) { + if(l > 1) { + b.append(classes[1].getCanonicalName()); + for(int i = 2; i < l; ++i) { + b.append(", ").append(classes[i].getCanonicalName()); + } + } + } else { + for(int i = 1; i < l - 1; ++i) { + b.append(classes[i].getCanonicalName()).append(", "); + } + b.append(classes[l - 1].getComponentType().getCanonicalName()).append("..."); + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/SafeUnreflector.java b/nashorn/src/jdk/internal/dynalink/beans/SafeUnreflector.java new file mode 100644 index 00000000000..e82870128ce --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/SafeUnreflector.java @@ -0,0 +1,156 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; +import jdk.internal.dynalink.beans.sandbox.Unreflector; + +/** + * Provides lookup of unreflected method handles through delegation to an instance of {@link SafeUnreflectorImpl}. If + * Dynalink is run as trusted code, the delegate class is loaded into an isolated zero-permissions protection domain, + * serving as a firebreak against an accidental privilege escalation downstream. + */ +final class SafeUnreflector { + private static final String UNREFLECTOR_IMPL_CLASS_NAME = "jdk.internal.dynalink.beans.SafeUnreflectorImpl"; + private static final Unreflector impl = createImpl(); + + private SafeUnreflector() { + } + + /** + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)}, converting any encountered + * {@link IllegalAccessException} into an {@link IllegalAccessError}. + * + * @param m the method to unreflect + * @return the unreflected method handle. + */ + static MethodHandle unreflect(Method m) { + return impl.unreflect(m); + } + + /** + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter(Field)}, converting any encountered + * {@link IllegalAccessException} into an {@link IllegalAccessError}. + * + * @param f the field for which a getter is unreflected + * @return the unreflected field getter handle. + */ + static MethodHandle unreflectGetter(Field f) { + return impl.unreflectGetter(f); + } + + /** + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectSetter(Field)}, converting any encountered + * {@link IllegalAccessException} into an {@link IllegalAccessError}. + * + * @param f the field for which a setter is unreflected + * @return the unreflected field setter handle. + */ + static MethodHandle unreflectSetter(Field f) { + return impl.unreflectSetter(f); + } + + static MethodHandle unreflectConstructor(Constructor c) { + return impl.unreflectConstructor(c); + } + + private static Unreflector createImpl() { + final Class unreflectorImplClass = AccessController.doPrivileged(new PrivilegedAction>() { + @Override + public Class run() { + return SandboxClassLoader.loadClass(UNREFLECTOR_IMPL_CLASS_NAME); + } + }); + try { + return (Unreflector)unreflectorImplClass.newInstance(); + } catch(InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e.getMessage(), e); + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/SafeUnreflectorImpl.java b/nashorn/src/jdk/internal/dynalink/beans/SafeUnreflectorImpl.java new file mode 100644 index 00000000000..5ae843041bd --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/SafeUnreflectorImpl.java @@ -0,0 +1,146 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import jdk.internal.dynalink.beans.sandbox.Unreflector; + +/** + * Performs lookup of unreflected method handles by delegating to {@link MethodHandles#lookup()} using itself as the + * lookup class. When Dynalink runs as trusted code, this class is loaded into an isolated zero-permissions protection + * domain to stop any accidental privilege escalation. + */ +final class SafeUnreflectorImpl implements Unreflector { + + SafeUnreflectorImpl() { + } + + @Override + public MethodHandle unreflect(Method m) { + try { + return MethodHandles.lookup().unreflect(m); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect method " + m); + ee.initCause(e); + throw ee; + } + } + + @Override + public MethodHandle unreflectGetter(Field f) { + try { + return MethodHandles.lookup().unreflectGetter(f); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect getter for field " + f); + ee.initCause(e); + throw ee; + } + } + + @Override + public MethodHandle unreflectSetter(Field f) { + try { + return MethodHandles.lookup().unreflectSetter(f); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect setter for field " + f); + ee.initCause(e); + throw ee; + } + } + + @Override + public MethodHandle unreflectConstructor(Constructor c) { + try { + return MethodHandles.lookup().unreflectConstructor(c); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect constructor " + c); + ee.initCause(e); + throw ee; + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/SandboxClassLoader.java b/nashorn/src/jdk/internal/dynalink/beans/SandboxClassLoader.java new file mode 100644 index 00000000000..00f1e7ac794 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/SandboxClassLoader.java @@ -0,0 +1,228 @@ +/* + * 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.beans; + +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static jdk.internal.org.objectweb.asm.Opcodes.ASM4; + +import java.io.IOException; +import java.io.InputStream; +import java.security.Permissions; +import java.security.ProtectionDomain; +import java.security.SecureClassLoader; +import java.security.SecureRandom; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.MethodVisitor; + +/** + * A utility class that can load a class with specified name into an isolated zero-permissions protection domain. It can + * be used to load classes that perform security-sensitive operations with no privileges at all, therefore ensuring such + * operations will only succeed if they would require no permissions, as well as to make sure that if these operations + * bind some part of the security execution context to their results, the bound security context is completely + * unprivileged. Such measures serve as firebreaks against accidental privilege escalation. + */ +final class SandboxClassLoader { + private final String className; + private final String randomizedClassName; + + private SandboxClassLoader(String className) { + this.className = className; + final String simpleClassName = className.substring(className.lastIndexOf('.') + 1); + this.randomizedClassName = "randomPackage" + Long.toHexString(new SecureRandom().nextLong()) + "." + simpleClassName; + } + + /** + * Load the named class into a zero-permissions protection domain. Even if the class is already loaded into the + * Dynalink's class loader, an independent class is created from the same bytecode, thus the returned class will + * never be identical with the one that might already be loaded. The class to be loaded is supposed to be package + * private and have no public constructors. This is not a functional requirement, but it is enforced to ensure that + * the original class was made adequately inaccessible. The returned class will be public and its constructors will + * be changed to public. The only permission given to the returned class will be + * {@code accessClassInPackage.jdk.internal.dynalink.beans.sandbox}. That package should be used solely to define + * SPI interfaces implemented by the loaded class. + * @param className the fully qualified name of the class to load + * @return the loaded class, renamed to a random package, made public, its constructors made public, and lacking any + * permissions except access to the sandbox package. + * @throws SecurityException if the calling code lacks the {@code createClassLoader} runtime permission. This + * normally means that Dynalink itself is running as untrusted code, and whatever functionality was meant to be + * isolated into an unprivileged class is likely okay to be used directly too. + */ + static Class loadClass(String className) throws SecurityException { + return new SandboxClassLoader(className).loadClass(); + } + + private Class loadClass() throws SecurityException { + final ClassLoader loader = createClassLoader(); + try { + final Class clazz = Class.forName(randomizedClassName, true, loader); + // Sanity check to ensure we didn't accidentally pick up the class from elsewhere + if(clazz.getClassLoader() != loader) { + throw new AssertionError(randomizedClassName + " was loaded from a different class loader"); + } + return clazz; + } catch(ClassNotFoundException e) { + throw new AssertionError(e); + } + } + + private ClassLoader createClassLoader() throws SecurityException { + final String lclassName = this.randomizedClassName; + // We deliberately override loadClass instead of findClass so that we don't give a chance to finding this + // class already loaded anywhere else. We use this class' loader as the parent class loader as the loaded class + // needs to be able to access implemented interfaces from the sandbox package. + return new SecureClassLoader(getClass().getClassLoader()) { + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + if(name.equals(lclassName)) { + final byte[] bytes = getClassBytes(); + // Define the class with a protection domain that grants (almost) no permissions. + Class clazz = defineClass(name, bytes, 0, bytes.length, createMinimalPermissionsDomain()); + if(resolve) { + resolveClass(clazz); + } + return clazz; + } + + final int i = name.lastIndexOf('.'); + if (i != -1) { + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPackageAccess(name.substring(0, i)); + } + } + return super.loadClass(name, resolve); + } + }; + } + + /** + * Create a no-permissions protection domain. Except, it's not really a no-permissions protection domain, since we + * need to give the protection domain the permission to access the sandbox package where the interop interfaces are + * defined. + * @return a new (almost) no-permission protection domain. + */ + private static ProtectionDomain createMinimalPermissionsDomain() { + final Permissions p = new Permissions(); + p.add(new RuntimePermission("accessClassInPackage.jdk.internal.dynalink.beans.sandbox")); + return new ProtectionDomain(null, p); + } + + private byte[] getClassBytes() { + try(final InputStream in = getClass().getResourceAsStream("/" + className.replace('.', '/') + ".class")) { + final ClassReader cr = new ClassReader(in); + final ClassWriter cw = new ClassWriter(cr, 0); + cr.accept(new ClassVisitor(ASM4, cw) { + @Override + public void visit(int version, int access, String name, String signature, String superName, + String[] interfaces) { + // Rename the class to its random name, and make it public (otherwise we won't be able to + // instantiate it). The privileged template class is package-private. + if((access & ACC_PUBLIC) != 0) { + throw new IllegalArgumentException("Class " + className + " must be package-private"); + } + super.visit(version, access | ACC_PUBLIC, randomizedClassName.replace('.', '/'), + signature, superName, interfaces); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, + String[] exceptions) { + // Make the constructor(s) public (otherwise we won't be able to instantiate the class). The + // privileged template's constructor(s) should not be public. + final boolean isCtor = "".equals(name); + if(isCtor && ((access & ACC_PUBLIC) != 0)) { + throw new IllegalArgumentException("Class " + className + " must have no public constructors"); + } + return super.visitMethod(isCtor ? (access | ACC_PUBLIC) : access, name, desc, signature, + exceptions); + } + }, 0); + return cw.toByteArray(); + } catch(IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java b/nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java new file mode 100644 index 00000000000..1fbf7dbb1a0 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java @@ -0,0 +1,239 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Array; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.support.Guards; + +/** + * A dynamic method bound to exactly one, non-overloaded Java method. Handles varargs. + * + * @author Attila Szegedi + */ +class SimpleDynamicMethod extends DynamicMethod { + private final MethodHandle target; + + /** + * Creates a simple dynamic method with no name. + * @param target the target method handle + */ + SimpleDynamicMethod(MethodHandle target) { + this(target, null); + } + + /** + * Creates a new simple dynamic method, with a name constructed from the class name, method name, and handle + * signature. + * + * @param target the target method handle + * @param clazz the class declaring the method + * @param name the simple name of the method + */ + SimpleDynamicMethod(MethodHandle target, Class clazz, String name) { + this(target, getName(target, clazz, name)); + } + + SimpleDynamicMethod(MethodHandle target, String name) { + super(name); + this.target = target; + } + + private static String getName(MethodHandle target, Class clazz, String name) { + return getMethodNameWithSignature(target, getClassAndMethodName(clazz, name)); + } + + static String getMethodNameWithSignature(MethodHandle target, String methodName) { + final String typeStr = target.type().toString(); + final int retTypeIndex = typeStr.lastIndexOf(')') + 1; + int secondParamIndex = typeStr.indexOf(',') + 1; + if(secondParamIndex == 0) { + secondParamIndex = retTypeIndex - 1; + } + return typeStr.substring(retTypeIndex) + " " + methodName + "(" + typeStr.substring(secondParamIndex, retTypeIndex); + } + + /** + * Returns the target of this dynamic method + * + * @return the target of this dynamic method + */ + MethodHandle getTarget() { + return target; + } + + @Override + SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes) { + return typeMatchesDescription(paramTypes, target.type()) ? this : null; + } + + @Override + MethodHandle getInvocation(MethodType callSiteType, LinkerServices linkerServices) { + final MethodType methodType = target.type(); + final int paramsLen = methodType.parameterCount(); + final boolean varArgs = target.isVarargsCollector(); + final MethodHandle fixTarget = varArgs ? target.asFixedArity() : target; + final int fixParamsLen = varArgs ? paramsLen - 1 : paramsLen; + final int argsLen = callSiteType.parameterCount(); + if(argsLen < fixParamsLen) { + // Less actual arguments than number of fixed declared arguments; can't invoke. + return null; + } + // Method handle has the same number of fixed arguments as the call site type + if(argsLen == fixParamsLen) { + // Method handle that matches the number of actual arguments as the number of fixed arguments + final MethodHandle matchedMethod; + if(varArgs) { + // If vararg, add a zero-length array of the expected type as the last argument to signify no variable + // arguments. + matchedMethod = MethodHandles.insertArguments(fixTarget, fixParamsLen, Array.newInstance( + methodType.parameterType(fixParamsLen).getComponentType(), 0)); + } else { + // Otherwise, just use the method + matchedMethod = fixTarget; + } + return createConvertingInvocation(matchedMethod, linkerServices, callSiteType); + } + + // What's below only works for varargs + if(!varArgs) { + return null; + } + + final Class varArgType = methodType.parameterType(fixParamsLen); + // Handle a somewhat sinister corner case: caller passes exactly one argument in the vararg position, and we + // must handle both a prepacked vararg array as well as a genuine 1-long vararg sequence. + if(argsLen == paramsLen) { + final Class callSiteLastArgType = callSiteType.parameterType(fixParamsLen); + if(varArgType.isAssignableFrom(callSiteLastArgType)) { + // Call site signature guarantees we'll always be passed a single compatible array; just link directly + // to the method. + return createConvertingInvocation(fixTarget, linkerServices, callSiteType); + } + if(!linkerServices.canConvert(callSiteLastArgType, varArgType)) { + // Call site signature guarantees the argument can definitely not be an array (i.e. it is primitive); + // link immediately to a vararg-packing method handle. + return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType); + } + // Call site signature makes no guarantees that the single argument in the vararg position will be + // compatible across all invocations. Need to insert an appropriate guard and fall back to generic vararg + // method when it is not. + return MethodHandles.guardWithTest(Guards.isInstance(varArgType, fixParamsLen, callSiteType), + createConvertingInvocation(fixTarget, linkerServices, callSiteType), + createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType)); + } + + // Remaining case: more than one vararg. + return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType); + } + + @Override + public boolean contains(MethodHandle mh) { + return target.type().parameterList().equals(mh.type().parameterList()); + } + + /** + * Creates a method handle out of the original target that will collect the varargs for the exact component type of + * the varArg array. Note that this will nicely trigger language-specific type converters for exactly those varargs + * for which it is necessary when later passed to linkerServices.convertArguments(). + * + * @param target the original method handle + * @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) { + final MethodType methodType = target.type(); + final int fixParamsLen = methodType.parameterCount() - 1; + final Class arrayType = methodType.parameterType(fixParamsLen); + return target.asCollector(arrayType, parameterCount - fixParamsLen); + } + + private static MethodHandle createConvertingInvocation(final MethodHandle sizedMethod, + final LinkerServices linkerServices, final MethodType callSiteType) { + return linkerServices.asType(sizedMethod, callSiteType); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/StaticClass.java b/nashorn/src/jdk/internal/dynalink/beans/StaticClass.java new file mode 100644 index 00000000000..5008c211432 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClass.java @@ -0,0 +1,138 @@ +/* + * 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.beans; + +import java.io.Serializable; + +/** + * Object that represents the static facet of a class (its static methods, properties, and fields, as well as + * construction of instances using "dyn:new"). Objects of this class are recognized by the {@link BeansLinker} as being + * special, and operations on them will be linked against the represented class' static facet. The "class" synthetic + * property is additionally recognized and returns the Java {@link Class} object, as per {@link #getRepresentedClass()} + * method. Conversely, {@link Class} objects exposed through {@link BeansLinker} expose the "static" synthetic property + * which returns an instance of this class. + */ +public class StaticClass implements Serializable { + private static final ClassValue staticClasses = new ClassValue() { + @Override + protected StaticClass computeValue(Class type) { + return new StaticClass(type); + } + }; + + private static final long serialVersionUID = 1L; + + private final Class clazz; + + /*private*/ StaticClass(Class clazz) { + clazz.getClass(); // NPE check + this.clazz = clazz; + } + + /** + * Retrieves the {@link StaticClass} instance for the specified class. + * @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) { + return staticClasses.get(clazz); + } + + /** + * Returns the represented Java class. + * @return the represented Java class. + */ + public Class getRepresentedClass() { + return clazz; + } + + @Override + public String toString() { + return "JavaClassStatics[" + clazz.getName() + "]"; + } + + private Object readResolve() { + return forClass(clazz); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java b/nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java new file mode 100644 index 00000000000..d4cedb7f284 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java @@ -0,0 +1,117 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.HashMap; +import java.util.Map; + +class StaticClassIntrospector extends FacetIntrospector { + StaticClassIntrospector(Class clazz) { + super(clazz, false); + } + + @Override + Map getInnerClassGetters() { + final Map map = new HashMap<>(); + for(Class innerClass: membersLookup.getInnerClasses()) { + map.put(innerClass.getSimpleName(), editMethodHandle(MethodHandles.constant(StaticClass.class, + StaticClass.forClass(innerClass)))); + } + return map; + } + + @Override + MethodHandle editMethodHandle(MethodHandle mh) { + MethodHandle newHandle = MethodHandles.dropArguments(mh, 0, Object.class); + // NOTE: this is a workaround for the fact that dropArguments doesn't preserve vararg collector state. + if(mh.isVarargsCollector() && !newHandle.isVarargsCollector()) { + final MethodType type = mh.type(); + newHandle = newHandle.asVarargsCollector(type.parameterType(type.parameterCount() - 1)); + } + return newHandle; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java b/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java new file mode 100644 index 00000000000..c87d666732b --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java @@ -0,0 +1,203 @@ +/* + * 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.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.List; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.support.Lookup; + +/** + * Provides a linker for the {@link StaticClass} objects. + * @author Attila Szegedi + */ +class StaticClassLinker implements TypeBasedGuardingDynamicLinker { + private final ClassValue linkers = new ClassValue() { + @Override + protected GuardingDynamicLinker computeValue(Class clazz) { + return new SingleClassStaticsLinker(clazz); + } + }; + + private static class SingleClassStaticsLinker extends AbstractJavaLinker { + private final DynamicMethod constructor; + + SingleClassStaticsLinker(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. + setPropertyGetter("class", GET_CLASS, ValidationType.INSTANCE_OF); + constructor = createConstructorMethod(clazz); + } + + /** + * Creates a dynamic method containing all overloads of a class' public constructor + * @param clazz the target class + * @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) { + if(clazz.isArray()) { + final MethodHandle boundArrayCtor = ARRAY_CTOR.bindTo(clazz.getComponentType()); + return new SimpleDynamicMethod(drop(boundArrayCtor.asType(boundArrayCtor.type().changeReturnType( + clazz))), clazz, ""); + } + + final Constructor[] ctrs = clazz.getConstructors(); + final List mhs = new ArrayList<>(ctrs.length); + for(int i = 0; i < ctrs.length; ++i) { + mhs.add(drop(SafeUnreflector.unreflectConstructor(ctrs[i]))); + } + return createDynamicMethod(mhs, clazz, ""); + } + + private static MethodHandle drop(MethodHandle mh) { + return MethodHandles.dropArguments(mh, 0, StaticClass.class); + } + + @Override + FacetIntrospector createFacetIntrospector() { + return new StaticClassIntrospector(clazz); + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest request, LinkerServices linkerServices) + throws Exception { + final GuardedInvocation gi = super.getGuardedInvocation(request, linkerServices); + if(gi != null) { + return gi; + } + final CallSiteDescriptor desc = request.getCallSiteDescriptor(); + final String op = desc.getNameToken(CallSiteDescriptor.OPERATOR); + final MethodType methodType = desc.getMethodType(); + if("new" == op && constructor != null) { + final MethodHandle ctorInvocation = constructor.getInvocation(methodType, linkerServices); + if(ctorInvocation != null) { + return new GuardedInvocation(ctorInvocation, getClassGuard(methodType)); + } + } + return null; + } + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest request, LinkerServices linkerServices) throws Exception { + final Object receiver = request.getReceiver(); + if(receiver instanceof StaticClass) { + return linkers.get(((StaticClass)receiver).getRepresentedClass()).getGuardedInvocation(request, + linkerServices); + } + return null; + } + + @Override + public boolean canLinkType(Class type) { + return type == StaticClass.class; + } + + /*private*/ static final MethodHandle GET_CLASS = new Lookup(MethodHandles.lookup()).findVirtual(StaticClass.class, + "getRepresentedClass", MethodType.methodType(Class.class)); + + /*private*/ static final MethodHandle IS_CLASS = new Lookup(MethodHandles.lookup()).findStatic(StaticClassLinker.class, + "isClass", MethodType.methodType(Boolean.TYPE, Class.class, Object.class)); + + /*private*/ static final MethodHandle ARRAY_CTOR = Lookup.PUBLIC.findStatic(Array.class, "newInstance", + MethodType.methodType(Object.class, Class.class, int.class)); + + @SuppressWarnings("unused") + private static boolean isClass(Class clazz, Object obj) { + return obj instanceof StaticClass && ((StaticClass)obj).getRepresentedClass() == clazz; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/beans/messages.properties b/nashorn/src/jdk/internal/dynalink/beans/messages.properties new file mode 100644 index 00000000000..b930988c1b5 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/messages.properties @@ -0,0 +1,25 @@ +# Copyright 2009-2013 Attila Szegedi +# +# Licensed under either the Apache License, Version 2.0 (the "Apache +# License") or 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. +# +# A copy of the BSD License is available in the root directory of the +# source distribution of the project under the file name +# "Dynalink-License-BSD.txt". +# +# A copy of the Apache License is available in the root directory of the +# source distribution of the project under the file name +# "Dynalink-License-Apache-2.0.txt". Alternatively, you may obtain a +# copy of the Apache License at +# +# 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 your chosen License for the specific language governing permissions +# and limitations under that License. + +couldNotDiscoverAccessibleMethods=Could not discover accessible methods of class {0}, trying its superclasses and interfaces. \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/beans/package.html b/nashorn/src/jdk/internal/dynalink/beans/package.html new file mode 100644 index 00000000000..f405d1649e2 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/package.html @@ -0,0 +1,86 @@ + + + + +

+ Contains the linker for POJOs. +

+ diff --git a/nashorn/src/jdk/internal/dynalink/beans/sandbox/Unreflector.java b/nashorn/src/jdk/internal/dynalink/beans/sandbox/Unreflector.java new file mode 100644 index 00000000000..b5174cd3633 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/beans/sandbox/Unreflector.java @@ -0,0 +1,132 @@ +/* + * 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.beans.sandbox; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * Interface for creating unreflected method handles. This class is public for implementation purposes and is not part + * of any supported API. + */ +public interface Unreflector { + /** + * Performs similarly to {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)} for some lookup object, + * also converting any encountered {@link IllegalAccessException} into an {@link IllegalAccessError}. + * + * @param m the method to unreflect + * @return the unreflected method handle. + */ + public MethodHandle unreflect(Method m); + + /** + * Performs similarly to {@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter(Field)} for some lookup + * object, also converting any encountered {@link IllegalAccessException} into an {@link IllegalAccessError}. + * + * @param f the field for which a getter is unreflected + * @return the unreflected field getter handle. + */ + public MethodHandle unreflectGetter(Field f); + + /** + * Performs similarly to {@link java.lang.invoke.MethodHandles.Lookup#unreflectSetter(Field)} for some lookup + * object, also converting any encountered {@link IllegalAccessException} into an {@link IllegalAccessError}. + * + * @param f the field for which a setter is unreflected + * @return the unreflected field setter handle. + */ + public MethodHandle unreflectSetter(Field f); + + /** + * Performs similarly to {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)} for some + * lookup object, also converting any encountered {@link IllegalAccessException} into an {@link IllegalAccessError}. + * + * @param c the constructor to unreflect + * @return the unreflected constructor handle. + */ + public MethodHandle unreflectConstructor(Constructor c); + +} diff --git a/nashorn/src/jdk/internal/dynalink/linker/ConversionComparator.java b/nashorn/src/jdk/internal/dynalink/linker/ConversionComparator.java new file mode 100644 index 00000000000..8f2d1e0d0f7 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/linker/ConversionComparator.java @@ -0,0 +1,114 @@ +/* + * 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.linker; + + +/** + * Optional interface to be implemented by {@link GuardingTypeConverterFactory} implementers. Language-specific + * conversions can cause increased overloaded method resolution ambiguity, as many methods can become applicable because + * of additional conversions. The static way of selecting the "most specific" method will fail more often, because there + * will be multiple maximally specific method with unrelated signatures. In these cases, language runtimes can be asked + * to resolve the ambiguity by expressing preferences for one conversion over the other. + * @author Attila Szegedi + */ +public interface ConversionComparator { + /** + * Enumeration of possible outcomes of comparing one conversion to another. + */ + enum Comparison { + INDETERMINATE, + TYPE_1_BETTER, + TYPE_2_BETTER, + } + + /** + * Determines which of the two target types is the preferred conversion target from a source type. + * @param sourceType the source type. + * @param targetType1 one potential target type + * @param targetType2 another potential target type. + * @return one of Comparison constants that establish which - if any - of the target types is preferred for the + * conversion. + */ + public Comparison compareConversion(Class sourceType, Class targetType1, Class targetType2); +} diff --git a/nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java b/nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java new file mode 100644 index 00000000000..26a741e8288 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java @@ -0,0 +1,314 @@ +/* + * 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.linker; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.SwitchPoint; +import java.lang.invoke.WrongMethodTypeException; +import java.util.List; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.support.Guards; + +/** + * Represents a conditionally valid method handle. It is an immutable triple of an invocation method handle, a guard + * method handle that defines the applicability of the invocation handle, and a switch point that can be used for + * external invalidation of the invocation handle. The invocation handle is suitable for invocation if the guard + * handle returns true for its arguments, and as long as the switch point is not invalidated. Both the guard and the + * switch point are optional; neither, one, or both can be present. + * + * @author Attila Szegedi + */ +public class GuardedInvocation { + private final MethodHandle invocation; + private final MethodHandle guard; + private final SwitchPoint switchPoint; + + /** + * 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 to represent + * an unconditional invocation, although that is unusual. + * @throws NullPointerException if invocation is null. + */ + public GuardedInvocation(MethodHandle invocation, MethodHandle guard) { + this(invocation, guard, 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. + * @throws NullPointerException if invocation is null. + */ + public GuardedInvocation(MethodHandle invocation, MethodHandle guard, SwitchPoint switchPoint) { + invocation.getClass(); // NPE check + this.invocation = invocation; + this.guard = guard; + this.switchPoint = switchPoint; + } + + /** + * 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. + * @throws NullPointerException if invocation is null. + */ + public GuardedInvocation(MethodHandle invocation, SwitchPoint switchPoint, MethodHandle guard) { + this(invocation, guard, switchPoint); + } + /** + * Returns the invocation method handle. + * + * @return the invocation method handle. It will never be null. + */ + public MethodHandle getInvocation() { + return invocation; + } + + /** + * Returns the guard method handle. + * + * @return the guard method handle. Can be null. + */ + public MethodHandle getGuard() { + return guard; + } + + /** + * Returns the switch point that can be used to invalidate the invocation handle. + * + * @return the switch point that can be used to invalidate the invocation handle. Can be null. + */ + public SwitchPoint getSwitchPoint() { + return switchPoint; + } + + /** + * Returns true if and only if this guarded invocation has a switchpoint, and that switchpoint has been invalidated. + * @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(); + } + + /** + * Asserts that the invocation is of the specified type, and the guard (if present) is of the specified type with a + * boolean return type. + * + * @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) { + assertType(invocation, type); + if(guard != null) { + assertType(guard, type.changeReturnType(Boolean.TYPE)); + } + } + + /** + * Creates a new guarded invocation with different methods, preserving the switch point. + * + * @param newInvocation the new invocation + * @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); + } + + private GuardedInvocation replaceMethodsOrThis(MethodHandle newInvocation, MethodHandle newGuard) { + if(newInvocation == invocation && newGuard == guard) { + return this; + } + return replaceMethods(newInvocation, newGuard); + } + + /** + * 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, and parameter count potentially truncated for + * the guard). If the invocation already is of the required type, returns this object. + * @param newType the new type of the invocation. + * @return a guarded invocation with the new type applied to it. + */ + public GuardedInvocation asType(MethodType newType) { + return replaceMethodsOrThis(invocation.asType(newType), guard == null ? null : Guards.asType(guard, newType)); + } + + /** + * Changes the type of the invocation, as if {@link LinkerServices#asType(MethodHandle, MethodType)} was applied to + * its invocation and its guard, if it has one (with return type changed to boolean, and parameter count potentially + * truncated for the guard). If the invocation already is of the required 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 asType(LinkerServices linkerServices, 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 MethodHandle#asType(MethodType)} was applied to its invocation + * and its guard, if it has one (with return type changed to boolean for guard). If the invocation already is of the + * required type, returns this object. + * @param desc a call descriptor whose method type is adapted. + * @return a guarded invocation with the new type applied to it. + */ + public GuardedInvocation asType(CallSiteDescriptor desc) { + return asType(desc.getMethodType()); + } + + /** + * Applies argument filters to both the invocation and the guard (if there is one). + * @param pos the position of the first argumen being filtered + * @param filters the argument filters + * @return a filtered invocation + */ + public GuardedInvocation filterArguments(int pos, MethodHandle... filters) { + return replaceMethods(MethodHandles.filterArguments(invocation, pos, filters), guard == null ? null : + MethodHandles.filterArguments(guard, pos, filters)); + } + + /** + * Makes an invocation that drops arguments in both the invocation and the guard (if there is one). + * @param pos the position of the first argument being dropped + * @param valueTypes the types of the values being dropped + * @return an invocation that drops arguments + */ + public GuardedInvocation dropArguments(int pos, List> valueTypes) { + return replaceMethods(MethodHandles.dropArguments(invocation, pos, valueTypes), guard == null ? null : + MethodHandles.dropArguments(guard, pos, valueTypes)); + } + + /** + * Makes an invocation that drops arguments in both the invocation and the guard (if there is one). + * @param pos the position of the first argument being dropped + * @param valueTypes the types of the values being dropped + * @return an invocation that drops arguments + */ + public GuardedInvocation dropArguments(int pos, Class... valueTypes) { + return replaceMethods(MethodHandles.dropArguments(invocation, pos, valueTypes), guard == null ? null : + MethodHandles.dropArguments(guard, pos, valueTypes)); + } + + + /** + * Composes the invocation, switchpoint, and the guard into a composite method handle that knows how to fall back. + * @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); + } + + /** + * 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. + * @return a composite method handle. + */ + public MethodHandle compose(MethodHandle switchpointFallback, MethodHandle guardFallback) { + final MethodHandle guarded = + guard == null ? invocation : MethodHandles.guardWithTest(guard, invocation, guardFallback); + return switchPoint == null ? guarded : switchPoint.guardWithTest(guarded, switchpointFallback); + } + + private static void assertType(MethodHandle mh, MethodType type) { + if(!mh.type().equals(type)) { + throw new WrongMethodTypeException("Expected type: " + type + " actual type: " + mh.type()); + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/linker/GuardingDynamicLinker.java b/nashorn/src/jdk/internal/dynalink/linker/GuardingDynamicLinker.java new file mode 100644 index 00000000000..2cd0d0f04d1 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/linker/GuardingDynamicLinker.java @@ -0,0 +1,112 @@ +/* + * 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.linker; + +/** + * The base interface for language-specific dynamic linkers. Such linkers always have to produce method handles with + * guards, as the validity of the method handle for calls at a call site inevitably depends on some condition (at the + * very least, it depends on the receiver belonging to the language runtime of the linker). Language runtime + * implementors will normally implement one for their own language, and declare it in the + * META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker file within their JAR file. + * + * @author Attila Szegedi + */ +public interface GuardingDynamicLinker { + /** + * Creates a guarded invocation appropriate for a particular invocation with the specified arguments at a call site. + * + * @param linkRequest the object describing the request for linking a particular invocation + * @param linkerServices linker services + * @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. + * @throws Exception if the operation fails for whatever reason + */ + public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, LinkerServices linkerServices) + throws Exception; +} diff --git a/nashorn/src/jdk/internal/dynalink/linker/GuardingTypeConverterFactory.java b/nashorn/src/jdk/internal/dynalink/linker/GuardingTypeConverterFactory.java new file mode 100644 index 00000000000..30ab9467ec4 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/linker/GuardingTypeConverterFactory.java @@ -0,0 +1,114 @@ +/* + * 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.linker; + +import jdk.internal.dynalink.support.TypeUtilities; + +/** + * Optional interface that can be implemented by {@link GuardingDynamicLinker} implementations to provide + * language-runtime specific implicit type conversion capabilities. Note that if you implement this interface, you will + * very likely want to implement {@link ConversionComparator} interface too, as your additional language-specific + * conversions, in absence of a strategy for prioritizing these conversions, will cause more ambiguity in selecting the + * correct overload when trying to link to an overloaded POJO method. + * + * @author Attila Szegedi + */ +public interface GuardingTypeConverterFactory { + /** + * Returns a guarded invocation that receives an Object of the specified source type and returns an Object converted + * to the specified target type. The type of the invocation is targetType(sourceType), while the type of the guard + * is boolean(sourceType). Note that this will never be invoked for type conversions allowed by the JLS 5.3 "Method + * Invocation Conversion", see {@link TypeUtilities#isMethodInvocationConvertible(Class, Class)} for details. An + * implementation can assume it is never requested to produce a converter for these conversions. + * + * @param sourceType source type + * @param targetType the target type. + * @return a guarded invocation that can take an object (if it passes guard) and returns another object that is its + * representation coerced into the target type. In case the factory is certain it is unable to handle a conversion, + * it can return null. In case the factory is certain that it can always handle the conversion, it can return an + * unconditional invocation (one whose guard is null). + * @throws Exception if there was an error during creation of the converter + */ + public GuardedInvocation convertToType(Class sourceType, Class targetType) throws Exception; +} diff --git a/nashorn/src/jdk/internal/dynalink/linker/LinkRequest.java b/nashorn/src/jdk/internal/dynalink/linker/LinkRequest.java new file mode 100644 index 00000000000..1a82a4fab7b --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/linker/LinkRequest.java @@ -0,0 +1,149 @@ +/* + * 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.linker; + +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.DynamicLinkerFactory; + +/** + * Represents a request to link a particular invocation at a particular call site. Instances of these requests are being + * passed to {@link GuardingDynamicLinker}. + * + * @author Attila Szegedi + */ +public interface LinkRequest { + /** + * Returns the call site descriptor for the call site being linked. + * + * @return the call site descriptor for the call site being linked. + */ + public CallSiteDescriptor getCallSiteDescriptor(); + + /** + * 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. + * + * @return the arguments for the invocation being linked. + */ + public Object[] getArguments(); + + /** + * Returns the 0th argument for the invocation being linked; this is typically the receiver object. + * + * @return the receiver object. + */ + public Object getReceiver(); + + /** + * 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 + * hint to prefer producing linkage that is more stable (its guard fails less frequently), even if that assumption + * causes a less effective version of an operation to be linked. This is just a hint, of course, and linkers are + * free to ignore this property. + * @return true if the call site is considered unstable. + */ + public boolean isCallSiteUnstable(); + + /** + * Returns a request stripped from runtime context arguments. Some language runtimes will include runtime-specific + * context parameters in their call sites as few arguments between 0th argument "this" and the normal arguments. If + * a linker does not recognize such contexts at all, or does not recognize the call site as one with its own + * context, it can ask for the alternative link request with context parameters and arguments removed, and link + * against it instead. + * + * @return the context-stripped request. If the link request does not have any language runtime specific context + * parameters, the same link request is returned. + */ + public LinkRequest withoutRuntimeContext(); + + /** + * Returns a request identical to this one with call site descriptor and arguments replaced with the ones specified. + * + * @param callSiteDescriptor the new call site descriptor + * @param arguments the new arguments + * @return a new request identical to this one, except with the call site descriptor and arguments replaced with the + * specified ones. + */ + public LinkRequest replaceArguments(CallSiteDescriptor callSiteDescriptor, Object[] arguments); +} diff --git a/nashorn/src/jdk/internal/dynalink/linker/LinkerServices.java b/nashorn/src/jdk/internal/dynalink/linker/LinkerServices.java new file mode 100644 index 00000000000..deaf820f11b --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/linker/LinkerServices.java @@ -0,0 +1,164 @@ +/* + * 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.linker; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.DynamicLinker; +import jdk.internal.dynalink.linker.ConversionComparator.Comparison; + +/** + * Interface for services provided to {@link GuardingDynamicLinker} instances by the {@link DynamicLinker} that owns + * them. You can think of it as the interface of the {@link DynamicLinker} that faces the {@link GuardingDynamicLinker} + * s. + * + * @author Attila Szegedi + */ +public interface LinkerServices { + /** + * Similar to {@link MethodHandle#asType(MethodType)} except it also hooks in method handles produced by + * {@link GuardingTypeConverterFactory} implementations, providing for language-specific type coercing of + * 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. + * + * @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 asType(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 + * this method directly; you should mostly rely on {@link #asType(MethodHandle, MethodType)} instead. You really + * only need this method if you have a piece of your program that is written in Java, and you need to reuse existing + * type conversion machinery in a non-invokedynamic context. + * @param sourceType the type to convert from + * @param targetType the type to convert to + * @return a method handle performing the conversion. + */ + public MethodHandle getTypeConverter(Class sourceType, Class targetType); + + /** + * Returns true if there might exist a conversion between the requested types (either an automatic JVM conversion, + * or one provided by any available {@link GuardingTypeConverterFactory}), or false if there definitely does not + * exist a conversion between the requested types. Note that returning true does not guarantee that the conversion + * will succeed at runtime (notably, if the "from" or "to" types are sufficiently generic), but returning false + * guarantees that it would fail. + * + * @param from the source type for the conversion + * @param to the target type for the conversion + * @return true if there can be a conversion, false if there can not. + */ + public boolean canConvert(Class from, Class to); + + /** + * Creates a guarded invocation using the {@link DynamicLinker} that exposes this linker services interface. Linkers + * can typically use them to delegate linking of wrapped objects. + * + * @param linkRequest a request for linking the invocation + * @return a guarded invocation linked by the top-level linker (or any of its delegates). Can be null if no + * available linker is able to link the invocation. + * @throws Exception in case the top-level linker throws an exception + */ + public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest) throws Exception; + + /** + * Determines which of the two type conversions from a source type to the two target types is preferred. This is + * used for dynamic overloaded method resolution. If the source type is convertible to exactly one target type with + * a method invocation conversion, it is chosen, otherwise available {@link ConversionComparator}s are consulted. + * @param sourceType the source type. + * @param targetType1 one potential target type + * @param targetType2 another potential target type. + * @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); +} diff --git a/nashorn/src/jdk/internal/dynalink/linker/TypeBasedGuardingDynamicLinker.java b/nashorn/src/jdk/internal/dynalink/linker/TypeBasedGuardingDynamicLinker.java new file mode 100644 index 00000000000..c7fac02d500 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/linker/TypeBasedGuardingDynamicLinker.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.linker; + +/** + * A guarding dynamic linker that can determine whether it can link the call site solely based on the type of the first + * argument at linking invocation time. (The first argument is usually the receiver class). Most language-specific + * linkers will fall into this category, as they recognize their native objects as Java objects of classes implementing + * a specific language-native interface or superclass. The linker mechanism can optimize the dispatch for these linkers. + * + * @author Attila Szegedi + */ +public interface TypeBasedGuardingDynamicLinker extends GuardingDynamicLinker { + /** + * Returns true if the linker can link an invocation where the first argument (receiver) is of the specified type. + * + * @param type the type to link + * @return true if the linker can link calls for the receiver type, or false otherwise. + */ + public boolean canLinkType(Class type); +} diff --git a/nashorn/src/jdk/internal/dynalink/linker/package.html b/nashorn/src/jdk/internal/dynalink/linker/package.html new file mode 100644 index 00000000000..4e3991d7614 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/linker/package.html @@ -0,0 +1,87 @@ + + + + +

+ Contains interfaces and classes needed by language runtimes to implement + their own language-specific linkers. +

+ diff --git a/nashorn/src/jdk/internal/dynalink/package.html b/nashorn/src/jdk/internal/dynalink/package.html new file mode 100644 index 00000000000..588823ac8c3 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/package.html @@ -0,0 +1,93 @@ + + + + +

+ Contains the main API for using the dynamic linking facilities. A + scripting framework or a language runtime that does not define its own + linker but only uses linkers available in the system will only need to + use classes and interfaces from this package. +

+

+ Languages that wish to define and use their own linkers will also need to + use the {@link jdk.internal.dynalink.linker} package. +

+ diff --git a/nashorn/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java b/nashorn/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java new file mode 100644 index 00000000000..e51f6fe2f2a --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java @@ -0,0 +1,185 @@ +/* + * 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 java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.util.Objects; +import jdk.internal.dynalink.CallSiteDescriptor; + +/** + * A base class for call site descriptor implementations. Provides reconstruction of the name from the tokens, as well + * as a generally useful {@code equals} and {@code hashCode} methods. + * @author Attila Szegedi + */ +public abstract class AbstractCallSiteDescriptor implements CallSiteDescriptor { + + @Override + public String getName() { + return appendName(new StringBuilder(getNameLength())).toString(); + } + + @Override + public Lookup getLookup() { + return MethodHandles.publicLookup(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof CallSiteDescriptor && equals((CallSiteDescriptor)obj); + } + + /** + * Returns true if this call site descriptor is equal to the passed call site descriptor. + * @param csd the other call site descriptor. + * @return true if they are equal. + */ + public boolean equals(CallSiteDescriptor csd) { + if(csd == null) { + return false; + } + if(csd == this) { + return true; + } + final int ntc = getNameTokenCount(); + if(ntc != csd.getNameTokenCount()) { + return false; + } + for(int i = ntc; i-- > 0;) { // Reverse order as variability is higher at the end + if(!Objects.equals(getNameToken(i), csd.getNameToken(i))) { + return false; + } + } + if(!getMethodType().equals(csd.getMethodType())) { + return false; + } + return lookupsEqual(getLookup(), csd.getLookup()); + } + + @Override + public int hashCode() { + final int c = getNameTokenCount(); + int h = 0; + for(int i = 0; i < c; ++i) { + h = h * 31 + getNameToken(i).hashCode(); + } + return h * 31 + getMethodType().hashCode(); + } + + @Override + public String toString() { + final String mt = getMethodType().toString(); + final String l = getLookup().toString(); + final StringBuilder b = new StringBuilder(l.length() + 1 + mt.length() + getNameLength()); + return appendName(b).append(mt).append("@").append(l).toString(); + } + + private int getNameLength() { + final int c = getNameTokenCount(); + int l = 0; + for(int i = 0; i < c; ++i) { + l += getNameToken(i).length(); + } + return l + c - 1; + } + + private StringBuilder appendName(StringBuilder b) { + b.append(getNameToken(0)); + final int c = getNameTokenCount(); + for(int i = 1; i < c; ++i) { + b.append(':').append(getNameToken(i)); + } + return b; + } + + private static boolean lookupsEqual(Lookup l1, Lookup l2) { + if(l1 == l2) { + return true; + } + if(l1.lookupClass() != l2.lookupClass()) { + return false; + } + return l1.lookupModes() == l2.lookupModes(); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/AbstractRelinkableCallSite.java b/nashorn/src/jdk/internal/dynalink/support/AbstractRelinkableCallSite.java new file mode 100644 index 00000000000..c05d35e0948 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/AbstractRelinkableCallSite.java @@ -0,0 +1,117 @@ +/* + * 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 java.lang.invoke.MethodHandle; +import java.lang.invoke.MutableCallSite; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.RelinkableCallSite; + +/** + * A basic implementation of the {@link RelinkableCallSite} as a {@link MutableCallSite} subclass. + * + * @author Attila Szegedi + */ +public abstract class AbstractRelinkableCallSite extends MutableCallSite implements RelinkableCallSite { + private final CallSiteDescriptor descriptor; + + /** + * Creates a new relinkable call site. + * @param descriptor the descriptor for this call site + */ + protected AbstractRelinkableCallSite(CallSiteDescriptor descriptor) { + super(descriptor.getMethodType()); + this.descriptor = descriptor; + } + + @Override + public CallSiteDescriptor getDescriptor() { + return descriptor; + } + + @Override + public void initialize(MethodHandle relinkAndInvoke) { + setTarget(relinkAndInvoke); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/AutoDiscovery.java b/nashorn/src/jdk/internal/dynalink/support/AutoDiscovery.java new file mode 100644 index 00000000000..2909365935b --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/AutoDiscovery.java @@ -0,0 +1,133 @@ +/* + * 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 java.util.LinkedList; +import java.util.List; +import java.util.ServiceLoader; +import jdk.internal.dynalink.DynamicLinkerFactory; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; + +/** + * Provides methods for automatic discovery of all guarding dynamic linkers listed in the + * /META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker resources of all JAR files for a + * particular class loader. Ordinarily, you will not use this class directly, but you will use a + * {@link DynamicLinkerFactory} instead. + */ +public class AutoDiscovery { + + private AutoDiscovery() { + } + + /** + * Discovers all guarding dynamic linkers listed in JAR files of the context class loader of the current thread. + * + * @return a list of available linkers. Can be zero-length list but not null. + */ + public static List loadLinkers() { + return getLinkers(ServiceLoader.load(GuardingDynamicLinker.class)); + } + + /** + * Discovers all guarding dynamic linkers listed in JAR files of the specified class loader. + * + * @param cl the class loader to use + * @return a list of guarding dynamic linkers available through the specified class loader. Can be zero-length list + * but not null. + */ + public static List loadLinkers(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 List getLinkers(ServiceLoader loader) { + final List list = new LinkedList<>(); + for(final T linker: loader) { + list.add(linker); + } + return list; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/Backport.java b/nashorn/src/jdk/internal/dynalink/support/Backport.java new file mode 100644 index 00000000000..1be7dc32acc --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/Backport.java @@ -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 java.lang.invoke.MethodHandles; + +/** + * @author Attila Szegedi + */ +public class Backport { + /** + * True if Remi's JSR-292 backport agent is active; false if we're using native OpenJDK JSR-292 support. + */ + public static final boolean inUse = MethodHandles.class.getName().startsWith("jsr292"); + + private Backport() { + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/BottomGuardingDynamicLinker.java b/nashorn/src/jdk/internal/dynalink/support/BottomGuardingDynamicLinker.java new file mode 100644 index 00000000000..7a2700e10ff --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/BottomGuardingDynamicLinker.java @@ -0,0 +1,116 @@ +/* + * 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.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; + +/** + * A linker that can't link any call site. Only used internally by {@link CompositeTypeBasedGuardingDynamicLinker}. Can + * be used by other language runtimes if they need it though. + * + * @author Attila Szegedi + */ +public class BottomGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker { + + /** + * The sole instance of this stateless linker. + */ + public static final BottomGuardingDynamicLinker INSTANCE = new BottomGuardingDynamicLinker(); + + private BottomGuardingDynamicLinker() { + } + + @Override + public boolean canLinkType(Class type) { + return false; + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, LinkerServices linkerServices) { + return null; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/CallSiteDescriptorFactory.java b/nashorn/src/jdk/internal/dynalink/support/CallSiteDescriptorFactory.java new file mode 100644 index 00000000000..b0039d21c2c --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/CallSiteDescriptorFactory.java @@ -0,0 +1,263 @@ +/* + * 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 java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import java.lang.ref.WeakReference; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.StringTokenizer; +import java.util.WeakHashMap; +import jdk.internal.dynalink.CallSiteDescriptor; + +/** + * Usable as a default factory for call site descriptor implementations. It is weakly canonicalizing, meaning it will + * return the same immutable call site descriptor for identical inputs, i.e. repeated requests for a descriptor + * signifying public lookup for "dyn:getProp:color" of type "Object(Object)" will return the same object as long as + * a previously created, at least softly reachable one exists. It also uses several different implementations of the + * {@link CallSiteDescriptor} internally, and chooses the most space-efficient one based on the input. + * @author Attila Szegedi + */ +public class CallSiteDescriptorFactory { + private static final WeakHashMap> publicDescs = + new WeakHashMap<>(); + + + private CallSiteDescriptorFactory() { + } + + /** + * Creates a new call site descriptor instance. The actual underlying class of the instance is dependent on the + * passed arguments to be space efficient; i.e. if you only use the public lookup, you'll get back an + * implementation that doesn't waste space on storing the lookup object. + * @param lookup the lookup that determines access rights at the call site. If your language runtime doesn't have + * equivalents of Java access concepts, just use {@link MethodHandles#publicLookup()}. Must not be null. + * @param name the name of the method at the call site. Must not be null. + * @param methodType the type of the method at the call site. Must not be null. + * @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) { + name.getClass(); // NPE check + methodType.getClass(); // NPE check + lookup.getClass(); // NPE check + final String[] tokenizedName = tokenizeName(name); + if(isPublicLookup(lookup)) { + return getCanonicalPublicDescriptor(createPublicCallSiteDescriptor(tokenizedName, methodType)); + } + return new LookupCallSiteDescriptor(tokenizedName, methodType, lookup); + } + + static CallSiteDescriptor getCanonicalPublicDescriptor(final CallSiteDescriptor desc) { + synchronized(publicDescs) { + final WeakReference ref = publicDescs.get(desc); + if(ref != null) { + final CallSiteDescriptor canonical = ref.get(); + if(canonical != null) { + return canonical; + } + } + publicDescs.put(desc, new WeakReference<>(desc)); + } + return desc; + } + + private static CallSiteDescriptor createPublicCallSiteDescriptor(String[] tokenizedName, MethodType methodType) { + final int l = tokenizedName.length; + if(l > 0 && tokenizedName[0] == "dyn") { + if(l == 2) { + return new UnnamedDynCallSiteDescriptor(tokenizedName[1], methodType); + } if (l == 3) { + return new NamedDynCallSiteDescriptor(tokenizedName[1], tokenizedName[2], methodType); + } + } + return new DefaultCallSiteDescriptor(tokenizedName, methodType); + } + + private static boolean isPublicLookup(Lookup lookup) { + return lookup == MethodHandles.publicLookup(); + } + + /** + * Tokenizes the composite name along colons, as well as {@link NameCodec#decode(String) demangles} and interns + * the tokens. The first two tokens are not demangled as they are supposed to be the naming scheme and the name of + * the operation which can be expected to consist of just alphabetical characters. + * @param name the composite name consisting of colon-separated, possibly mangled tokens. + * @return an array of tokens + */ + public static String[] tokenizeName(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) { + String token = tok.nextToken(); + if(i > 1) { + token = NameCodec.decode(token); + } + tokens[i] = token.intern(); + } + return tokens; + } + + /** + * Tokenizes a composite operation name along pipe characters. I.e. if you have a "dyn:getElem|getProp|getMethod" + * operation, returns a list of ["getElem", "getProp", "getMethod"]. The tokens are not interned. + * @param desc the call site descriptor with the operation + * @return a list of tokens + */ + public static List tokenizeOperators(CallSiteDescriptor desc) { + final String ops = desc.getNameToken(CallSiteDescriptor.OPERATOR); + final StringTokenizer tok = new StringTokenizer(ops, CallSiteDescriptor.OPERATOR_DELIMITER); + final int count = tok.countTokens(); + if(count == 1) { + return Collections.singletonList(ops); + } + final String[] tokens = new String[count]; + for(int i = 0; i < count; ++i) { + tokens[i] = tok.nextToken(); + } + return Arrays.asList(tokens); + } + + /** + * Returns a new call site descriptor that is identical to the passed one, except that it has some parameter types + * removed from its method type. + * @param desc the original call site descriptor + * @param start index of the first parameter to remove + * @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) { + return desc.changeMethodType(desc.getMethodType().dropParameterTypes(start, end)); + } + + /** + * Returns a new call site descriptor that is identical to the passed one, except that it has a single parameter + * type changed in its method type. + * @param desc the original call site descriptor + * @param num index of the parameter to change + * @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) { + return desc.changeMethodType(desc.getMethodType().changeParameterType(num, nptype)); + } + + /** + * Returns a new call site descriptor that is identical to the passed one, except that it has the return type + * changed in its method type. + * @param desc the original call site descriptor + * @param nrtype the new return type + * @return a new call site descriptor with modified method type + */ + public static CallSiteDescriptor changeReturnType(CallSiteDescriptor desc, Class nrtype) { + return desc.changeMethodType(desc.getMethodType().changeReturnType(nrtype)); + } + + /** + * Returns a new call site descriptor that is identical to the passed one, except that it has additional parameter + * types inserted into its method type. + * @param desc the original call site descriptor + * @param num index at which the new parameters are inserted + * @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) { + return desc.changeMethodType(desc.getMethodType().insertParameterTypes(num, ptypesToInsert)); + } + + /** + * Returns a new call site descriptor that is identical to the passed one, except that it has additional parameter + * types inserted into its method type. + * @param desc the original call site descriptor + * @param num index at which the new parameters are inserted + * @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> ptypesToInsert) { + return desc.changeMethodType(desc.getMethodType().insertParameterTypes(num, ptypesToInsert)); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/ClassMap.java b/nashorn/src/jdk/internal/dynalink/support/ClassMap.java new file mode 100644 index 00000000000..7369d2557cf --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/ClassMap.java @@ -0,0 +1,177 @@ +/* + * 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 java.lang.ref.Reference; +import java.lang.ref.SoftReference; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * A dual map that can either strongly or weakly reference a given class depending on whether the class is visible from + * a class loader or not. + * + * @author Attila Szegedi + * @param the type of the values in the map + */ +public abstract class ClassMap { + private final ConcurrentMap, T> map = new ConcurrentHashMap<>(); + private final Map, Reference> weakMap = new WeakHashMap<>(); + private final ClassLoader classLoader; + + /** + * Creates a new class map. It will use strong references for all keys and values where the key is a class visible + * from the class loader, and will use weak keys and soft values for all other classes. + * + * @param classLoader the classloader that determines strong referenceability. + */ + protected ClassMap(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + /** + * Compute the value associated with the given class. It is possible that the method will be invoked several times + * (or even concurrently) for the same class parameter. + * + * @param clazz the class to compute the value for + * @return the return value. Must not be null. + */ + protected abstract T computeValue(Class clazz); + + /** + * Returns the class loader that governs the strong referenceability of this class map. + * + * @return the class loader that governs the strong referenceability of this class map. + */ + public ClassLoader getClassLoader() { + return classLoader; + } + + /** + * Returns the value associated with the class + * + * @param clazz the class + * @return the value associated with the class + */ + public T get(Class clazz) { + // Check in fastest first - objects we're allowed to strongly reference + final T v = map.get(clazz); + if(v != null) { + return v; + } + // Check objects we're not allowed to strongly reference + Reference ref; + synchronized(weakMap) { + ref = weakMap.get(clazz); + } + if(ref != null) { + final T refv = ref.get(); + if(refv != null) { + return refv; + } + } + // Not found in either place; create a new value + final T newV = computeValue(clazz); + assert newV != null; + // If allowed to strongly reference, put it in the fast map + if(Guards.canReferenceDirectly(classLoader, clazz.getClassLoader())) { + final T oldV = map.putIfAbsent(clazz, newV); + return oldV != null ? oldV : newV; + } + // Otherwise, put it into the weak map + synchronized(weakMap) { + ref = weakMap.get(clazz); + if(ref != null) { + final T oldV = ref.get(); + if(oldV != null) { + return oldV; + } + } + weakMap.put(clazz, new SoftReference<>(newV)); + return newV; + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/CompositeGuardingDynamicLinker.java b/nashorn/src/jdk/internal/dynalink/support/CompositeGuardingDynamicLinker.java new file mode 100644 index 00000000000..44f5c4b3874 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/CompositeGuardingDynamicLinker.java @@ -0,0 +1,131 @@ +/* + * 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 java.io.Serializable; +import java.util.LinkedList; +import java.util.List; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; + +/** + * A {@link GuardingDynamicLinker} that delegates sequentially to a list of other guarding dynamic linkers. The first + * value returned from a component linker other than null is returned. If no component linker returns an invocation, + * null is returned. + * + * @author Attila Szegedi + */ +public class CompositeGuardingDynamicLinker implements GuardingDynamicLinker, Serializable { + + private static final long serialVersionUID = 1L; + + private final GuardingDynamicLinker[] linkers; + + /** + * Creates a new composite linker. + * + * @param linkers a list of component linkers. + */ + public CompositeGuardingDynamicLinker(Iterable linkers) { + final List l = new LinkedList<>(); + for(GuardingDynamicLinker linker: linkers) { + l.add(linker); + } + this.linkers = l.toArray(new GuardingDynamicLinker[l.size()]); + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, final LinkerServices linkerServices) + throws Exception { + for(final GuardingDynamicLinker linker: linkers) { + final GuardedInvocation invocation = linker.getGuardedInvocation(linkRequest, linkerServices); + if(invocation != null) { + return invocation; + } + } + return null; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/CompositeTypeBasedGuardingDynamicLinker.java b/nashorn/src/jdk/internal/dynalink/support/CompositeTypeBasedGuardingDynamicLinker.java new file mode 100644 index 00000000000..180ab0c6b1a --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/CompositeTypeBasedGuardingDynamicLinker.java @@ -0,0 +1,225 @@ +/* + * 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 java.io.Serializable; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; + +/** + * A composite type-based guarding dynamic linker. When a receiver of a not yet seen class is encountered, all linkers + * are queried sequentially on their {@link TypeBasedGuardingDynamicLinker#canLinkType(Class)} method. The linkers + * returning true are then bound to the class, and next time a receiver of same type is encountered, the linking is + * delegated to those linkers only, speeding up dispatch. + * + * @author Attila Szegedi + */ +public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker, Serializable { + private static final long serialVersionUID = 1L; + + // Using a separate static class instance so there's no strong reference from the class value back to the composite + // linker. + private static class ClassToLinker extends ClassValue> { + private static final List NO_LINKER = Collections.emptyList(); + private final TypeBasedGuardingDynamicLinker[] linkers; + private final List[] singletonLinkers; + + @SuppressWarnings("unchecked") + ClassToLinker(TypeBasedGuardingDynamicLinker[] linkers) { + this.linkers = linkers; + singletonLinkers = new List[linkers.length]; + for(int i = 0; i < linkers.length; ++i) { + singletonLinkers[i] = Collections.singletonList(linkers[i]); + } + } + + @Override + protected List computeValue(Class clazz) { + List list = NO_LINKER; + for(int i = 0; i < linkers.length; ++i) { + final TypeBasedGuardingDynamicLinker linker = linkers[i]; + if(linker.canLinkType(clazz)) { + switch(list.size()) { + case 0: { + list = singletonLinkers[i]; + break; + } + case 1: { + list = new LinkedList<>(list); + } + //$FALL-THROUGH$ + default: { + list.add(linker); + } + } + } + } + return list; + } + } + + private final ClassValue> classToLinker; + + /** + * Creates a new composite type-based linker. + * + * @param linkers the component linkers + */ + public CompositeTypeBasedGuardingDynamicLinker(Iterable linkers) { + final List l = new LinkedList<>(); + for(TypeBasedGuardingDynamicLinker linker: linkers) { + l.add(linker); + } + this.classToLinker = new ClassToLinker(l.toArray(new TypeBasedGuardingDynamicLinker[l.size()])); + } + + @Override + public boolean canLinkType(Class type) { + return !classToLinker.get(type).isEmpty(); + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, final LinkerServices linkerServices) + throws Exception { + final Object obj = linkRequest.getReceiver(); + if(obj == null) { + return null; + } + for(TypeBasedGuardingDynamicLinker linker: classToLinker.get(obj.getClass())) { + final GuardedInvocation invocation = linker.getGuardedInvocation(linkRequest, linkerServices); + if(invocation != null) { + return invocation; + } + } + return null; + } + + /** + * Optimizes a list of type-based linkers. If a group of adjacent linkers in the list all implement + * {@link TypeBasedGuardingDynamicLinker}, they will be replaced with a single instance of + * {@link CompositeTypeBasedGuardingDynamicLinker} that contains them. + * + * @param linkers the list of linkers to optimize + * @return the optimized list + */ + public static List optimize(Iterable linkers) { + final List llinkers = new LinkedList<>(); + final List tblinkers = new LinkedList<>(); + for(GuardingDynamicLinker linker: linkers) { + if(linker instanceof TypeBasedGuardingDynamicLinker) { + tblinkers.add((TypeBasedGuardingDynamicLinker)linker); + } else { + addTypeBased(llinkers, tblinkers); + llinkers.add(linker); + } + } + addTypeBased(llinkers, tblinkers); + return llinkers; + } + + private static void addTypeBased(List llinkers, + List tblinkers) { + switch(tblinkers.size()) { + case 0: { + break; + } + case 1: { + llinkers.addAll(tblinkers); + tblinkers.clear(); + break; + } + default: { + llinkers.add(new CompositeTypeBasedGuardingDynamicLinker(tblinkers)); + tblinkers.clear(); + break; + } + } + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/DefaultCallSiteDescriptor.java b/nashorn/src/jdk/internal/dynalink/support/DefaultCallSiteDescriptor.java new file mode 100644 index 00000000000..46d4fc8bba9 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/DefaultCallSiteDescriptor.java @@ -0,0 +1,134 @@ +/* + * 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 java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.CallSiteDescriptor; + +/** + * A default, fairly light implementation of a call site descriptor used for describing non-standard operations. It does + * not store {@link Lookup} objects but always returns the public lookup from its {@link #getLookup()} method. If you + * need to support non-public lookup, you can use {@link LookupCallSiteDescriptor}. + * @author Attila Szegedi + */ +class DefaultCallSiteDescriptor extends AbstractCallSiteDescriptor { + + private final String[] tokenizedName; + private final MethodType methodType; + + DefaultCallSiteDescriptor(String[] tokenizedName, MethodType methodType) { + this.tokenizedName = tokenizedName; + this.methodType = methodType; + } + + @Override + public int getNameTokenCount() { + return tokenizedName.length; + } + + @Override + public String getNameToken(int i) { + try { + return tokenizedName[i]; + } catch(ArrayIndexOutOfBoundsException e) { + throw new IllegalArgumentException(e.getMessage()); + } + } + + String[] getTokenizedName() { + return tokenizedName; + } + + @Override + public MethodType getMethodType() { + return methodType; + } + + @Override + public CallSiteDescriptor changeMethodType(MethodType newMethodType) { + return CallSiteDescriptorFactory.getCanonicalPublicDescriptor(new DefaultCallSiteDescriptor(tokenizedName, + newMethodType)); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/Guards.java b/nashorn/src/jdk/internal/dynalink/support/Guards.java new file mode 100644 index 00000000000..bab6e1dc6ca --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/Guards.java @@ -0,0 +1,359 @@ +/* + * 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 java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.logging.Level; +import java.util.logging.Logger; +import jdk.internal.dynalink.linker.LinkerServices; + +/** + * Utility methods for creating typical guards. TODO: introduce reasonable caching of created guards. + * + * @author Attila Szegedi + */ +public class Guards { + private static final Logger LOG = Logger + .getLogger(Guards.class.getName(), "jdk.internal.dynalink.support.messages"); + + private Guards() { + } + + /** + * Creates a guard method handle with arguments of a specified type, but with boolean return value. When invoked, it + * returns true if the first argument is of the specified class (exactly of it, not a subclass). The rest of the + * arguments will be ignored. + * + * @param clazz the class of the first argument to test for + * @param type the method type + * @return a method handle testing whether its first argument is of the specified class. + */ + @SuppressWarnings("boxing") + public static MethodHandle isOfClass(Class clazz, MethodType type) { + final Class declaredType = type.parameterType(0); + if(clazz == declaredType) { + LOG.log(Level.WARNING, "isOfClassGuardAlwaysTrue", new Object[] { clazz.getName(), 0, type }); + return constantTrue(type); + } + if(!declaredType.isAssignableFrom(clazz)) { + LOG.log(Level.WARNING, "isOfClassGuardAlwaysFalse", new Object[] { clazz.getName(), 0, type }); + return constantFalse(type); + } + return getClassBoundArgumentTest(IS_OF_CLASS, clazz, 0, type); + } + + /** + * Creates a method handle with arguments of a specified type, but with boolean return value. When invoked, it + * returns true if the first argument is instance of the specified class or its subclass). The rest of the arguments + * will be ignored. + * + * @param clazz the class of the first argument to test for + * @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) { + return isInstance(clazz, 0, type); + } + + /** + * Creates a method handle with arguments of a specified type, but with boolean return value. When invoked, it + * returns true if the n'th argument is instance of the specified class or its subclass). The rest of the arguments + * will be ignored. + * + * @param clazz the class of the first argument to test for + * @param pos the position on the argument list to test + * @param type the method type + * @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) { + final Class declaredType = type.parameterType(pos); + if(clazz.isAssignableFrom(declaredType)) { + LOG.log(Level.WARNING, "isInstanceGuardAlwaysTrue", new Object[] { clazz.getName(), pos, type }); + return constantTrue(type); + } + if(!declaredType.isAssignableFrom(clazz)) { + LOG.log(Level.WARNING, "isInstanceGuardAlwaysFalse", new Object[] { clazz.getName(), pos, type }); + return constantFalse(type); + } + return getClassBoundArgumentTest(IS_INSTANCE, clazz, pos, type); + } + + /** + * Creates a method handle that returns true if the argument in the specified position is a Java array. + * + * @param pos the position in the argument lit + * @param type the method type of the handle + * @return a method handle that returns true if the argument in the specified position is a Java array; the rest of + * the arguments are ignored. + */ + @SuppressWarnings("boxing") + public static MethodHandle isArray(int pos, MethodType type) { + final Class declaredType = type.parameterType(pos); + if(declaredType.isArray()) { + LOG.log(Level.WARNING, "isArrayGuardAlwaysTrue", new Object[] { pos, type }); + return constantTrue(type); + } + if(!declaredType.isAssignableFrom(Object[].class)) { + LOG.log(Level.WARNING, "isArrayGuardAlwaysFalse", new Object[] { pos, type }); + return constantFalse(type); + } + return asType(IS_ARRAY, pos, type); + } + + /** + * Return true if it is safe to strongly reference a class from the referred class loader from a class associated + * with the referring class loader without risking a class loader memory leak. + * + * @param referrerLoader the referrer class loader + * @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) { + if(referredLoader == null) { + // Can always refer directly to a system class + return true; + } + if(referrerLoader == null) { + // System classes can't refer directly to any non-system class + return false; + } + // Otherwise, can only refer directly to classes residing in same or + // parent class loader. + + ClassLoader referrer = referrerLoader; + do { + if(referrer == referredLoader) { + return true; + } + referrer = referrer.getParent(); + } while(referrer != null); + return false; + } + + private static MethodHandle getClassBoundArgumentTest(MethodHandle test, Class clazz, int pos, MethodType type) { + // Bind the class to the first argument of the test + return asType(test.bindTo(clazz), pos, type); + } + + /** + * Takes a guard-test method handle, and adapts it to the requested type, returning a boolean. Only applies + * conversions as per {@link MethodHandle#asType(MethodType)}. + * @param test the test method handle + * @param type the type to adapt the method handle to + * @return the adapted method handle + */ + public static MethodHandle asType(MethodHandle test, MethodType type) { + return test.asType(getTestType(test, type)); + } + + /** + * Takes a guard-test method handle, and adapts it to the requested type, returning a boolean. Applies the passed + * {@link LinkerServices} object's {@link LinkerServices#asType(MethodHandle, MethodType)}. + * @param linkerServices the linker services to use for type conversions + * @param test the test method handle + * @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) { + return linkerServices.asType(test, getTestType(test, type)); + } + + private static MethodType getTestType(MethodHandle test, MethodType type) { + return type.dropParameterTypes(test.type().parameterCount(), + type.parameterCount()).changeReturnType(boolean.class); + } + + private static MethodHandle asType(MethodHandle test, int pos, MethodType type) { + assert test != null; + assert type != null; + assert type.parameterCount() > 0; + assert pos >= 0 && pos < type.parameterCount(); + assert test.type().parameterCount() == 1; + assert test.type().returnType() == Boolean.TYPE; + return MethodHandles.permuteArguments(test.asType(test.type().changeParameterType(0, type.parameterType(pos))), + type.changeReturnType(Boolean.TYPE), new int[] { pos }); + } + + private static final MethodHandle IS_OF_CLASS = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, + "isOfClass", MethodType.methodType(Boolean.TYPE, Class.class, Object.class)); + + private static final MethodHandle IS_INSTANCE = Lookup.PUBLIC.findVirtual(Class.class, "isInstance", + MethodType.methodType(Boolean.TYPE, Object.class)); + + private static final MethodHandle IS_ARRAY = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, "isArray", + MethodType.methodType(Boolean.TYPE, Object.class)); + + private static final MethodHandle IS_IDENTICAL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, + "isIdentical", MethodType.methodType(Boolean.TYPE, Object.class, Object.class)); + + private static final MethodHandle IS_NULL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, + "isNull", MethodType.methodType(Boolean.TYPE, Object.class)); + + private static final MethodHandle IS_NOT_NULL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, + "isNotNull", MethodType.methodType(Boolean.TYPE, Object.class)); + + /** + * Creates a guard method that tests its only argument for being of an exact particular class. + * @param clazz the class to test for. + * @return the desired guard method. + */ + public static MethodHandle getClassGuard(Class clazz) { + return IS_OF_CLASS.bindTo(clazz); + } + + /** + * Creates a guard method that tests its only argument for being an instance of a particular class. + * @param clazz the class to test for. + * @return the desired guard method. + */ + public static MethodHandle getInstanceOfGuard(Class clazz) { + return IS_INSTANCE.bindTo(clazz); + } + + /** + * Creates a guard method that tests its only argument for being referentially identical to another object + * @param obj the object used as referential identity test + * @return the desired guard method. + */ + public static MethodHandle getIdentityGuard(Object obj) { + return IS_IDENTICAL.bindTo(obj); + } + + /** + * Returns a guard that tests whether the first argument is null. + * @return a guard that tests whether the first argument is null. + */ + public static MethodHandle isNull() { + return IS_NULL; + } + + /** + * Returns a guard that tests whether the first argument is not null. + * @return a guard that tests whether the first argument is not null. + */ + public static MethodHandle isNotNull() { + return IS_NOT_NULL; + } + + @SuppressWarnings("unused") + private static boolean isNull(Object obj) { + return obj == null; + } + + @SuppressWarnings("unused") + private static boolean isNotNull(Object obj) { + return obj != null; + } + + @SuppressWarnings("unused") + private static boolean isArray(Object o) { + return o != null && o.getClass().isArray(); + } + + @SuppressWarnings("unused") + private static boolean isOfClass(Class c, Object o) { + return o != null && o.getClass() == c; + } + + @SuppressWarnings("unused") + private static boolean isIdentical(Object o1, Object o2) { + return o1 == o2; + } + + private static MethodHandle constantTrue(MethodType type) { + return constantBoolean(Boolean.TRUE, type); + } + + private static MethodHandle constantFalse(MethodType type) { + return constantBoolean(Boolean.FALSE, type); + } + + private static MethodHandle constantBoolean(Boolean value, MethodType type) { + return MethodHandles.permuteArguments(MethodHandles.constant(Boolean.TYPE, value), + type.changeReturnType(Boolean.TYPE)); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/LinkRequestImpl.java b/nashorn/src/jdk/internal/dynalink/support/LinkRequestImpl.java new file mode 100644 index 00000000000..c2b0092bf99 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/LinkRequestImpl.java @@ -0,0 +1,143 @@ +/* + * 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.CallSiteDescriptor; +import jdk.internal.dynalink.linker.LinkRequest; + +/** + * Default implementation of the {@link LinkRequest}, representing a link request to a call site that passes no language + * runtime specific native context arguments on the stack. + * + * @author Attila Szegedi + */ +public class LinkRequestImpl implements LinkRequest { + + private final CallSiteDescriptor callSiteDescriptor; + private final Object[] arguments; + private final boolean callSiteUnstable; + + /** + * Creates a new link request. + * + * @param callSiteDescriptor the descriptor for the call site being linked + * @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) { + this.callSiteDescriptor = callSiteDescriptor; + this.callSiteUnstable = callSiteUnstable; + this.arguments = arguments; + } + + @Override + public Object[] getArguments() { + return arguments != null ? arguments.clone() : null; + } + + @Override + public Object getReceiver() { + return arguments != null && arguments.length > 0 ? arguments[0] : null; + } + + @Override + public CallSiteDescriptor getCallSiteDescriptor() { + return callSiteDescriptor; + } + + @Override + public boolean isCallSiteUnstable() { + return callSiteUnstable; + } + + @Override + public LinkRequest withoutRuntimeContext() { + return this; + } + + @Override + public LinkRequest replaceArguments(CallSiteDescriptor newCallSiteDescriptor, Object[] newArguments) { + return new LinkRequestImpl(newCallSiteDescriptor, callSiteUnstable, newArguments); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/LinkerServicesImpl.java b/nashorn/src/jdk/internal/dynalink/support/LinkerServicesImpl.java new file mode 100644 index 00000000000..4eb0ca9da7e --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/LinkerServicesImpl.java @@ -0,0 +1,140 @@ +/* + * 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 java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.linker.ConversionComparator.Comparison; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingDynamicLinker; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; + +/** + * Default implementation of the {@link LinkerServices} interface. + * + * @author Attila Szegedi + */ +public class LinkerServicesImpl implements LinkerServices { + + private final TypeConverterFactory typeConverterFactory; + private final GuardingDynamicLinker topLevelLinker; + + /** + * Creates a new linker services object. + * + * @param typeConverterFactory the type converter factory exposed by the services. + * @param topLevelLinker the top level linker used by the services. + */ + public LinkerServicesImpl(final TypeConverterFactory typeConverterFactory, + final GuardingDynamicLinker topLevelLinker) { + this.typeConverterFactory = typeConverterFactory; + this.topLevelLinker = topLevelLinker; + } + + @Override + public boolean canConvert(Class from, Class to) { + return typeConverterFactory.canConvert(from, to); + } + + @Override + public MethodHandle asType(MethodHandle handle, MethodType fromType) { + return typeConverterFactory.asType(handle, fromType); + } + + @Override + public MethodHandle getTypeConverter(Class sourceType, Class targetType) { + return typeConverterFactory.getTypeConverter(sourceType, targetType); + } + + @Override + public Comparison compareConversion(Class sourceType, Class targetType1, Class targetType2) { + return typeConverterFactory.compareConversion(sourceType, targetType1, targetType2); + } + + @Override + public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest) throws Exception { + return topLevelLinker.getGuardedInvocation(linkRequest, this); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/Lookup.java b/nashorn/src/jdk/internal/dynalink/support/Lookup.java new file mode 100644 index 00000000000..52a610246a8 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/Lookup.java @@ -0,0 +1,360 @@ +/* + * 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 java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * A wrapper around MethodHandles.Lookup that masks checked exceptions in those cases when you're looking up methods + * within your own codebase (therefore it is an error if they are not present). + * + * @author Attila Szegedi + */ +public class Lookup { + private final MethodHandles.Lookup lookup; + + /** + * Creates a new instance, bound to an instance of {@link java.lang.invoke.MethodHandles.Lookup}. + * + * @param lookup the {@link java.lang.invoke.MethodHandles.Lookup} it delegates to. + */ + public Lookup(MethodHandles.Lookup lookup) { + this.lookup = lookup; + } + + /** + * A canonical Lookup object that wraps {@link MethodHandles#publicLookup()}. + */ + public static final Lookup PUBLIC = new Lookup(MethodHandles.publicLookup()); + + /** + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)}, converting any encountered + * {@link IllegalAccessException} into an {@link IllegalAccessError}. + * + * @param m the method to unreflect + * @return the unreflected method handle. + */ + public MethodHandle unreflect(Method m) { + try { + return lookup.unreflect(m); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect method " + m); + ee.initCause(e); + throw ee; + } + } + + + /** + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter(Field)}, converting any encountered + * {@link IllegalAccessException} into an {@link IllegalAccessError}. + * + * @param f the field for which a getter is unreflected + * @return the unreflected field getter handle. + */ + public MethodHandle unreflectGetter(Field f) { + try { + return lookup.unreflectGetter(f); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect getter for field " + f); + ee.initCause(e); + throw ee; + } + } + + /** + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#findGetter(Class, String, Class)}, converting any + * encountered {@link IllegalAccessException} into an {@link IllegalAccessError} and {@link NoSuchFieldException} + * into a {@link NoSuchFieldError}. + * + * @param refc the class declaring the field + * @param name the name of the field + * @param type the type of the field + * @return the unreflected field getter handle. + * @throws IllegalAccessError if the field is inaccessible. + * @throws NoSuchFieldError if the field does not exist. + */ + public MethodHandle findGetter(Classrefc, String name, Class type) { + try { + return lookup.findGetter(refc, name, type); + } catch(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) { + final NoSuchFieldError ee = new NoSuchFieldError("Failed to find getter for field " + refc.getName() + + "." + name + " of type " + type.getName()); + ee.initCause(e); + throw ee; + } + } + + /** + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectSetter(Field)}, converting any encountered + * {@link IllegalAccessException} into an {@link IllegalAccessError}. + * + * @param f the field for which a setter is unreflected + * @return the unreflected field setter handle. + */ + public MethodHandle unreflectSetter(Field f) { + try { + return lookup.unreflectSetter(f); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect setter for field " + f); + ee.initCause(e); + throw ee; + } + } + + /** + * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)}, converting any + * encountered {@link IllegalAccessException} into an {@link IllegalAccessError}. + * + * @param c the constructor to unreflect + * @return the unreflected constructor handle. + */ + public MethodHandle unreflectConstructor(Constructor c) { + try { + return lookup.unreflectConstructor(c); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to unreflect constructor " + c); + ee.initCause(e); + throw ee; + } + } + + /** + * Performs a findSpecial on the underlying lookup, except for the backport where it rather uses unreflect. Converts + * any encountered {@link IllegalAccessException} into an {@link IllegalAccessError} and a + * {@link NoSuchMethodException} into a {@link NoSuchMethodError}. + * + * @param declaringClass class declaring the method + * @param name the name of the method + * @param type the type of the method + * @return a method handle for the method + * @throws IllegalAccessError if the method is inaccessible. + * @throws NoSuchMethodError if the method does not exist. + */ + public MethodHandle findSpecial(Class declaringClass, String name, MethodType type) { + try { + if(Backport.inUse) { + final Method m = declaringClass.getDeclaredMethod(name, type.parameterArray()); + if(!Modifier.isPublic(declaringClass.getModifiers()) || !Modifier.isPublic(m.getModifiers())) { + m.setAccessible(true); + } + return unreflect(m); + } + return lookup.findSpecial(declaringClass, name, type, declaringClass); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to access special method " + methodDescription( + declaringClass, name, type)); + ee.initCause(e); + throw ee; + } catch(NoSuchMethodException e) { + final NoSuchMethodError ee = new NoSuchMethodError("Failed to find special method " + methodDescription( + declaringClass, name, type)); + ee.initCause(e); + throw ee; + } + } + + private static String methodDescription(Class declaringClass, String name, MethodType type) { + return declaringClass.getName() + "#" + name + type; + } + + /** + * Performs a findStatic on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an + * {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}. + * + * @param declaringClass class declaring the method + * @param name the name of the method + * @param type the type of the method + * @return a method handle for the method + * @throws IllegalAccessError if the method is inaccessible. + * @throws NoSuchMethodError if the method does not exist. + */ + public MethodHandle findStatic(Class declaringClass, String name, MethodType type) { + try { + return lookup.findStatic(declaringClass, name, type); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to access static method " + methodDescription( + declaringClass, name, type)); + ee.initCause(e); + throw ee; + } catch(NoSuchMethodException e) { + final NoSuchMethodError ee = new NoSuchMethodError("Failed to find static method " + methodDescription( + declaringClass, name, type)); + ee.initCause(e); + throw ee; + } + } + + /** + * Performs a findVirtual on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an + * {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}. + * + * @param declaringClass class declaring the method + * @param name the name of the method + * @param type the type of the method + * @return a method handle for the method + * @throws IllegalAccessError if the method is inaccessible. + * @throws NoSuchMethodError if the method does not exist. + */ + public MethodHandle findVirtual(Class declaringClass, String name, MethodType type) { + try { + return lookup.findVirtual(declaringClass, name, type); + } catch(IllegalAccessException e) { + final IllegalAccessError ee = new IllegalAccessError("Failed to access virtual method " + methodDescription( + declaringClass, name, type)); + ee.initCause(e); + throw ee; + } catch(NoSuchMethodException e) { + final NoSuchMethodError ee = new NoSuchMethodError("Failed to find virtual method " + methodDescription( + declaringClass, name, type)); + ee.initCause(e); + throw ee; + } + } + + /** + * Given a lookup, finds using {@link #findSpecial(Class, String, MethodType)} a method on that lookup's class. + * Useful in classes' code for convenient linking to their own privates. + * @param lookup the lookup for the class + * @param name the name of the method + * @param rtype the return type of the method + * @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) { + return new Lookup(lookup).findOwnSpecial(name, rtype, ptypes); + } + + + /** + * Finds using {@link #findSpecial(Class, String, MethodType)} a method on that lookup's class. Useful in classes' + * code for convenient linking to their own privates. It's easier to use than {@code findSpecial} in that you can + * just list the parameter types, and don't have to specify lookup class. + * @param name the name of the method + * @param rtype the return type of the method + * @param ptypes the parameter types of the method + * @return the method handle for the method + */ + public MethodHandle findOwnSpecial(String name, Class rtype, Class... ptypes) { + return findSpecial(lookup.lookupClass(), name, MethodType.methodType(rtype, ptypes)); + } + + /** + * Given a lookup, finds using {@link #findStatic(Class, String, MethodType)} a method on that lookup's class. + * Useful in classes' code for convenient linking to their own privates. It's easier to use than {@code findStatic} + * in that you can just list the parameter types, and don't have to specify lookup class. + * @param lookup the lookup for the class + * @param name the name of the method + * @param rtype the return type of the method + * @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) { + return new Lookup(lookup).findOwnStatic(name, rtype, ptypes); + } + + /** + * Finds using {@link #findStatic(Class, String, MethodType)} a method on that lookup's class. Useful in classes' + * code for convenient linking to their own privates. It's easier to use than {@code findStatic} in that you can + * just list the parameter types, and don't have to specify lookup class. + * @param name the name of the method + * @param rtype the return type of the method + * @param ptypes the parameter types of the method + * @return the method handle for the method + */ + public MethodHandle findOwnStatic(String name, Class rtype, Class... ptypes) { + return findStatic(lookup.lookupClass(), name, MethodType.methodType(rtype, ptypes)); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/LookupCallSiteDescriptor.java b/nashorn/src/jdk/internal/dynalink/support/LookupCallSiteDescriptor.java new file mode 100644 index 00000000000..bc5521bbfc7 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/LookupCallSiteDescriptor.java @@ -0,0 +1,117 @@ +/* + * 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 java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import jdk.internal.dynalink.CallSiteDescriptor; + +/** + * A call site descriptor that stores a specific {@link Lookup}. It does not, however, store static bootstrap arguments. + * @author Attila Szegedi + */ +class LookupCallSiteDescriptor extends DefaultCallSiteDescriptor { + private Lookup lookup; + + /** + * Create a new call site descriptor from explicit information. + * @param tokenizedName the name of the method + * @param methodType the method type + * @param lookup the lookup + */ + LookupCallSiteDescriptor(String[] tokenizedName, MethodType methodType, Lookup lookup) { + super(tokenizedName, methodType); + this.lookup = lookup; + } + + @Override + public Lookup getLookup() { + return lookup; + } + + @Override + public CallSiteDescriptor changeMethodType(MethodType newMethodType) { + return new LookupCallSiteDescriptor(getTokenizedName(), newMethodType, lookup); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/NameCodec.java b/nashorn/src/jdk/internal/dynalink/support/NameCodec.java new file mode 100644 index 00000000000..1c7cd29b95f --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/NameCodec.java @@ -0,0 +1,218 @@ +/* + * 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.CallSiteDescriptor; + +/** + * Implements the name mangling and demangling as specified by John Rose's + * "Symbolic Freedom in the + * VM" article. It is recommended that implementers of languages on the JVM uniformly adopt this for symbolic + * interoperability between languages. Normally, you would mangle the names as you're generating bytecode, and then + * demangle them when you're creating {@link CallSiteDescriptor} objects. Note that you are expected to mangle + * individual tokens, and not the whole name at the call site, i.e. the colon character normally separating the tokens + * is never mangled. I.e. you wouldn't mangle {@code dyn:getProp:color} into {@code dyn\!getProp\!color}, but you would + * mangle {@code dyn:getProp:color$} into {@code dyn:getProp:\=color\%} (only mangling the individual token containing + * the symbol {@code color$}). {@link CallSiteDescriptorFactory#tokenizeName(String)} (and by implication, all call site + * descriptors it creates) will automatically perform demangling on the passed names. If you use this factory, or you + * have your own way of creating call site descriptors, but you still delegate to this method of the default factory + * (it is recommended that you do), then you have demangling handled for you already, and only need to ensure that you + * mangle the names when you're emitting them in the bytecode. + * + * @author Attila Szegedi + */ +public class NameCodec { + private static final char ESCAPE_CHAR = '\\'; + private static final char EMPTY_ESCAPE = '='; + private static final String EMPTY_NAME = new String(new char[] { ESCAPE_CHAR, EMPTY_ESCAPE }); + private static final char EMPTY_CHAR = 0xFEFF; + + private static final int MIN_ENCODING = '$'; + private static final int MAX_ENCODING = ']'; + private static final char[] ENCODING = new char[MAX_ENCODING - MIN_ENCODING + 1]; + private static final int MIN_DECODING = '!'; + private static final int MAX_DECODING = '}'; + private static final char[] DECODING = new char[MAX_DECODING - MIN_DECODING + 1]; + + static { + addEncoding('/', '|'); + addEncoding('.', ','); + addEncoding(';', '?'); + addEncoding('$', '%'); + addEncoding('<', '^'); + addEncoding('>', '_'); + addEncoding('[', '{'); + addEncoding(']', '}'); + addEncoding(':', '!'); + addEncoding('\\', '-'); + DECODING[EMPTY_ESCAPE - MIN_DECODING] = EMPTY_CHAR; + } + + private NameCodec() { + } + + /** + * Encodes ("mangles") an unencoded symbolic name. + * @param name the symbolic name to mangle + * @return the mangled form of the symbolic name. + */ + public static String encode(String name) { + final int l = name.length(); + if(l == 0) { + return EMPTY_NAME; + } + StringBuilder b = null; + int lastEscape = -1; + for(int i = 0; i < l; ++i) { + final int encodeIndex = name.charAt(i) - MIN_ENCODING; + if(encodeIndex >= 0 && encodeIndex < ENCODING.length) { + final char e = ENCODING[encodeIndex]; + if(e != 0) { + if(b == null) { + b = new StringBuilder(name.length() + 3); + if(name.charAt(0) != ESCAPE_CHAR && i > 0) { + b.append(EMPTY_NAME); + } + b.append(name, 0, i); + } else { + b.append(name, lastEscape + 1, i); + } + b.append(ESCAPE_CHAR).append(e); + lastEscape = i; + } + } + } + if(b == null) { + return name.toString(); + } + assert lastEscape != -1; + b.append(name, lastEscape + 1, l); + return b.toString(); + } + + /** + * Decodes ("demangles") an encoded symbolic name. + * @param name the symbolic name to demangle + * @return the demangled form of the symbolic name. + */ + public static String decode(String name) { + if(name.charAt(0) != ESCAPE_CHAR) { + return name; + } + final int l = name.length(); + if(l == 2 && name.charAt(1) == EMPTY_CHAR) { + return ""; + } + StringBuilder b = new StringBuilder(name.length()); + int lastEscape = -2; + int lastBackslash = -1; + for(;;) { + int nextBackslash = name.indexOf(ESCAPE_CHAR, lastBackslash + 1); + if(nextBackslash == -1 || nextBackslash == l - 1) { + break; + } + final int decodeIndex = name.charAt(nextBackslash + 1) - MIN_DECODING; + if(decodeIndex >= 0 && decodeIndex < DECODING.length) { + final char d = DECODING[decodeIndex]; + if(d == EMPTY_CHAR) { + // "\=" is only valid at the beginning of a mangled string + if(nextBackslash == 0) { + lastEscape = 0; + } + } else if(d != 0) { + b.append(name, lastEscape + 2, nextBackslash).append(d); + lastEscape = nextBackslash; + } + } + lastBackslash = nextBackslash; + } + b.append(name, lastEscape + 2, l); + return b.toString(); + } + + private static void addEncoding(char from, char to) { + ENCODING[from - MIN_ENCODING] = to; + DECODING[to - MIN_DECODING] = from; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/NamedDynCallSiteDescriptor.java b/nashorn/src/jdk/internal/dynalink/support/NamedDynCallSiteDescriptor.java new file mode 100644 index 00000000000..71cbb1d299e --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/NamedDynCallSiteDescriptor.java @@ -0,0 +1,117 @@ +/* + * 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 java.lang.invoke.MethodType; +import jdk.internal.dynalink.CallSiteDescriptor; + +class NamedDynCallSiteDescriptor extends UnnamedDynCallSiteDescriptor { + private final String name; + + NamedDynCallSiteDescriptor(String op, String name, MethodType methodType) { + super(op, methodType); + this.name = name; + } + + @Override + public int getNameTokenCount() { + return 3; + } + + @Override + public String getNameToken(int i) { + switch(i) { + case 0: return "dyn"; + case 1: return getOp(); + case 2: return name; + default: throw new IndexOutOfBoundsException(String.valueOf(i)); + } + } + + @Override + public CallSiteDescriptor changeMethodType(MethodType newMethodType) { + return CallSiteDescriptorFactory.getCanonicalPublicDescriptor(new NamedDynCallSiteDescriptor(getOp(), name, + newMethodType)); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/RuntimeContextLinkRequestImpl.java b/nashorn/src/jdk/internal/dynalink/support/RuntimeContextLinkRequestImpl.java new file mode 100644 index 00000000000..03309a7c26a --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/RuntimeContextLinkRequestImpl.java @@ -0,0 +1,142 @@ +/* + * 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.CallSiteDescriptor; +import jdk.internal.dynalink.linker.LinkRequest; + +/** + * A link request implementation for call sites that pass language runtime specific context arguments on the stack. The + * context specific arguments should be the first "n" arguments. + * + * @author Attila Szegedi + */ +public class RuntimeContextLinkRequestImpl extends LinkRequestImpl { + + private final int runtimeContextArgCount; + private LinkRequestImpl contextStrippedRequest; + + /** + * Creates a new link request. + * + * @param callSiteDescriptor the descriptor for the call site being linked + * @param arguments the arguments for the invocation + * @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); + if(runtimeContextArgCount < 1) { + throw new IllegalArgumentException("runtimeContextArgCount < 1"); + } + this.runtimeContextArgCount = runtimeContextArgCount; + } + + @Override + public LinkRequest withoutRuntimeContext() { + if(contextStrippedRequest == null) { + contextStrippedRequest = + new LinkRequestImpl(CallSiteDescriptorFactory.dropParameterTypes(getCallSiteDescriptor(), 1, + runtimeContextArgCount + 1), isCallSiteUnstable(), getTruncatedArguments()); + } + return contextStrippedRequest; + } + + @Override + public LinkRequest replaceArguments(CallSiteDescriptor callSiteDescriptor, Object[] arguments) { + return new RuntimeContextLinkRequestImpl(callSiteDescriptor, isCallSiteUnstable(), arguments, + runtimeContextArgCount); + } + + private Object[] getTruncatedArguments() { + final Object[] args = getArguments(); + final Object[] newargs = new Object[args.length - runtimeContextArgCount]; + newargs[0] = args[0]; // "this" remains at the 0th position + System.arraycopy(args, runtimeContextArgCount + 1, newargs, 1, newargs.length - 1); + return newargs; + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java b/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java new file mode 100644 index 00000000000..71fb4eb7228 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java @@ -0,0 +1,319 @@ +/* + * 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 java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.WrongMethodTypeException; +import java.util.LinkedList; +import java.util.List; +import jdk.internal.dynalink.linker.ConversionComparator; +import jdk.internal.dynalink.linker.ConversionComparator.Comparison; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; +import jdk.internal.dynalink.linker.LinkerServices; + +/** + * A factory for type converters. This class is the main implementation behind the + * {@link LinkerServices#asType(MethodHandle, MethodType)}. It manages the known {@link GuardingTypeConverterFactory} + * instances and creates appropriate converters for method handles. + * + * @author Attila Szegedi + */ +public class TypeConverterFactory { + + private final GuardingTypeConverterFactory[] factories; + private final ConversionComparator[] comparators; + + private final ClassValue> converterMap = new ClassValue>() { + @Override + protected ClassMap computeValue(final Class sourceType) { + return new ClassMap(sourceType.getClassLoader()) { + @Override + protected MethodHandle computeValue(Class targetType) { + try { + return createConverter(sourceType, targetType); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }; + } + }; + + private final ClassValue> converterIdentityMap = new ClassValue>() { + @Override + protected ClassMap computeValue(final Class sourceType) { + return new ClassMap(sourceType.getClassLoader()) { + @Override + protected MethodHandle computeValue(Class targetType) { + if(!canAutoConvert(sourceType, targetType)) { + final MethodHandle converter = getTypeConverterNull(sourceType, targetType); + if(converter != null) { + return converter; + } + } + return IDENTITY_CONVERSION.asType(MethodType.methodType(targetType, sourceType)); + } + }; + } + }; + + /** + * Creates a new type converter factory from the available {@link GuardingTypeConverterFactory} instances. + * + * @param factories the {@link GuardingTypeConverterFactory} instances to compose. + */ + public TypeConverterFactory(Iterable factories) { + final List l = new LinkedList<>(); + final List c = new LinkedList<>(); + for(GuardingTypeConverterFactory factory: factories) { + l.add(factory); + if(factory instanceof ConversionComparator) { + c.add((ConversionComparator)factory); + } + } + this.factories = l.toArray(new GuardingTypeConverterFactory[l.size()]); + this.comparators = c.toArray(new ConversionComparator[c.size()]); + + } + + /** + * Similar to {@link MethodHandle#asType(MethodType)} except it also hooks in method handles produced by + * {@link GuardingTypeConverterFactory} implementations, providing for language-specific type coercing of + * 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. + * + * @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 asType(MethodHandle handle, final MethodType fromType) { + MethodHandle newHandle = handle; + final MethodType toType = newHandle.type(); + final int l = toType.parameterCount(); + if(l != fromType.parameterCount()) { + throw new WrongMethodTypeException("Parameter counts differ: " + handle.type() + " vs. " + fromType); + } + int pos = 0; + final List converters = new LinkedList<>(); + for(int i = 0; i < l; ++i) { + final Class fromParamType = fromType.parameterType(i); + final Class toParamType = toType.parameterType(i); + if(canAutoConvert(fromParamType, toParamType)) { + newHandle = applyConverters(newHandle, pos, converters); + } else { + final MethodHandle converter = getTypeConverterNull(fromParamType, toParamType); + if(converter != null) { + if(converters.isEmpty()) { + pos = i; + } + converters.add(converter); + } else { + newHandle = applyConverters(newHandle, pos, converters); + } + } + } + newHandle = applyConverters(newHandle, pos, converters); + + // Convert return type + final Class fromRetType = fromType.returnType(); + final Class toRetType = toType.returnType(); + if(fromRetType != Void.TYPE && toRetType != Void.TYPE) { + if(!canAutoConvert(toRetType, fromRetType)) { + final MethodHandle converter = getTypeConverterNull(toRetType, fromRetType); + if(converter != null) { + newHandle = MethodHandles.filterReturnValue(newHandle, converter); + } + } + } + + // Take care of automatic conversions + return newHandle.asType(fromType); + } + + private static MethodHandle applyConverters(MethodHandle handle, int pos, List converters) { + if(converters.isEmpty()) { + return handle; + } + final MethodHandle newHandle = + MethodHandles.filterArguments(handle, pos, converters.toArray(new MethodHandle[converters.size()])); + converters.clear(); + return newHandle; + } + + /** + * Returns true if there might exist a conversion between the requested types (either an automatic JVM conversion, + * or one provided by any available {@link GuardingTypeConverterFactory}), or false if there definitely does not + * exist a conversion between the requested types. Note that returning true does not guarantee that the conversion + * will succeed at runtime (notably, if the "from" or "to" types are sufficiently generic), but returning false + * guarantees that it would fail. + * + * @param from the source type for the conversion + * @param to the target type for the conversion + * @return true if there can be a conversion, false if there can not. + */ + public boolean canConvert(final Class from, final Class to) { + return canAutoConvert(from, to) || getTypeConverterNull(from, to) != null; + } + + /** + * Determines which of the two type conversions from a source type to the two target types is preferred. This is + * used for dynamic overloaded method resolution. If the source type is convertible to exactly one target type with + * a method invocation conversion, it is chosen, otherwise available {@link ConversionComparator}s are consulted. + * @param sourceType the source type. + * @param targetType1 one potential target type + * @param targetType2 another potential target type. + * @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) { + final Comparison result = comparator.compareConversion(sourceType, targetType1, targetType2); + if(result != Comparison.INDETERMINATE) { + return result; + } + } + if(TypeUtilities.isMethodInvocationConvertible(sourceType, targetType1)) { + if(!TypeUtilities.isMethodInvocationConvertible(sourceType, targetType2)) { + return Comparison.TYPE_1_BETTER; + } + } else if(TypeUtilities.isMethodInvocationConvertible(sourceType, targetType2)) { + return Comparison.TYPE_2_BETTER; + } + return Comparison.INDETERMINATE; + } + + /** + * Determines whether it's safe to perform an automatic conversion between the source and target class. + * + * @param fromType convert from this class + * @param toType convert to this class + * @return true if it's safe to let MethodHandles.convertArguments() to handle this conversion. + */ + /*private*/ static boolean canAutoConvert(final Class fromType, final Class toType) { + return TypeUtilities.isMethodInvocationConvertible(fromType, toType); + } + + /*private*/ MethodHandle getTypeConverterNull(Class sourceType, Class targetType) { + final MethodHandle converter = converterMap.get(sourceType).get(targetType); + return converter == IDENTITY_CONVERSION ? null : converter; + } + + /** + * 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 can use this method + * if you have a piece of your program that is written in Java, and you need to reuse existing type conversion + * machinery in a non-invokedynamic context. + * @param sourceType the type to convert from + * @param targetType the type to convert to + * @return a method handle performing the conversion. + */ + public MethodHandle getTypeConverter(Class sourceType, Class targetType) { + return converterIdentityMap.get(sourceType).get(targetType); + } + + /*private*/ MethodHandle createConverter(Class sourceType, Class targetType) throws Exception { + final MethodType type = MethodType.methodType(targetType, sourceType); + final MethodHandle identity = IDENTITY_CONVERSION.asType(type); + MethodHandle last = identity; + for(int i = factories.length; i-- > 0;) { + final GuardedInvocation next = factories[i].convertToType(sourceType, targetType); + if(next != null) { + next.assertType(type); + last = next.compose(last); + } + } + return last == identity ? IDENTITY_CONVERSION : last; + } + + /*private*/ static final MethodHandle IDENTITY_CONVERSION = MethodHandles.identity(Object.class); +} diff --git a/nashorn/src/jdk/internal/dynalink/support/TypeUtilities.java b/nashorn/src/jdk/internal/dynalink/support/TypeUtilities.java new file mode 100644 index 00000000000..57fea990efa --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/TypeUtilities.java @@ -0,0 +1,442 @@ +/* + * 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 java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Various static utility methods for testing type relationships. + * + * @author Attila Szegedi + */ +public class TypeUtilities { + static final Class OBJECT_CLASS = Object.class; + + private TypeUtilities() { + } + + /** + * Given two types represented by c1 and c2, returns a type that is their most specific common superclass or + * superinterface. + * + * @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. + */ + public static Class getMostSpecificCommonType(Class c1, Class c2) { + if(c1 == c2) { + return c1; + } + 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; + } + Set> a1 = getAssignables(c1, c3); + Set> a2 = getAssignables(c3, c1); + a1.retainAll(a2); + if(a1.isEmpty()) { + // Can happen when at least one of the arguments is an interface, + // as they don't have Object at the root of their hierarchy. + return Object.class; + } + // Gather maximally specific elements. Yes, there can be more than one + // 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> max = new ArrayList<>(); + outer: for(Class clazz: a1) { + for(Iterator> maxiter = max.iterator(); maxiter.hasNext();) { + Class maxClazz = maxiter.next(); + if(isSubtype(maxClazz, clazz)) { + // It can't be maximal, if there's already a more specific + // maximal than it. + continue outer; + } + if(isSubtype(clazz, maxClazz)) { + // If it's more specific than a currently maximal element, + // that currently maximal is no longer a maximal. + maxiter.remove(); + } + } + // If we get here, no current maximal is more specific than the + // current class, so it is considered maximal as well + max.add(clazz); + } + if(max.size() > 1) { + return OBJECT_CLASS; + } + return max.get(0); + } + + private static Set> getAssignables(Class c1, Class c2) { + Set> s = new HashSet<>(); + collectAssignables(c1, c2, s); + return s; + } + + private static void collectAssignables(Class c1, Class c2, Set> s) { + if(c1.isAssignableFrom(c2)) { + s.add(c1); + } + Class sc = c1.getSuperclass(); + if(sc != null) { + collectAssignables(sc, c2, s); + } + Class[] itf = c1.getInterfaces(); + for(int i = 0; i < itf.length; ++i) { + collectAssignables(itf[i], c2, s); + } + } + + private static final Map, Class> WRAPPER_TYPES = createWrapperTypes(); + private static final Map, Class> PRIMITIVE_TYPES = invertMap(WRAPPER_TYPES); + private static final Map> PRIMITIVE_TYPES_BY_NAME = createClassNameMapping(WRAPPER_TYPES.keySet()); + + private static Map, Class> createWrapperTypes() { + final Map, Class> wrapperTypes = new IdentityHashMap<>(8); + wrapperTypes.put(Boolean.TYPE, Boolean.class); + wrapperTypes.put(Byte.TYPE, Byte.class); + wrapperTypes.put(Character.TYPE, Character.class); + wrapperTypes.put(Short.TYPE, Short.class); + wrapperTypes.put(Integer.TYPE, Integer.class); + wrapperTypes.put(Long.TYPE, Long.class); + wrapperTypes.put(Float.TYPE, Float.class); + wrapperTypes.put(Double.TYPE, Double.class); + return Collections.unmodifiableMap(wrapperTypes); + } + + private static Map> createClassNameMapping(Collection> classes) { + final Map> map = new HashMap<>(); + for(Class clazz: classes) { + map.put(clazz.getName(), clazz); + } + return map; + } + + private static Map invertMap(Map map) { + final Map inverted = new IdentityHashMap<>(map.size()); + for(Map.Entry entry: map.entrySet()) { + inverted.put(entry.getValue(), entry.getKey()); + } + return Collections.unmodifiableMap(inverted); + } + + /** + * Determines whether one type can be converted to another type using a method invocation conversion, as per JLS 5.3 + * "Method Invocation Conversion". This is basically all conversions allowed by subtyping (see + * {@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. + */ + public static boolean isMethodInvocationConvertible(Class callSiteType, Class methodType) { + if(methodType.isAssignableFrom(callSiteType)) { + return true; + } + if(callSiteType.isPrimitive()) { + if(methodType.isPrimitive()) { + return isProperPrimitiveSubtype(callSiteType, methodType); + } + // Boxing + widening reference conversion + return methodType.isAssignableFrom(WRAPPER_TYPES.get(callSiteType)); + } + if(methodType.isPrimitive()) { + final Class unboxedCallSiteType = PRIMITIVE_TYPES.get(callSiteType); + return unboxedCallSiteType != null + && (unboxedCallSiteType == methodType || isProperPrimitiveSubtype(unboxedCallSiteType, methodType)); + } + 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 + * well as between any primitive type and any reference type that can hold a boxed primitive. + * + * @param callSiteType the parameter type at the call site + * @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) { + // Widening or narrowing reference conversion + if(methodType.isAssignableFrom(callSiteType) || callSiteType.isAssignableFrom(methodType)) { + return true; + } + if(callSiteType.isPrimitive()) { + // Allow any conversion among primitives, as well as from any + // primitive to any type that can receive a boxed primitive. + // TODO: narrow this a bit, i.e. allow, say, boolean to Character? + // MethodHandles.convertArguments() allows it, so we might need to + // too. + return methodType.isPrimitive() || isAssignableFromBoxedPrimitive(methodType); + } + if(methodType.isPrimitive()) { + // Allow conversion from any reference type that can contain a + // boxed primitive to any primitive. + // TODO: narrow this a bit too? + return isAssignableFromBoxedPrimitive(callSiteType); + } + return false; + } + + /** + * 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 + * identity conversion (JLS 5.1.1), widening primitive conversion (JLS 5.1.2) and widening reference conversion (JLS + * 5.1.5). + * + * @param subType the supposed subtype + * @param superType the supposed supertype of the subtype + * @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) { + // 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. + if(superType.isAssignableFrom(subType)) { + return true; + } + // JLS 4.10.1 "Subtyping among Primitive Types". Note we don't test for + // identity, as identical types were taken care of in the + // isAssignableFrom test. As per 4.10.1, the supertype relation is as + // follows: + // double > float + // float > long + // long > int + // int > short + // int > char + // short > byte + if(superType.isPrimitive() && subType.isPrimitive()) { + return isProperPrimitiveSubtype(subType, superType); + } + return false; + } + + /** + * Returns true if a supposed primitive subtype is a proper subtype ( meaning, subtype and not identical) of the + * supposed primitive supertype + * + * @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 + */ + private static boolean isProperPrimitiveSubtype(Class subType, Class superType) { + if(superType == boolean.class || subType == boolean.class) { + return false; + } + if(subType == byte.class) { + return superType != char.class; + } + if(subType == char.class) { + return superType != short.class && superType != byte.class; + } + if(subType == short.class) { + return superType != char.class && superType != byte.class; + } + if(subType == int.class) { + return superType == long.class || superType == float.class || superType == double.class; + } + if(subType == long.class) { + return superType == float.class || superType == double.class; + } + if(subType == float.class) { + return superType == double.class; + } + return false; + } + + private static final Map, Class> WRAPPER_TO_PRIMITIVE_TYPES = createWrapperToPrimitiveTypes(); + + private static Map, Class> createWrapperToPrimitiveTypes() { + final Map, Class> classes = new IdentityHashMap<>(); + classes.put(Void.class, Void.TYPE); + classes.put(Boolean.class, Boolean.TYPE); + classes.put(Byte.class, Byte.TYPE); + classes.put(Character.class, Character.TYPE); + classes.put(Short.class, Short.TYPE); + classes.put(Integer.class, Integer.TYPE); + classes.put(Long.class, Long.TYPE); + classes.put(Float.class, Float.TYPE); + classes.put(Double.class, Double.TYPE); + return classes; + } + + private static final Set> PRIMITIVE_WRAPPER_TYPES = createPrimitiveWrapperTypes(); + + private static Set> createPrimitiveWrapperTypes() { + final Map, Class> classes = new IdentityHashMap<>(); + addClassHierarchy(classes, Boolean.class); + addClassHierarchy(classes, Byte.class); + addClassHierarchy(classes, Character.class); + addClassHierarchy(classes, Short.class); + addClassHierarchy(classes, Integer.class); + addClassHierarchy(classes, Long.class); + addClassHierarchy(classes, Float.class); + addClassHierarchy(classes, Double.class); + return classes.keySet(); + } + + private static void addClassHierarchy(Map, Class> map, Class clazz) { + if(clazz == null) { + return; + } + map.put(clazz, clazz); + addClassHierarchy(map, clazz.getSuperclass()); + for(Class itf: clazz.getInterfaces()) { + addClassHierarchy(map, itf); + } + } + + /** + * Returns true if the class can be assigned from any boxed primitive. + * + * @param clazz the class + * @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) { + return PRIMITIVE_WRAPPER_TYPES.contains(clazz); + } + + /** + * Given a name of a primitive type (except "void"), returns the class representing it. I.e. when invoked with + * "int", returns {@link Integer#TYPE}. + * @param name the name of the primitive type + * @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) { + return PRIMITIVE_TYPES_BY_NAME.get(name); + } + + /** + * When passed a class representing a wrapper for a primitive type, returns the class representing the corresponding + * primitive type. I.e. calling it with {@code Integer.class} will return {@code Integer.TYPE}. If passed a class + * that is not a wrapper for primitive type, returns null. + * @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) { + return WRAPPER_TO_PRIMITIVE_TYPES.get(wrapperType); + } + + + /** + * When passed a class representing a primitive type, returns the class representing the corresponding + * wrapper type. I.e. calling it with {@code int.class} will return {@code Integer.class}. If passed a class + * that is not a primitive type, returns null. + * @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) { + return WRAPPER_TYPES.get(primitiveType); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/UnnamedDynCallSiteDescriptor.java b/nashorn/src/jdk/internal/dynalink/support/UnnamedDynCallSiteDescriptor.java new file mode 100644 index 00000000000..da8c0096f49 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/UnnamedDynCallSiteDescriptor.java @@ -0,0 +1,126 @@ +/* + * 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 java.lang.invoke.MethodType; +import jdk.internal.dynalink.CallSiteDescriptor; + +class UnnamedDynCallSiteDescriptor extends AbstractCallSiteDescriptor { + private final MethodType methodType; + private final String op; + + UnnamedDynCallSiteDescriptor(String op, MethodType methodType) { + this.op = op; + this.methodType = methodType; + } + + @Override + public int getNameTokenCount() { + return 2; + } + + String getOp() { + return op; + } + + @Override + public String getNameToken(int i) { + switch(i) { + case 0: return "dyn"; + case 1: return op; + default: throw new IndexOutOfBoundsException(String.valueOf(i)); + } + } + + @Override + public MethodType getMethodType() { + return methodType; + } + + @Override + public CallSiteDescriptor changeMethodType(MethodType newMethodType) { + return CallSiteDescriptorFactory.getCanonicalPublicDescriptor(new UnnamedDynCallSiteDescriptor(op, + newMethodType)); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/messages.properties b/nashorn/src/jdk/internal/dynalink/support/messages.properties new file mode 100644 index 00000000000..eaf1f630d09 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/messages.properties @@ -0,0 +1,86 @@ +# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. + +isInstanceGuardAlwaysTrue=isInstance guard for {0} in position {1} in method type {2} will always return true +isInstanceGuardAlwaysFalse=isInstance guard for {0} in position {1} in method type {2} will always return false + +isOfClassGuardAlwaysTrue=isOfClass guard for {0} in position {1} in method type {2} will always return true +isOfClassGuardAlwaysFalse=isOfClass guard for {0} in position {1} in method type {2} will always return false + +isArrayGuardAlwaysTrue=isArray guard in position {0} in method type {1} will always return true +isArrayGuardAlwaysFalse=isArray guard in position {0} in method type {1} will always return false \ No newline at end of file diff --git a/nashorn/src/jdk/internal/dynalink/support/package.html b/nashorn/src/jdk/internal/dynalink/support/package.html new file mode 100644 index 00000000000..7bf9efcdc21 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/package.html @@ -0,0 +1,89 @@ + + + + +

+ Contains supporting classes for other packages. There is no guarantee that + any of these classes or interfaces will not change in a manner that breaks + backwards compatibility; they are not considered to be part of the public + API. +

+ diff --git a/nashorn/src/jdk/nashorn/api/scripting/Formatter.java b/nashorn/src/jdk/nashorn/api/scripting/Formatter.java new file mode 100644 index 00000000000..3b47d3479e4 --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/Formatter.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.api.scripting; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Formatter is a class to get the type conversion between javascript types and + * java types for the format (sprintf) method working. + * + *

In javascript the type for numbers can be different from the format type + * specifier. For format type '%d', '%o', '%x', '%X' double need to be + * converted to integer. For format type 'e', 'E', 'f', 'g', 'G', 'a', 'A' + * integer needs to be converted to double. + * + *

Format type "%c" and javascript string needs special handling. + * + *

The javascript date objects can be handled if they are type double (the + * related javascript code will convert with Date.getTime() to double). So + * double date types are converted to long. + * + *

Pattern and the logic for parameter position: java.util.Formatter + * + */ +public final class Formatter { + + private Formatter() { + } + + /** + * Method which converts javascript types to java types for the + * String.format method (jrunscript function sprintf). + * + * @param format a format string + * @param args arguments referenced by the format specifiers in format + * @return a formatted string + */ + public static String format(final String format, final Object[] args) { + Matcher m = FS_PATTERN.matcher(format); + int positionalParameter = 1; + + while (m.find()) { + int index = index(m.group(1)); + boolean previous = isPreviousArgument(m.group(2)); + char conversion = m.group(6).charAt(0); + + // skip over some formats + if (index < 0 || previous + || conversion == 'n' || conversion == '%') { + continue; + } + + // index 0 here means take a positional parameter + if (index == 0) { + index = positionalParameter++; + } + + // out of index, String.format will handle + if (index > args.length) { + continue; + } + + // current argument + Object arg = args[index - 1]; + + // for date we convert double to long + if (m.group(5) != null) { + // convert double to long + if (arg instanceof Double) { + args[index - 1] = ((Double) arg).longValue(); + } + } else { + // we have to convert some types + switch (conversion) { + case 'd': + case 'o': + case 'x': + case 'X': + if (arg instanceof Double) { + // convert double to long + args[index - 1] = ((Double) arg).longValue(); + } else if (arg instanceof String + && ((String) arg).length() > 0) { + // convert string (first character) to int + args[index - 1] = (int) ((String) arg).charAt(0); + } + break; + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + case 'a': + case 'A': + if (arg instanceof Integer) { + // convert integer to double + args[index - 1] = ((Integer) arg).doubleValue(); + } + break; + case 'c': + if (arg instanceof Double) { + // convert double to integer + args[index - 1] = ((Double) arg).intValue(); + } else if (arg instanceof String + && ((String) arg).length() > 0) { + // get the first character from string + args[index - 1] = (int) ((String) arg).charAt(0); + } + break; + default: + break; + } + } + } + + return String.format(format, args); + } + + /** + * Method to parse the integer of the argument index. + * + * @param s + * @return -1 if parsing failed, 0 if string is null, > 0 integer + */ + private static int index(final String s) { + int index = -1; + + if (s != null) { + try { + index = Integer.parseInt(s.substring(0, s.length() - 1)); + } catch (final NumberFormatException e) { + //ignored + } + } else { + index = 0; + } + + return index; + } + + /** + * Method to check if a string contains '<'. This is used to find out if + * previous parameter is used. + * + * @param s + * @return true if '<' is in the string, else false + */ + private static boolean isPreviousArgument(final String s) { + return (s != null && s.indexOf('<') >= 0) ? true : false; + } + + // %[argument_index$][flags][width][.precision][t]conversion + private static final String formatSpecifier = + "%(\\d+\\$)?([-#+ 0,(\\<]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])"; + // compiled format string + private static final Pattern FS_PATTERN; + + static { + FS_PATTERN = Pattern.compile(formatSpecifier); + } +} diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornException.java b/nashorn/src/jdk/nashorn/api/scripting/NashornException.java new file mode 100644 index 00000000000..d1d47b1dc08 --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornException.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.api.scripting; + +import jdk.nashorn.internal.runtime.ECMAErrors; + +/** + * This is base exception for all Nashorn exceptions. These originate from + * user's ECMAScript code. Example: script parse errors, exceptions thrown from + * scripts. Note that ScriptEngine methods like "eval", "invokeMethod", + * "invokeFunction" will wrap this as ScriptException and throw it. But, there + * are cases where user may need to access this exception (or implementation + * defined subtype of this). For example, if java interface is implemented by a + * script object or Java access to script object properties via java.util.Map + * interface. In these cases, user code will get an instance of this or + * implementation defined subclass. + */ +@SuppressWarnings("serial") +public abstract class NashornException extends RuntimeException { + // script file name + private final String fileName; + // script line number + private final int line; + // script column number + private final int column; + + /** script source name used for "engine.js" */ + public static final String ENGINE_SCRIPT_SOURCE_NAME = "nashorn:engine/resources/engine.js"; + + /** + * Constructor + * + * @param msg exception message + * @param fileName file name + * @param line line number + * @param column column number + */ + protected NashornException(final String msg, final String fileName, final int line, final int column) { + this(msg, null, fileName, line, column); + } + + /** + * Constructor + * + * @param msg exception message + * @param cause exception cause + * @param fileName file name + * @param line line number + * @param column column number + */ + protected NashornException(final String msg, final Throwable cause, final String fileName, final int line, final int column) { + super(msg, cause == null ? null : cause); + this.fileName = fileName; + this.line = line; + this.column = column; + } + + /** + * Constructor + * + * @param msg exception message + * @param cause exception cause + */ + protected NashornException(final String msg, final Throwable cause) { + super(msg, cause == null ? null : cause); + // This is not so pretty - but it gets the job done. Note that the stack + // trace has been already filled by "fillInStackTrace" call from + // Throwable + // constructor and so we don't pay additional cost for it. + + // Hard luck - no column number info + this.column = -1; + + // Find the first JavaScript frame by walking and set file, line from it + // Usually, we should be able to find it in just few frames depth. + for (final StackTraceElement ste : getStackTrace()) { + if (ECMAErrors.isScriptFrame(ste)) { + // Whatever here is compiled from JavaScript code + this.fileName = ste.getFileName(); + this.line = ste.getLineNumber(); + return; + } + } + + this.fileName = null; + this.line = 0; + } + + /** + * Get the source file name for this {@code NashornException} + * + * @return the file name + */ + public final String getFileName() { + return fileName; + } + + /** + * Get the line number for this {@code NashornException} + * + * @return the line number + */ + public final int getLineNumber() { + return line; + } + + /** + * Get the column for this {@code NashornException} + * + * @return the column + */ + public final int getColumnNumber() { + return column; + } + +} diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java new file mode 100644 index 00000000000..ce16a7e82d0 --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java @@ -0,0 +1,488 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.api.scripting; + +import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError; +import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import javax.script.AbstractScriptEngine; +import javax.script.Bindings; +import javax.script.Compilable; +import javax.script.CompiledScript; +import javax.script.Invocable; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptException; +import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.ErrorManager; +import jdk.nashorn.internal.runtime.GlobalObject; +import jdk.nashorn.internal.runtime.Property; +import jdk.nashorn.internal.runtime.ScriptFunction; +import jdk.nashorn.internal.runtime.ScriptObject; +import jdk.nashorn.internal.runtime.ScriptRuntime; +import jdk.nashorn.internal.runtime.Source; +import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; +import jdk.nashorn.internal.runtime.options.Options; + +/** + * JSR-223 compliant script engine for Nashorn. Instances are not created directly, but rather returned through + * {@link NashornScriptEngineFactory#getScriptEngine()}. Note that this engine implements the {@link Compilable} and + * {@link Invocable} interfaces, allowing for efficient precompilation and repeated execution of scripts. + * @see NashornScriptEngineFactory + */ + +public final class NashornScriptEngine extends AbstractScriptEngine implements Compilable, Invocable { + + private final ScriptEngineFactory factory; + private final Context nashornContext; + private final ScriptObject global; + + // default options passed to Nashorn Options object + private static final String[] DEFAULT_OPTIONS = new String[] { "-scripting", "-af", "-doe" }; + + NashornScriptEngine(final NashornScriptEngineFactory factory, final ClassLoader appLoader) { + this(factory, DEFAULT_OPTIONS, appLoader); + } + + @SuppressWarnings("LeakingThisInConstructor") + NashornScriptEngine(final NashornScriptEngineFactory factory, final String[] args, final ClassLoader appLoader) { + this.factory = factory; + final Options options = new Options("nashorn"); + options.process(args); + + // throw ParseException on first error from script + final ErrorManager errMgr = new Context.ThrowErrorManager(); + // create new Nashorn Context + this.nashornContext = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Context run() { + try { + return new Context(options, errMgr, appLoader); + } catch (final RuntimeException e) { + if (Context.DEBUG) { + e.printStackTrace(); + } + throw e; + } + } + }); + + // create new global object + this.global = createNashornGlobal(); + // set the default engine scope for the default context + context.setBindings(new ScriptObjectMirror(global, global), ScriptContext.ENGINE_SCOPE); + + // evaluate engine initial script + try { + evalEngineScript(); + } catch (final ScriptException e) { + if (Context.DEBUG) { + e.printStackTrace(); + } + throw new RuntimeException(e); + } + } + + @Override + public Object eval(final Reader reader, final ScriptContext ctxt) throws ScriptException { + try { + if (reader instanceof URLReader) { + final URL url = ((URLReader)reader).getURL(); + return evalImpl(compileImpl(new Source(url.toString(), url), ctxt), ctxt); + } + return evalImpl(Source.readFully(reader), ctxt); + } catch (final IOException e) { + throw new ScriptException(e); + } + } + + @Override + public Object eval(final String script, final ScriptContext ctxt) throws ScriptException { + return evalImpl(script.toCharArray(), ctxt); + } + + @Override + public ScriptEngineFactory getFactory() { + return factory; + } + + @Override + public Bindings createBindings() { + final ScriptObject newGlobal = createNashornGlobal(); + return new ScriptObjectMirror(newGlobal, newGlobal); + } + + // Compilable methods + + @Override + public CompiledScript compile(final Reader reader) throws ScriptException { + try { + return asCompiledScript(compileImpl(Source.readFully(reader), context)); + } catch (final IOException e) { + throw new ScriptException(e); + } + } + + @Override + public CompiledScript compile(final String str) throws ScriptException { + return asCompiledScript(compileImpl(str.toCharArray(), context)); + } + + // Invocable methods + + @Override + public Object invokeFunction(final String name, final Object... args) + throws ScriptException, NoSuchMethodException { + return invokeImpl(null, name, args); + } + + @Override + public Object invokeMethod(final Object self, final String name, final Object... args) + throws ScriptException, NoSuchMethodException { + if (self == null) { + throw new IllegalArgumentException("script object can not be null"); + } + return invokeImpl(self, name, args); + } + + private T getInterfaceInner(final Object self, final Class clazz) { + final Object realSelf; + final ScriptObject ctxtGlobal = getNashornGlobalFrom(context); + if(self == null) { + realSelf = ctxtGlobal; + } else if (!(self instanceof ScriptObject)) { + realSelf = ScriptObjectMirror.unwrap(self, ctxtGlobal); + } else { + realSelf = self; + } + try { + final ScriptObject oldGlobal = getNashornGlobal(); + try { + if(oldGlobal != ctxtGlobal) { + setNashornGlobal(ctxtGlobal); + } + return clazz.cast(JavaAdapterFactory.getConstructor(realSelf.getClass(), clazz).invoke(realSelf)); + } finally { + if(oldGlobal != ctxtGlobal) { + setNashornGlobal(oldGlobal); + } + } + } catch(final RuntimeException|Error e) { + throw e; + } catch(final Throwable t) { + throw new RuntimeException(t); + } + } + + @Override + public T getInterface(final Class clazz) { + return getInterfaceInner(null, clazz); + } + + @Override + public T getInterface(final Object self, final Class clazz) { + if (self == null) { + throw new IllegalArgumentException("script object can not be null"); + } + return getInterfaceInner(self, clazz); + } + + // These are called from the "engine.js" script + + /** + * This hook is used to search js global variables exposed from Java code. + * + * @param self 'this' passed from the script + * @param ctxt current ScriptContext in which name is searched + * @param name name of the variable searched + * @return the value of the named variable + */ + public Object __noSuchProperty__(final Object self, final ScriptContext ctxt, final String name) { + final int scope = ctxt.getAttributesScope(name); + final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt); + if (scope != -1) { + return ScriptObjectMirror.unwrap(ctxt.getAttribute(name, scope), ctxtGlobal); + } + + if (self == UNDEFINED) { + // scope access and so throw ReferenceError + throw referenceError(ctxtGlobal, "not.defined", name); + } + + return UNDEFINED; + } + + private ScriptObject getNashornGlobalFrom(final ScriptContext ctxt) { + final Bindings bindings = ctxt.getBindings(ScriptContext.ENGINE_SCOPE); + if (bindings instanceof ScriptObjectMirror) { + ScriptObject sobj = ((ScriptObjectMirror)bindings).getScriptObject(); + if (sobj instanceof GlobalObject) { + return sobj; + } + } + + // didn't find global object from context given - return the engine-wide global + return global; + } + + private ScriptObject createNashornGlobal() { + final ScriptObject newGlobal = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public ScriptObject run() { + try { + return nashornContext.newGlobal(); + } catch (final RuntimeException e) { + if (Context.DEBUG) { + e.printStackTrace(); + } + throw e; + } + } + }); + + nashornContext.initGlobal(newGlobal); + + // current ScriptContext exposed as "context" + newGlobal.addOwnProperty("context", Property.NOT_ENUMERABLE, UNDEFINED); + // current ScriptEngine instance exposed as "engine". We added @SuppressWarnings("LeakingThisInConstructor") as + // NetBeans identifies this assignment as such a leak - this is a false positive as we're setting this property + // in the Global of a Context we just created - both the Context and the Global were just created and can not be + // seen from another thread outside of this constructor. + newGlobal.addOwnProperty("engine", Property.NOT_ENUMERABLE, this); + // global script arguments with undefined value + newGlobal.addOwnProperty("arguments", Property.NOT_ENUMERABLE, UNDEFINED); + // file name default is null + newGlobal.addOwnProperty(ScriptEngine.FILENAME, Property.NOT_ENUMERABLE, null); + return newGlobal; + } + + private void evalEngineScript() throws ScriptException { + evalSupportScript("resources/engine.js", NashornException.ENGINE_SCRIPT_SOURCE_NAME); + } + + private void evalSupportScript(final String script, final String name) throws ScriptException { + try { + final InputStream is = AccessController.doPrivileged( + new PrivilegedExceptionAction() { + @Override + public InputStream run() throws Exception { + final URL url = NashornScriptEngine.class.getResource(script); + return url.openStream(); + } + }); + put(ScriptEngine.FILENAME, name); + try (final InputStreamReader isr = new InputStreamReader(is)) { + eval(isr); + } + } catch (final PrivilegedActionException | IOException e) { + throw new ScriptException(e); + } finally { + put(ScriptEngine.FILENAME, null); + } + } + + // scripts should see "context" and "engine" as variables + private void setContextVariables(final ScriptContext ctxt) { + ctxt.setAttribute("context", ctxt, ScriptContext.ENGINE_SCOPE); + final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt); + ctxtGlobal.set("context", ctxt, false); + Object args = ScriptObjectMirror.unwrap(ctxt.getAttribute("arguments"), ctxtGlobal); + if (args == null || args == UNDEFINED) { + args = ScriptRuntime.EMPTY_ARRAY; + } + // if no arguments passed, expose it + args = ((GlobalObject)ctxtGlobal).wrapAsObject(args); + ctxtGlobal.set("arguments", args, false); + } + + private Object invokeImpl(final Object selfObject, final String name, final Object... args) throws ScriptException, NoSuchMethodException { + final ScriptObject oldGlobal = getNashornGlobal(); + final ScriptObject ctxtGlobal = getNashornGlobalFrom(context); + final boolean globalChanged = (oldGlobal != ctxtGlobal); + + Object self = globalChanged? ScriptObjectMirror.wrap(selfObject, oldGlobal) : selfObject; + + try { + if (globalChanged) { + setNashornGlobal(ctxtGlobal); + } + + ScriptObject sobj; + Object value = null; + + self = ScriptObjectMirror.unwrap(self, ctxtGlobal); + + // FIXME: should convert when self is not ScriptObject + if (self instanceof ScriptObject) { + sobj = (ScriptObject)self; + value = sobj.get(name); + } else if (self == null) { + self = ctxtGlobal; + sobj = ctxtGlobal; + value = sobj.get(name); + } + + if (value instanceof ScriptFunction) { + final Object res; + try { + final Object[] modArgs = globalChanged? ScriptObjectMirror.wrapArray(args, oldGlobal) : args; + res = ScriptRuntime.checkAndApply((ScriptFunction)value, self, ScriptObjectMirror.unwrapArray(modArgs, ctxtGlobal)); + } catch (final Exception e) { + throwAsScriptException(e); + throw new AssertionError("should not reach here"); + } + return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(res, ctxtGlobal)); + } + + throw new NoSuchMethodException(name); + } finally { + if (globalChanged) { + setNashornGlobal(oldGlobal); + } + } + } + + private Object evalImpl(final char[] buf, final ScriptContext ctxt) throws ScriptException { + return evalImpl(compileImpl(buf, ctxt), ctxt); + } + + private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt) throws ScriptException { + if (script == null) { + return null; + } + final ScriptObject oldGlobal = getNashornGlobal(); + final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt); + final boolean globalChanged = (oldGlobal != ctxtGlobal); + try { + if (globalChanged) { + setNashornGlobal(ctxtGlobal); + } + + setContextVariables(ctxt); + final Object val = ctxt.getAttribute(ScriptEngine.FILENAME); + final String fileName = (val != null) ? val.toString() : ""; + + // NOTE: FIXME: If this is jrunscript's init.js, we want to run the replacement. + // This should go away once we fix jrunscript's copy of init.js. + if ("".equals(fileName)) { + evalSupportScript("resources/init.js", "nashorn:engine/resources/init.js"); + return null; + } + + Object res = ScriptRuntime.apply(script, ctxtGlobal); + return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(res, ctxtGlobal)); + } catch (final Exception e) { + throwAsScriptException(e); + throw new AssertionError("should not reach here"); + } finally { + if (globalChanged) { + setNashornGlobal(oldGlobal); + } + } + } + + private static void throwAsScriptException(final Exception e) throws ScriptException { + if (e instanceof ScriptException) { + throw (ScriptException)e; + } else if (e instanceof NashornException) { + final NashornException ne = (NashornException)e; + final ScriptException se = new ScriptException( + ne.getMessage(), ne.getFileName(), + ne.getLineNumber(), ne.getColumnNumber()); + se.initCause(e); + throw se; + } else if (e instanceof RuntimeException) { + throw (RuntimeException)e; + } else { + // wrap any other exception as ScriptException + throw new ScriptException(e); + } + } + + private CompiledScript asCompiledScript(final ScriptFunction script) { + return new CompiledScript() { + @Override + public Object eval(final ScriptContext ctxt) throws ScriptException { + return evalImpl(script, ctxt); + } + @Override + public ScriptEngine getEngine() { + return NashornScriptEngine.this; + } + }; + } + + private ScriptFunction compileImpl(final char[] buf, final ScriptContext ctxt) throws ScriptException { + final Object val = ctxt.getAttribute(ScriptEngine.FILENAME); + final String fileName = (val != null) ? val.toString() : ""; + return compileImpl(new Source(fileName, buf), ctxt); + } + + private ScriptFunction compileImpl(final Source source, final ScriptContext ctxt) throws ScriptException { + final ScriptObject oldGlobal = getNashornGlobal(); + final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt); + final boolean globalChanged = (oldGlobal != ctxtGlobal); + try { + if (globalChanged) { + setNashornGlobal(ctxtGlobal); + } + + return nashornContext.compileScript(source, ctxtGlobal); + } catch (final Exception e) { + throwAsScriptException(e); + throw new AssertionError("should not reach here"); + } finally { + if (globalChanged) { + setNashornGlobal(oldGlobal); + } + } + } + + // don't make this public!! + static ScriptObject getNashornGlobal() { + return Context.getGlobal(); + } + + static void setNashornGlobal(final ScriptObject newGlobal) { + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Void run() { + Context.setGlobal(newGlobal); + return null; + } + }); + } +} diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java new file mode 100644 index 00000000000..47a0c595236 --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.api.scripting; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import jdk.nashorn.internal.runtime.Version; +import sun.reflect.Reflection; + +/** + * JSR-223 compliant script engine factory for Nashorn. The engine answers for: + *

    + *
  • names {@code "nashorn"}, {@code "Nashorn"}, {@code "js"}, {@code "JS"}, {@code "JavaScript"}, + * {@code "javascript"}, {@code "ECMAScript"}, and {@code "ecmascript"};
  • + *
  • MIME types {@code "application/javascript"}, {@code "application/ecmascript"}, {@code "text/javascript"}, and + * {@code "text/ecmascript"};
  • + *
  • as well as for the extension {@code "js"}.
  • + *
+ * Programs executing in engines created using {@link #getScriptEngine(String[])} will have the passed arguments + * accessible as a global variable named {@code "arguments"}. + */ +public final class NashornScriptEngineFactory implements ScriptEngineFactory { + @Override + public String getEngineName() { + return (String) getParameter(ScriptEngine.ENGINE); + } + + @Override + public String getEngineVersion() { + return (String) getParameter(ScriptEngine.ENGINE_VERSION); + } + + @Override + public List getExtensions() { + return Collections.unmodifiableList(extensions); + } + + @Override + public String getLanguageName() { + return (String) getParameter(ScriptEngine.LANGUAGE); + } + + @Override + public String getLanguageVersion() { + return (String) getParameter(ScriptEngine.LANGUAGE_VERSION); + } + + @Override + public String getMethodCallSyntax(final String obj, final String method, final String... args) { + final StringBuilder sb = new StringBuilder().append(obj).append('.').append(method).append('('); + final int len = args.length; + + if (len > 0) { + sb.append(args[0]); + } + for (int i = 1; i < len; i++) { + sb.append(',').append(args[i]); + } + sb.append(')'); + + return sb.toString(); + } + + @Override + public List getMimeTypes() { + return Collections.unmodifiableList(mimeTypes); + } + + @Override + public List getNames() { + return Collections.unmodifiableList(names); + } + + @Override + public String getOutputStatement(final String toDisplay) { + return "print(" + toDisplay + ")"; + } + + @Override + public Object getParameter(final String key) { + switch (key) { + case ScriptEngine.NAME: + return "javascript"; + case ScriptEngine.ENGINE: + return "Oracle Nashorn"; + case ScriptEngine.ENGINE_VERSION: + return Version.version(); + case ScriptEngine.LANGUAGE: + return "ECMAScript"; + case ScriptEngine.LANGUAGE_VERSION: + return "ECMA - 262 Edition 5.1"; + case "THREADING": + // The engine implementation is not thread-safe. Can't be + // used to execute scripts concurrently on multiple threads. + return null; + default: + throw new IllegalArgumentException("Invalid key"); + } + } + + @Override + public String getProgram(final String... statements) { + final StringBuilder sb = new StringBuilder(); + + for (final String statement : statements) { + sb.append(statement).append(';'); + } + + return sb.toString(); + } + + @Override + public ScriptEngine getScriptEngine() { + return new NashornScriptEngine(this, getAppClassLoader()); + } + + /** + * Create a new Script engine initialized by given class loader. + * + * @param appLoader class loader to be used as script "app" class loader. + * @return newly created script engine. + */ + public ScriptEngine getScriptEngine(final ClassLoader appLoader) { + return new NashornScriptEngine(this, appLoader); + } + + /** + * Create a new Script engine initialized by given arguments. + * + * @param args arguments array passed to script engine. + * @return newly created script engine. + */ + public ScriptEngine getScriptEngine(final String[] args) { + return new NashornScriptEngine(this, args, getAppClassLoader()); + } + + /** + * Create a new Script engine initialized by given arguments. + * + * @param args arguments array passed to script engine. + * @param appLoader class loader to be used as script "app" class loader. + * @return newly created script engine. + */ + public ScriptEngine getScriptEngine(final String[] args, final ClassLoader appLoader) { + return new NashornScriptEngine(this, args, appLoader); + } + + // -- Internals only below this point + + private static final List names; + private static final List mimeTypes; + private static final List extensions; + + static { + names = immutableList( + "nashorn", "Nashorn", + "js", "JS", + "JavaScript", "javascript", + "ECMAScript", "ecmascript" + ); + + mimeTypes = immutableList( + "application/javascript", + "application/ecmascript", + "text/javascript", + "text/ecmascript" + ); + + extensions = immutableList("js"); + } + + private static List immutableList(final String... elements) { + return Collections.unmodifiableList(Arrays.asList(elements)); + } + + private static ClassLoader getAppClassLoader() { + if (System.getSecurityManager() == null) { + return Thread.currentThread().getContextClassLoader(); + } + + // Try to determine the caller class loader. Use that if it can be + // found. If not, use the class loader of nashorn itself as the + // "application" class loader for scripts. + + // User could have called ScriptEngineFactory.getScriptEngine() + // + // + // + // + // + // + // or used one of the getEngineByABC methods of ScriptEngineManager. + // + // + // + // + // + // + + // So, stack depth is 3 or 4 (recall it is zero based). We try + // stack depths 3, 4 and look for non-bootstrap caller. + Class caller = null; + for (int depth = 3; depth < 5; depth++) { + caller = Reflection.getCallerClass(depth); + if (caller != null && caller.getClassLoader() != null) { + // found a non-bootstrap caller + break; + } + } + + final ClassLoader ccl = (caller == null)? null : caller.getClassLoader(); + // if caller loader is null, then use nashorn's own loader + return (ccl == null)? NashornScriptEngineFactory.class.getClassLoader() : ccl; + } +} diff --git a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java new file mode 100644 index 00000000000..266ce87f48d --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.api.scripting; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Callable; +import javax.script.Bindings; +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 netscape.javascript.JSObject; + +/** + * Mirror object that wraps a given ScriptObject instance. User can + * access ScriptObject via the javax.script.Bindings interface or + * netscape.javascript.JSObject interface. + */ +final class ScriptObjectMirror extends JSObject implements Bindings { + private final ScriptObject sobj; + private final ScriptObject global; + + ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) { + this.sobj = sobj; + this.global = global; + } + + @Override + public boolean equals(final Object other) { + if (other instanceof ScriptObjectMirror) { + return sobj.equals(((ScriptObjectMirror)other).sobj); + } + + return false; + } + + @Override + public int hashCode() { + return sobj.hashCode(); + } + + @Override + public String toString() { + return inGlobal(new Callable() { + @Override + public String call() { + return ScriptRuntime.safeToString(sobj); + } + }); + } + + private V inGlobal(final Callable callable) { + final ScriptObject oldGlobal = NashornScriptEngine.getNashornGlobal(); + final boolean globalChanged = (oldGlobal != global); + if (globalChanged) { + NashornScriptEngine.setNashornGlobal(global); + } + try { + return callable.call(); + } catch (final RuntimeException e) { + throw e; + } catch (final Exception e) { + throw new AssertionError("Cannot happen", e); + } finally { + if (globalChanged) { + NashornScriptEngine.setNashornGlobal(oldGlobal); + } + } + } + + // JSObject methods + @Override + public Object call(final String methodName, final Object args[]) { + final ScriptObject oldGlobal = NashornScriptEngine.getNashornGlobal(); + final boolean globalChanged = (oldGlobal != global); + + try { + if (globalChanged) { + NashornScriptEngine.setNashornGlobal(global); + } + + final Object val = sobj.get(methodName); + if (! (val instanceof ScriptFunction)) { + throw new RuntimeException("No such method: " + methodName); + } + + final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args; + return wrap(ScriptRuntime.checkAndApply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global); + } catch (final RuntimeException | Error e) { + throw e; + } catch (final Throwable t) { + throw new RuntimeException(t); + } finally { + if (globalChanged) { + NashornScriptEngine.setNashornGlobal(oldGlobal); + } + } + } + + @Override + public Object eval(final String s) { + return inGlobal(new Callable() { + @Override + public Object call() { + final Context context = AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public Context run() { + return Context.getContext(); + } + }); + return wrap(context.eval(global, s, null, null, false), global); + } + }); + } + + @Override + public Object getMember(final String name) { + return inGlobal(new Callable() { + @Override public Object call() { + return wrap(sobj.get(name), global); + } + }); + } + + @Override + public Object getSlot(final int index) { + return inGlobal(new Callable() { + @Override public Object call() { + return wrap(sobj.get(index), global); + } + }); + } + + @Override + public void removeMember(final String name) { + remove(name); + } + + @Override + public void setMember(final String name, final Object value) { + put(name, value); + } + + @Override + public void setSlot(final int index, final Object value) { + inGlobal(new Callable() { + @Override public Void call() { + sobj.set(index, unwrap(value, global), global.isStrictContext()); + return null; + } + }); + } + + @Override + public void clear() { + inGlobal(new Callable() { + @Override public Object call() { + sobj.clear(); + return null; + } + }); + } + + @Override + public boolean containsKey(final Object key) { + return inGlobal(new Callable() { + @Override public Boolean call() { + return sobj.containsKey(unwrap(key, global)); + } + }); + } + + @Override + public boolean containsValue(final Object value) { + return inGlobal(new Callable() { + @Override public Boolean call() { + return sobj.containsValue(unwrap(value, global)); + } + }); + } + + @Override + public Set> entrySet() { + return inGlobal(new Callable>>() { + @Override public Set> call() { + final Iterator iter = sobj.propertyIterator(); + final Set> entries = new HashSet<>(); + + while (iter.hasNext()) { + final String key = iter.next(); + final Object value = translateUndefined(wrap(sobj.get(key), global)); + entries.add(new AbstractMap.SimpleImmutableEntry<>(key, value)); + } + + return Collections.unmodifiableSet(entries); + } + }); + } + + @Override + public Object get(final Object key) { + return inGlobal(new Callable() { + @Override public Object call() { + return translateUndefined(wrap(sobj.get(key), global)); + } + }); + } + + @Override + public boolean isEmpty() { + return inGlobal(new Callable() { + @Override public Boolean call() { + return sobj.isEmpty(); + } + }); + } + + @Override + public Set keySet() { + return inGlobal(new Callable>() { + @Override public Set call() { + final Iterator iter = sobj.propertyIterator(); + final Set keySet = new HashSet<>(); + + while (iter.hasNext()) { + keySet.add(iter.next()); + } + + return Collections.unmodifiableSet(keySet); + } + }); + } + + @Override + public Object put(final String key, final Object value) { + final ScriptObject oldGlobal = NashornScriptEngine.getNashornGlobal(); + final boolean globalChanged = (oldGlobal != global); + return inGlobal(new Callable() { + @Override public Object call() { + final Object modValue = globalChanged? wrap(value, oldGlobal) : value; + return translateUndefined(wrap(sobj.put(key, unwrap(modValue, global)), global)); + } + }); + } + + @Override + public void putAll(final Map map) { + final ScriptObject oldGlobal = NashornScriptEngine.getNashornGlobal(); + final boolean globalChanged = (oldGlobal != global); + final boolean strict = sobj.isStrictContext(); + inGlobal(new Callable() { + @Override public Object call() { + for (final Map.Entry entry : map.entrySet()) { + final Object value = entry.getValue(); + final Object modValue = globalChanged? wrap(value, oldGlobal) : value; + sobj.set(entry.getKey(), unwrap(modValue, global), strict); + } + return null; + } + }); + } + + @Override + public Object remove(final Object key) { + return inGlobal(new Callable() { + @Override public Object call() { + return wrap(sobj.remove(unwrap(key, global)), global); + } + }); + } + + @Override + public int size() { + return inGlobal(new Callable() { + @Override public Integer call() { + return sobj.size(); + } + }); + } + + @Override + public Collection values() { + return inGlobal(new Callable>() { + @Override public Collection call() { + final List values = new ArrayList<>(size()); + final Iterator iter = sobj.valueIterator(); + + while (iter.hasNext()) { + values.add(translateUndefined(wrap(iter.next(), global))); + } + + return Collections.unmodifiableList(values); + } + }); + } + + // package-privates below this. + ScriptObject getScriptObject() { + return sobj; + } + + static Object translateUndefined(Object obj) { + return (obj == ScriptRuntime.UNDEFINED)? null : obj; + } + + static Object wrap(final Object obj, final ScriptObject homeGlobal) { + return (obj instanceof ScriptObject) ? new ScriptObjectMirror((ScriptObject)obj, homeGlobal) : obj; + } + + static Object unwrap(final Object obj, final ScriptObject homeGlobal) { + if (obj instanceof ScriptObjectMirror) { + final ScriptObjectMirror mirror = (ScriptObjectMirror)obj; + return (mirror.global == homeGlobal)? mirror.sobj : obj; + } + + return obj; + } + + static Object[] wrapArray(final Object[] args, final ScriptObject homeGlobal) { + if (args == null || args.length == 0) { + return args; + } + + final Object[] newArgs = new Object[args.length]; + int index = 0; + for (final Object obj : args) { + newArgs[index] = wrap(obj, homeGlobal); + index++; + } + return newArgs; + } + + static Object[] unwrapArray(final Object[] args, final ScriptObject homeGlobal) { + if (args == null || args.length == 0) { + return args; + } + + final Object[] newArgs = new Object[args.length]; + int index = 0; + for (final Object obj : args) { + newArgs[index] = unwrap(obj, homeGlobal); + index++; + } + return newArgs; + } +} diff --git a/nashorn/src/jdk/nashorn/api/scripting/URLReader.java b/nashorn/src/jdk/nashorn/api/scripting/URLReader.java new file mode 100644 index 00000000000..d21d6263611 --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/URLReader.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.api.scripting; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; + +/** + * A Reader that reads from a URL. Used to make sure that the reader + * reads content from given URL and can be trusted to do so. + */ +public final class URLReader extends Reader { + // underlying URL + private URL url; + // lazily initialized underlying reader for URL + private Reader reader; + + /** + * Constructor + * + * @param url URL for this URLReader + */ + public URLReader(final URL url) { + this.url = url; + } + + @Override + public int read(char cbuf[], int off, int len) throws IOException { + return getReader().read(cbuf, off, len); + } + + @Override + public void close() throws IOException { + getReader().close(); + } + + /** + * URL of this reader + * @return the URL from which this reader reads. + */ + public URL getURL() { + return url; + } + + // lazily initialize char array reader using URL content + private Reader getReader() throws IOException { + synchronized (lock) { + if (reader == null) { + reader = new InputStreamReader(url.openStream()); + } + } + + return reader; + } +} diff --git a/nashorn/src/jdk/nashorn/api/scripting/package-info.java b/nashorn/src/jdk/nashorn/api/scripting/package-info.java new file mode 100644 index 00000000000..6876151e330 --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/package-info.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 package provides the {@code javax.script} integration, which is the preferred way to use Nashorn. + * You will ordinarily do this to obtain an instance of a Nashorn script engine: + *
+ * import javax.script.*;
+ * ...
+ * ScriptEngine nashornEngine = new ScriptEngineManager().getEngineByName("Nashorn");
+ * 
+ *

Nashorn script engines implement the optional {@link javax.script.Invocable} and {@link javax.script.Compilable} + * interfaces, allowing for efficient pre-compilation and repeated execution of scripts. See + * {@link jdk.nashorn.api.scripting.NashornScriptEngineFactory} for further details. + */ +package jdk.nashorn.api.scripting; diff --git a/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js b/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js new file mode 100644 index 00000000000..65b82dfe797 --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js @@ -0,0 +1,48 @@ +/* + * 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. + */ + +/** + * This script file is executed by script engine at the construction + * of the engine. The functions here assume global variables "context" + * of type javax.script.ScriptContext and "engine" of the type + * jdk.nashorn.api.scripting.NashornScriptEngine. + * + **/ + +Object.defineProperty(this, "__noSuchProperty__", { + configurable: true, + enumerable: false, + writable: true, + value: function (name) { + 'use strict'; + return engine.__noSuchProperty__(this, context, name); + } +}); + +function print(str) { + var writer = context.getWriter(); + if (! (writer instanceof java.io.PrintWriter)) { + writer = new java.io.PrintWriter(writer); + } + writer.println(String(str)); +} diff --git a/nashorn/src/jdk/nashorn/api/scripting/resources/init.js b/nashorn/src/jdk/nashorn/api/scripting/resources/init.js new file mode 100644 index 00000000000..18cde929451 --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/resources/init.js @@ -0,0 +1,939 @@ +/* + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +/** + * jrunscript JavaScript built-in functions and objects. + */ + +/** + * Creates an object that delegates all method calls on + * it to the 'invoke' method on the given delegate object.
+ * + * Example: + *

+ * 
+ *     var x  = { invoke: function(name, args) { //code...}
+ *     var y = new JSInvoker(x);
+ *     y.func(3, 3); // calls x.invoke('func', args); where args is array of arguments
+ * 
+ * 
+ * @param obj object to be wrapped by JSInvoker + * @constructor + */ +function JSInvoker(obj) { + return new JSAdapter({ + __get__ : function(name) { + return function() { + return obj.invoke(name, arguments); + } + } + }); +} + +/** + * This variable represents OS environment. Environment + * variables can be accessed as fields of this object. For + * example, env.PATH will return PATH value configured. + */ +var env = new JSAdapter({ + __get__ : function (name) { + return java.lang.System.getenv(name); + }, + __has__ : function (name) { + return java.lang.System.getenv().containsKey(name); + }, + __getIds__ : function() { + return java.lang.System.getenv().keySet().toArray(); + }, + __delete__ : function(name) { + println("can't delete env item"); + }, + __put__ : function (name, value) { + println("can't change env item"); + }, + toString: function() { + return java.lang.System.getenv().toString(); + } +}); + +/** + * Creates a convenient script object to deal with java.util.Map instances. + * The result script object's field names are keys of the Map. For example, + * scriptObj.keyName can be used to access value associated with given key.
+ * Example: + *
+ * 
+ *     var x = java.lang.SystemProperties();
+ *     var y = jmap(x);
+ *     println(y['java.class.path']); // prints java.class.path System property
+ *     delete y['java.class.path']; // remove java.class.path System property
+ * 
+ * 
+ * + * @param map java.util.Map instance that will be wrapped + * @constructor + */ +function jmap(map) { + return new JSAdapter({ + __get__ : function(name) { + if (map.containsKey(name)) { + return map.get(name); + } else { + return undefined; + } + }, + __has__ : function(name) { + return map.containsKey(name); + }, + + __delete__ : function (name) { + return map.remove(name); + }, + __put__ : function(name, value) { + map.put(name, value); + }, + __getIds__ : function() { + return map.keySet().toArray(); + }, + toString: function() { + return map.toString(); + } + }); +} + +/** + * Creates a convenient script object to deal with java.util.List instances. + * The result script object behaves like an array. For example, + * scriptObj[index] syntax can be used to access values in the List instance. + * 'length' field gives size of the List.
+ * + * Example: + *
+ * 
+ *    var x = new java.util.ArrayList(4);
+ *    x.add('Java');
+ *    x.add('JavaScript');
+ *    x.add('SQL');
+ *    x.add('XML');
+ *
+ *    var y = jlist(x);
+ *    println(y[2]); // prints third element of list
+ *    println(y.length); // prints size of the list
+ *
+ * @param map java.util.List instance that will be wrapped
+ * @constructor
+ */
+function jlist(list) {
+    function isValid(index) {
+        return typeof(index) == 'number' &&
+            index > -1 && index < list.size();
+    }
+    return new JSAdapter({
+        __get__ :  function(name) {
+            if (isValid(name)) {
+                return list.get(name);
+            } else if (name == 'length') {
+                return list.size();
+            } else {
+                return undefined;
+            }
+        },
+        __has__ : function (name) {
+            return isValid(name) || name == 'length';
+        },
+        __delete__ : function(name) {
+            if (isValid(name)) {
+                list.remove(name);
+            }
+        },
+        __put__ : function(name, value) {
+            if (isValid(name)) {
+                list.set(name, value);
+            }
+        },
+        __getIds__: function() {
+            var res = new Array(list.size());
+            for (var i = 0; i < res.length; i++) {
+                res[i] = i;
+            }
+            return res;
+        },
+        toString: function() {
+            return list.toString();
+        }
+    });
+}
+
+/**
+ * This is java.lang.System properties wrapped by JSAdapter.
+ * For eg. to access java.class.path property, you can use
+ * the syntax sysProps["java.class.path"]
+ */
+var sysProps = new JSAdapter({
+    __get__ : function (name) {
+        return java.lang.System.getProperty(name);
+    },
+    __has__ : function (name) {
+        return java.lang.System.getProperty(name) != null;
+    },
+    __getIds__ : function() {
+        return java.lang.System.getProperties().keySet().toArray();
+    },
+    __delete__ : function(name) {
+        java.lang.System.clearProperty(name);
+        return true;
+    },
+    __put__ : function (name, value) {
+        java.lang.System.setProperty(name, value);
+    },
+    toString: function() {
+        return "";
+    }
+});
+
+// stdout, stderr & stdin
+var out = java.lang.System.out;
+var err = java.lang.System.err;
+// can't use 'in' because it is a JavaScript keyword :-(
+var inp = java.lang.System["in"];
+
+var BufferedInputStream = java.io.BufferedInputStream;
+var BufferedOutputStream = java.io.BufferedOutputStream;
+var BufferedReader = java.io.BufferedReader;
+var DataInputStream = java.io.DataInputStream;
+var File = java.io.File;
+var FileInputStream = java.io.FileInputStream;
+var FileOutputStream = java.io.FileOutputStream;
+var InputStream = java.io.InputStream;
+var InputStreamReader = java.io.InputStreamReader;
+var OutputStream = java.io.OutputStream;
+var Reader = java.io.Reader;
+var URL = java.net.URL;
+
+/**
+ * Generic any object to input stream mapper
+ * @param str input file name, URL or InputStream
+ * @return InputStream object
+ * @private
+ */
+function inStream(str) {
+    if (typeof(str) == "string") {
+        // '-' means standard input
+        if (str == '-') {
+            return java.lang.System["in"];
+        }
+        // try file first
+        var file = null;
+        try {
+            file = pathToFile(str);
+        } catch (e) {
+        }
+        if (file && file.exists()) {
+            return new FileInputStream(file);
+        } else {
+            try {
+                // treat the string as URL
+                return new URL(str).openStream();
+            } catch (e) {
+                throw 'file or URL ' + str + ' not found';
+            }
+        }
+    } else {
+        if (str instanceof InputStream) {
+            return str;
+        } else if (str instanceof URL) {
+            return str.openStream();
+        } else if (str instanceof File) {
+            return new FileInputStream(str);
+        }
+    }
+    // everything failed, just give input stream
+    return java.lang.System["in"];
+}
+
+/**
+ * Generic any object to output stream mapper
+ *
+ * @param out output file name or stream
+ * @return OutputStream object
+ * @private
+ */
+function outStream(out) {
+    if (typeof(out) == "string") {
+        if (out == '>') {
+            return java.lang.System.out;
+        } else {
+            // treat it as file
+            return new FileOutputStream(pathToFile(out));
+        }
+    } else {
+        if (out instanceof OutputStream) {
+            return out;
+        } else if (out instanceof File) {
+            return new FileOutputStream(out);
+        }
+    }
+
+    // everything failed, just return System.out
+    return java.lang.System.out;
+}
+
+/**
+ * stream close takes care not to close stdin, out & err.
+ * @private
+ */
+function streamClose(stream) {
+    if (stream) {
+        if (stream != java.lang.System["in"] &&
+            stream != java.lang.System.out &&
+            stream != java.lang.System.err) {
+            try {
+                stream.close();
+            } catch (e) {
+                println(e);
+            }
+        }
+    }
+}
+
+/**
+ * Loads and evaluates JavaScript code from a stream or file or URL
+ * + * Examples: + *
+ * 
+ *    load('test.js'); // load script file 'test.js'
+ *    load('http://java.sun.com/foo.js'); // load from a URL
+ * 
+ * 
+ * + * @param str input from which script is loaded and evaluated + */ +if (typeof(load) == 'undefined') { + var load = function(str) { + var stream = inStream(str); + var bstream = new BufferedInputStream(stream); + var reader = new BufferedReader(new InputStreamReader(bstream)); + var oldFilename = engine.get(engine.FILENAME); + engine.put(engine.FILENAME, str); + try { + engine.eval(reader); + } finally { + engine.put(engine.FILENAME, oldFilename); + streamClose(stream); + } + } +} + +// file system utilities + +/** + * Creates a Java byte[] of given length + * @param len size of the array to create + * @private + */ +function javaByteArray(len) { + return java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, len); +} + +var curDir = new File('.'); + +/** + * Print present working directory + */ +function pwd() { + println(curDir.getAbsolutePath()); +} + +/** + * Changes present working directory to given directory + * @param target directory to change to. optional, defaults to user's HOME + */ +function cd(target) { + if (target == undefined) { + target = sysProps["user.home"]; + } + if (!(target instanceof File)) { + target = pathToFile(target); + } + if (target.exists() && target.isDirectory()) { + curDir = target; + } else { + println(target + " is not a directory"); + } +} + +/** + * Converts path to java.io.File taking care of shell present working dir + * + * @param pathname file path to be converted + * @private + */ +function pathToFile(pathname) { + var tmp = pathname; + if (!(tmp instanceof File)) { + tmp = new File(tmp); + } + if (!tmp.isAbsolute()) { + return new File(curDir, pathname); + } else { + return tmp; + } +} + +/** + * Copies a file or URL or stream to another file or stream + * + * @param from input file or URL or stream + * @param to output stream or file + */ +function cp(from, to) { + if (from == to) { + println("file " + from + " cannot be copied onto itself!"); + return; + } + var inp = inStream(from); + var out = outStream(to); + var binp = new BufferedInputStream(inp); + var bout = new BufferedOutputStream(out); + var buff = javaByteArray(1024); + var len; + while ((len = binp.read(buff)) > 0 ) + bout.write(buff, 0, len); + + bout.flush(); + streamClose(inp); + streamClose(out); +} + +/** + * Shows the content of a file or URL or any InputStream
+ * Examples: + *
+ * 
+ *    cat('test.txt'); // show test.txt file contents
+ *    cat('http://java.net'); // show the contents from the URL http://java.net
+ * 
+ * 
+ * @param obj input to show + * @param pattern optional. show only the lines matching the pattern + */ +function cat(obj, pattern) { + if (obj instanceof File && obj.isDirectory()) { + ls(obj); + return; + } + + var inp = null; + if (!(obj instanceof Reader)) { + inp = inStream(obj); + obj = new BufferedReader(new InputStreamReader(inp)); + } + var line; + if (pattern) { + var count = 1; + while ((line=obj.readLine()) != null) { + if (line.match(pattern)) { + println(count + "\t: " + line); + } + count++; + } + } else { + while ((line=obj.readLine()) != null) { + println(line); + } + } +} + +/** + * Returns directory part of a filename + * + * @param pathname input path name + * @return directory part of the given file name + */ +function dirname(pathname) { + var dirName = "."; + // Normalize '/' to local file separator before work. + var i = pathname.replace('/', File.separatorChar ).lastIndexOf( + File.separator ); + if ( i != -1 ) + dirName = pathname.substring(0, i); + return dirName; +} + +/** + * Creates a new dir of given name + * + * @param dir name of the new directory + */ +function mkdir(dir) { + dir = pathToFile(dir); + println(dir.mkdir()? "created" : "can not create dir"); +} + +/** + * Creates the directory named by given pathname, including + * any necessary but nonexistent parent directories. + * + * @param dir input path name + */ +function mkdirs(dir) { + dir = pathToFile(dir); + println(dir.mkdirs()? "created" : "can not create dirs"); +} + +/** + * Removes a given file + * + * @param pathname name of the file + */ +function rm(pathname) { + var file = pathToFile(pathname); + if (!file.exists()) { + println("file not found: " + pathname); + return false; + } + // note that delete is a keyword in JavaScript! + println(file["delete"]()? "deleted" : "can not delete"); +} + +/** + * Removes a given directory + * + * @param pathname name of the directory + */ +function rmdir(pathname) { + rm(pathname); +} + +/** + * Synonym for 'rm' + */ +function del(pathname) { + rm(pathname); +} + +/** + * Moves a file to another + * + * @param from original name of the file + * @param to new name for the file + */ +function mv(from, to) { + println(pathToFile(from).renameTo(pathToFile(to))? + "moved" : "can not move"); +} + +/** + * Synonym for 'mv'. + */ +function ren(from, to) { + mv(from, to); +} + +var months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; + +/** + * Helper function called by ls + * @private + */ +function printFile(f) { + var sb = new java.lang.StringBuffer(); + sb.append(f.isDirectory()? "d" : "-"); + sb.append(f.canRead() ? "r": "-" ); + sb.append(f.canWrite() ? "w": "-" ); + sb.append(" "); + + var d = new java.util.Date(f.lastModified()); + var c = new java.util.GregorianCalendar(); + c.setTime(d); + var day = c.get(java.util.Calendar.DAY_OF_MONTH); + sb.append(months[c.get(java.util.Calendar.MONTH)] + + " " + day ); + if (day < 10) { + sb.append(" "); + } + + // to get fixed length 'length' field + var fieldlen = 8; + var len = new java.lang.StringBuffer(); + for(var j=0; j + * + * Examples: + *
+ * 
+ *    find('.')
+ *    find('.', '.*\.class', rm);  // remove all .class files
+ *    find('.', '.*\.java');       // print fullpath of each .java file
+ *    find('.', '.*\.java', cat);  // print all .java files
+ * 
+ * 
+ * + * @param dir directory to search files + * @param pattern to search in the files + * @param callback function to call for matching files + */ +function find(dir, pattern, callback) { + dir = pathToFile(dir); + if (!callback) callback = print; + var files = dir.listFiles(); + for (var f in files) { + var file = files[f]; + if (file.isDirectory()) { + find(file, pattern, callback); + } else { + if (pattern) { + if (file.getName().match(pattern)) { + callback(file); + } + } else { + callback(file); + } + } + } +} + +// process utilities + +/** + * Exec's a child process, waits for completion & returns exit code + * + * @param cmd command to execute in child process + */ +function exec(cmd) { + var process = java.lang.Runtime.getRuntime().exec(cmd); + var inp = new DataInputStream(process.getInputStream()); + var line = null; + while ((line = inp.readLine()) != null) { + println(line); + } + process.waitFor(); + $exit = process.exitValue(); +} + +// XML utilities + +/** + * Converts input to DOM Document object + * + * @param inp file or reader. optional, without this param, + * this function returns a new DOM Document. + * @return returns a DOM Document object + */ +function XMLDocument(inp) { + var factory = javax.xml.parsers.DocumentBuilderFactory.newInstance(); + var builder = factory.newDocumentBuilder(); + if (inp) { + if (typeof(inp) == "string") { + return builder.parse(pathToFile(inp)); + } else { + return builder.parse(inp); + } + } else { + return builder.newDocument(); + } +} + +/** + * Converts arbitrary stream, file, URL to XMLSource + * + * @param inp input stream or file or URL + * @return XMLSource object + */ +function XMLSource(inp) { + if (inp instanceof javax.xml.transform.Source) { + return inp; + } else if (inp instanceof Packages.org.w3c.dom.Document) { + return new javax.xml.transform.dom.DOMSource(inp); + } else { + inp = new BufferedInputStream(inStream(inp)); + return new javax.xml.transform.stream.StreamSource(inp); + } +} + +/** + * Converts arbitrary stream, file to XMLResult + * + * @param inp output stream or file + * @return XMLResult object + */ +function XMLResult(out) { + if (out instanceof javax.xml.transform.Result) { + return out; + } else if (out instanceof Packages.org.w3c.dom.Document) { + return new javax.xml.transform.dom.DOMResult(out); + } else { + out = new BufferedOutputStream(outStream(out)); + return new javax.xml.transform.stream.StreamResult(out); + } +} + +/** + * Perform XSLT transform + * + * @param inp Input XML to transform (URL, File or InputStream) + * @param style XSL Stylesheet to be used (URL, File or InputStream). optional. + * @param out Output XML (File or OutputStream + */ +function XSLTransform(inp, style, out) { + switch (arguments.length) { + case 2: + inp = arguments[0]; + out = arguments[1]; + break; + case 3: + inp = arguments[0]; + style = arguments[1]; + out = arguments[2]; + break; + default: + println("XSL tranform requires 2 or 3 arguments"); + return; + } + + var factory = javax.xml.transform.TransformerFactory.newInstance(); + var transformer; + if (style) { + transformer = factory.newTransformer(XMLSource(style)); + } else { + transformer = factory.newTransformer(); + } + var source = XMLSource(inp); + var result = XMLResult(out); + transformer.transform(source, result); + if (source.getInputStream) { + streamClose(source.getInputStream()); + } + if (result.getOutputStream) { + streamClose(result.getOutputStream()); + } +} + +// miscellaneous utilities + +/** + * Prints which command is selected from PATH + * + * @param cmd name of the command searched from PATH + */ +function which(cmd) { + var st = new java.util.StringTokenizer(env.PATH, File.pathSeparator); + while (st.hasMoreTokens()) { + var file = new File(st.nextToken(), cmd); + if (file.exists()) { + println(file.getAbsolutePath()); + return; + } + } +} + +/** + * Prints IP addresses of given domain name + * + * @param name domain name + */ +function ip(name) { + var addrs = InetAddress.getAllByName(name); + for (var i in addrs) { + println(addrs[i]); + } +} + +/** + * Prints current date in current locale + */ +function date() { + println(new Date().toLocaleString()); +} + +/** + * Echoes the given string arguments + */ +function echo(x) { + for (var i = 0; i < arguments.length; i++) { + println(arguments[i]); + } +} + +/** + * Reads one or more lines from stdin after printing prompt + * + * @param prompt optional, default is '>' + * @param multiline to tell whether to read single line or multiple lines + */ +function read(prompt, multiline) { + if (!prompt) { + prompt = '>'; + } + var inp = java.lang.System["in"]; + var reader = new BufferedReader(new InputStreamReader(inp)); + if (multiline) { + var line = ''; + while (true) { + java.lang.System.err.print(prompt); + java.lang.System.err.flush(); + var tmp = reader.readLine(); + if (tmp == '' || tmp == null) break; + line += tmp + '\n'; + } + return line; + } else { + java.lang.System.err.print(prompt); + java.lang.System.err.flush(); + return reader.readLine(); + } +} + +if (typeof(println) == 'undefined') { + var print = function(str, newline) { + if (typeof(str) == 'undefined') { + str = 'undefined'; + } else if (str == null) { + str = 'null'; + } + + if (!(out instanceof java.io.PrintWriter)) { + out = new java.io.PrintWriter(out); + } + + out.print(String(str)); + if (newline) { + out.print('\n'); + } + out.flush(); + } + + var println = function(str) { + print(str, true); + }; +} + +/** + * This is C-like printf + * + * @param format string to format the rest of the print items + * @param args variadic argument list + */ +function printf(format, args/*, more args*/) { + print(sprintf.apply(this, arguments)); +} + +/** + * This is C-like sprintf + * + * @param format string to format the rest of the print items + * @param args variadic argument list + */ +function sprintf(format, args/*, more args*/) { + var len = arguments.length - 1; + var array = []; + + if (len < 0) { + return ""; + } + + for (var i = 0; i < len; i++) { + if (arguments[i+1] instanceof Date) { + array[i] = arguments[i+1].getTime(); + } else { + array[i] = arguments[i+1]; + } + } + + array = Java.toJavaArray(array); + return Packages.jdk.nashorn.api.scripting.Formatter.format(format, array); +} diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java new file mode 100644 index 00000000000..211140e4123 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java @@ -0,0 +1,1609 @@ +/* + * 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.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.SCOPE; +import static jdk.nashorn.internal.codegen.CompilerConstants.SCRIPT_RETURN; +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.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_THIS; +import static jdk.nashorn.internal.ir.Symbol.IS_VAR; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.AccessNode; +import jdk.nashorn.internal.ir.BinaryNode; +import jdk.nashorn.internal.ir.Block; +import jdk.nashorn.internal.ir.CallNode; +import jdk.nashorn.internal.ir.CallNode.EvalArgs; +import jdk.nashorn.internal.ir.CaseNode; +import jdk.nashorn.internal.ir.CatchNode; +import jdk.nashorn.internal.ir.ForNode; +import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.IdentNode; +import jdk.nashorn.internal.ir.IndexNode; +import jdk.nashorn.internal.ir.LiteralNode; +import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; +import jdk.nashorn.internal.ir.Node; +import jdk.nashorn.internal.ir.ObjectNode; +import jdk.nashorn.internal.ir.PropertyNode; +import jdk.nashorn.internal.ir.ReferenceNode; +import jdk.nashorn.internal.ir.ReturnNode; +import jdk.nashorn.internal.ir.RuntimeNode; +import jdk.nashorn.internal.ir.RuntimeNode.Request; +import jdk.nashorn.internal.ir.SwitchNode; +import jdk.nashorn.internal.ir.Symbol; +import jdk.nashorn.internal.ir.TernaryNode; +import jdk.nashorn.internal.ir.TryNode; +import jdk.nashorn.internal.ir.UnaryNode; +import jdk.nashorn.internal.ir.VarNode; +import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; +import jdk.nashorn.internal.ir.visitor.NodeVisitor; +import jdk.nashorn.internal.parser.TokenType; +import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.Debug; +import jdk.nashorn.internal.runtime.DebugLogger; +import jdk.nashorn.internal.runtime.ECMAException; +import jdk.nashorn.internal.runtime.JSType; +import jdk.nashorn.internal.runtime.Property; +import jdk.nashorn.internal.runtime.PropertyMap; +import jdk.nashorn.internal.runtime.ScriptFunction; +import jdk.nashorn.internal.runtime.ScriptObject; + +/** + * This is the attribution pass of the code generator. Attr takes Lowered IR, + * that is, IR where control flow has been computed and high level to low level + * substitions for operations have been performed. + * + * After Attr, every symbol will have a conservative correct type. + * + * Any expression that requires temporary storage as part of computation will + * also be detected here and give a temporary symbol + * + * Types can be narrowed after Attr by Access Specialization in FinalizeTypes, + * but in general, this is where the main symbol type information is + * computed. + */ + +final class Attr extends NodeOperatorVisitor { + /** + * Local definitions in current block (to discriminate from function + * declarations always defined in the function scope. This is for + * "can be undefined" analysis. + */ + private Set localDefs; + + /** + * Local definitions in current block to guard against cases like + * NASHORN-467 when things can be undefined as they are used before + * their local var definition. *sigh* JavaScript... + */ + private Set localUses; + + private static final DebugLogger LOG = new DebugLogger("attr"); + private static final boolean DEBUG = LOG.isEnabled(); + + /** + * Constructor. + */ + Attr() { + } + + @Override + protected Node enterDefault(final Node node) { + return start(node); + } + + @Override + protected Node leaveDefault(final Node node) { + return end(node); + } + + @Override + public Node leave(final AccessNode accessNode) { + newTemporary(Type.OBJECT, accessNode); //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this + end(accessNode); + return accessNode; + } + + @Override + public Node enter(final Block block) { + start(block); + + final Set savedLocalDefs = localDefs; + final Set savedLocalUses = localUses; + + block.setFrame(getCurrentFunctionNode().pushFrame()); + + try { + // a block starts out by copying the local defs and local uses + // from the outer level. But we need the copies, as when we + // leave the block the def and use sets given upon entry must + // be restored + localDefs = new HashSet<>(savedLocalDefs); + localUses = new HashSet<>(savedLocalUses); + + for (final Node statement : block.getStatements()) { + statement.accept(this); + } + } finally { + localDefs = savedLocalDefs; + localUses = savedLocalUses; + + getCurrentFunctionNode().popFrame(); + } + + end(block); + + return null; + } + + @Override + public Node enter(final CallNode callNode) { + start(callNode); + + callNode.getFunction().accept(this); + + final List acceptedArgs = new ArrayList<>(callNode.getArgs().size()); + for (final Node arg : callNode.getArgs()) { + LOG.info("Doing call arg " + arg); + acceptedArgs.add(arg.accept(this)); + } + callNode.setArgs(acceptedArgs); + + final EvalArgs evalArgs = callNode.getEvalArgs(); + if (evalArgs != null) { + evalArgs.setCode(evalArgs.getCode().accept(this)); + + final IdentNode thisNode = new IdentNode(getCurrentFunctionNode().getThisNode()); + assert thisNode.getSymbol() != null; //should copy attributed symbol and that's it + evalArgs.setThis(thisNode); + } + + newTemporary(Type.OBJECT, callNode); // object type here, access specialization in FinalizeTypes may narrow it later + newType(callNode.getFunction().getSymbol(), Type.OBJECT); + + end(callNode); + + return null; + } + + @Override + public Node enter(final CatchNode catchNode) { + final IdentNode exception = catchNode.getException(); + final Block block = getCurrentBlock(); + + start(catchNode); + + // define block-local exception variable + final Symbol def = block.defineSymbol(exception.getName(), IS_VAR | IS_LET, exception); + newType(def, Type.OBJECT); + addLocalDef(exception.getName()); + + return catchNode; + } + + @Override + public Node enter(final FunctionNode functionNode) { + start(functionNode, false); + if (functionNode.isLazy()) { + LOG.info("LAZY: " + functionNode.getName()); + end(functionNode); + return null; + } + + clearLocalDefs(); + clearLocalUses(); + + functionNode.setFrame(functionNode.pushFrame()); + + initCallee(functionNode); + initThis(functionNode); + if (functionNode.isVarArg()) { + initVarArg(functionNode); + } + + initParameters(functionNode); + initScope(functionNode); + initReturn(functionNode); + + // Add all nested functions as symbols in this function + for (final FunctionNode nestedFunction : functionNode.getFunctions()) { + final IdentNode ident = nestedFunction.getIdent(); + if (ident != null && nestedFunction.isStatement()) { + final Symbol functionSymbol = functionNode.defineSymbol(ident.getName(), IS_VAR, nestedFunction); + newType(functionSymbol, Type.typeFor(ScriptFunction.class)); + } + } + + if (functionNode.isScript()) { + initFromPropertyMap(functionNode); + } + + // Add function name as local symbol + if (!functionNode.isStatement() && !functionNode.isAnonymous() && !functionNode.isScript()) { + final Symbol selfSymbol = functionNode.defineSymbol(functionNode.getIdent().getName(), IS_VAR, functionNode); + newType(selfSymbol, Type.OBJECT); + selfSymbol.setNode(functionNode); + } + + /* + * This pushes all declarations (except for non-statements, i.e. for + * node temporaries) to 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 + */ + + final List declaredSymbols = new ArrayList<>(); + for (final VarNode decl : functionNode.getDeclarations()) { + final IdentNode ident = decl.getName(); + // any declared symbols that aren't visited need to be typed as well, hence the list + declaredSymbols.add(functionNode.defineSymbol(ident.getName(), IS_VAR, new IdentNode(ident))); + } + + // Every nested function needs a definition in the outer function with its name. Add these. + for (final FunctionNode nestedFunction : functionNode.getFunctions()) { + final VarNode varNode = nestedFunction.getFunctionVarNode(); + if (varNode != null) { + varNode.accept(this); + assert varNode.isFunctionVarNode() : varNode + " should be function var node"; + } + } + + for (final Node statement : functionNode.getStatements()) { + if (statement instanceof VarNode && ((VarNode)statement).isFunctionVarNode()) { + continue; //var nodes have already been processed, skip or they will generate additional defs/uses and false "can be undefined" + } + statement.accept(this); + } + + for (final FunctionNode nestedFunction : functionNode.getFunctions()) { + LOG.info("Going into nested function " + functionNode.getName() + " -> " + nestedFunction.getName()); + nestedFunction.accept(this); + } + + //unknown parameters are promoted to object type. + finalizeParameters(functionNode); + finalizeTypes(functionNode); + for (final Symbol symbol : declaredSymbols) { + if (symbol.getSymbolType().isUnknown()) { + symbol.setType(Type.OBJECT); + symbol.setCanBeUndefined(); + } + } + + if (functionNode.getReturnType().isUnknown()) { + LOG.info("Unknown return type promoted to object"); + functionNode.setReturnType(Type.OBJECT); + } + + if (functionNode.getSelfSymbolInit() != null) { + LOG.info("Accepting self symbol init " + functionNode.getSelfSymbolInit() + " for " + functionNode.getName()); + final Node init = functionNode.getSelfSymbolInit(); + final List newStatements = new ArrayList<>(); + newStatements.add(init); + newStatements.addAll(functionNode.getStatements()); + functionNode.setStatements(newStatements); + functionNode.setNeedsSelfSymbol(functionNode.getSelfSymbolInit().accept(this)); + } + + functionNode.popFrame(); + + end(functionNode, false); + + return null; + } + + @Override + public Node leaveCONVERT(final UnaryNode unaryNode) { + assert false : "There should be no convert operators in IR during Attribution"; + end(unaryNode); + return unaryNode; + } + + @Override + public Node enter(final IdentNode identNode) { + final String name = identNode.getName(); + + start(identNode); + + if (identNode.isPropertyName()) { + // assign a pseudo symbol to property name + final Symbol pseudoSymbol = pseudoSymbol(name); + LOG.info("IdentNode is property name -> assigning pseudo symbol " + pseudoSymbol); + LOG.unindent(); + identNode.setSymbol(pseudoSymbol); + return null; + } + + final Block block = getCurrentBlock(); + final Symbol oldSymbol = identNode.getSymbol(); + + Symbol symbol = block.findSymbol(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 (isFunctionExpressionSelfReference(symbol)) { + final FunctionNode functionNode = (FunctionNode)symbol.getNode(); + assert functionNode.getCalleeNode() != null; + + final VarNode var = new VarNode(functionNode.getSource(), functionNode.getToken(), functionNode.getFinish(), functionNode.getIdent(), functionNode.getCalleeNode()); + //newTemporary(Type.OBJECT, var); //ScriptFunction? TODO + + functionNode.setNeedsSelfSymbol(var); + } + + if (!identNode.isInitializedHere()) { // NASHORN-448 + // here is a use outside the local def scope + if (!isLocalDef(name)) { + newType(symbol, Type.OBJECT); + symbol.setCanBeUndefined(); + } + } + + identNode.setSymbol(symbol); + if (!getCurrentFunctionNode().isLocal(symbol)) { + // non-local: we need to put symbol in scope (if it isn't already) + if (!symbol.isScope()) { + final List lookupBlocks = findLookupBlocksHelper(getCurrentFunctionNode(), symbol.findFunction()); + for (final Block lookupBlock : lookupBlocks) { + final Symbol refSymbol = lookupBlock.findSymbol(name); + if (refSymbol != null) { // See NASHORN-837, function declaration in lexical scope: try {} catch (x){ function f() { use(x) } } f() + LOG.finest("Found a ref symbol that must be scope " + refSymbol); + refSymbol.setIsScope(); + } + } + } + } + } else { + LOG.info("No symbol exists. Declare undefined: " + symbol); + symbol = block.useSymbol(name, identNode); + // we have never seen this before, it can be undefined + newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway? + symbol.setCanBeUndefined(); + symbol.setIsScope(); + } + + assert symbol != null; + if(symbol.isGlobal()) { + getCurrentFunctionNode().setUsesGlobalSymbol(); + } else if(symbol.isScope()) { + getCurrentFunctionNode().setUsesScopeSymbol(symbol); + } + + if (symbol != oldSymbol && !identNode.isInitializedHere()) { + symbol.increaseUseCount(); + } + addLocalUse(identNode.getName()); + + end(identNode); + + return null; + } + + @Override + public Node leave(final IndexNode indexNode) { + newTemporary(Type.OBJECT, indexNode); //TORO + return indexNode; + } + + @SuppressWarnings("rawtypes") + @Override + public Node enter(final LiteralNode literalNode) { + try { + start(literalNode); + assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens + + if (literalNode instanceof ArrayLiteralNode) { + final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode; + final Node[] array = arrayLiteralNode.getValue(); + + for (int i = 0; i < array.length; i++) { + final Node element = array[i]; + if (element != null) { + array[i] = element.accept(this); + } + } + arrayLiteralNode.analyze(); + //array literal node now has an element type and all elements are attributed + } else { + assert !(literalNode.getValue() instanceof Node) : "literals with Node values not supported"; + } + + getCurrentFunctionNode().newLiteral(literalNode); + } finally { + end(literalNode); + } + return null; + } + + @Override + public Node leave(final ObjectNode objectNode) { + newTemporary(Type.OBJECT, objectNode); + end(objectNode); + return objectNode; + } + + @Override + public Node enter(final PropertyNode propertyNode) { + // assign a pseudo symbol to property name, see NASHORN-710 + propertyNode.setSymbol(new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT)); + end(propertyNode); + return propertyNode; + } + + @Override + public Node enter(final ReferenceNode referenceNode) { + final FunctionNode functionNode = referenceNode.getReference(); + if (functionNode != null) { + functionNode.addReferencingParentBlock(getCurrentBlock()); + } + return referenceNode; + } + + @Override + public Node leave(final ReferenceNode referenceNode) { + newTemporary(Type.OBJECT, referenceNode); //reference node type is always an object, i.e. the scriptFunction. the function return type varies though + + final FunctionNode functionNode = referenceNode.getReference(); + //assert !functionNode.getType().isUnknown() || functionNode.isLazy() : functionNode.getType(); + if (functionNode.isLazy()) { + LOG.info("Lazy function node call reference: " + functionNode.getName() + " => Promoting to OBJECT"); + functionNode.setReturnType(Type.OBJECT); + } + end(referenceNode); + + return referenceNode; + } + + @Override + public Node leave(final ReturnNode returnNode) { + final Node expr = returnNode.getExpression(); + + if (expr != null) { + //we can't do parameter specialization if we return something that hasn't been typed yet + final Symbol symbol = expr.getSymbol(); + if (expr.getType().isUnknown() && symbol.isParam()) { + symbol.setType(Type.OBJECT); + } + getCurrentFunctionNode().setReturnType(Type.widest(getCurrentFunctionNode().getReturnType(), symbol.getSymbolType())); + LOG.info("Returntype is now " + getCurrentFunctionNode().getReturnType()); + } + + end(returnNode); + + return returnNode; + } + + @Override + public Node leave(final SwitchNode switchNode) { + Type type = Type.UNKNOWN; + + for (final CaseNode caseNode : switchNode.getCases()) { + final Node test = caseNode.getTest(); + if (test != null) { + if (test instanceof LiteralNode) { + //go down to integers if we can + final LiteralNode lit = (LiteralNode)test; + if (lit.isNumeric() && !(lit.getValue() instanceof Integer)) { + if (JSType.isRepresentableAsInt(lit.getNumber())) { + caseNode.setTest(LiteralNode.newInstance(lit, lit.getInt32()).accept(this)); + } + } + } else { + // the "all integer" case that CodeGenerator optimizes for currently assumes literals only + type = Type.OBJECT; + break; + } + + type = Type.widest(type, caseNode.getTest().getType()); + } + } + + //only optimize for all integers + if (!type.isInteger()) { + type = Type.OBJECT; + } + + switchNode.setTag(newInternal(getCurrentFunctionNode().uniqueName(SWITCH_TAG_PREFIX.tag()), type)); + + end(switchNode); + + return switchNode; + } + + @Override + public Node leave(final TryNode tryNode) { + tryNode.setException(exceptionSymbol()); + + if (tryNode.getFinallyBody() != null) { + tryNode.setFinallyCatchAll(exceptionSymbol()); + } + + end(tryNode); + + return tryNode; + } + + @Override + public Node enter(final VarNode varNode) { + start(varNode); + + final IdentNode ident = varNode.getName(); + final String name = ident.getName(); + + final Symbol symbol = getCurrentBlock().defineSymbol(name, IS_VAR, ident); + assert symbol != null; + + LOG.info("VarNode " + varNode + " set symbol " + symbol); + varNode.setSymbol(symbol); + + // NASHORN-467 - use before definition of vars - conservative + if (localUses.contains(ident.getName())) { + newType(symbol, Type.OBJECT); + symbol.setCanBeUndefined(); + } + + if (varNode.getInit() != null) { + varNode.getInit().accept(this); + } + + return varNode; + } + + @Override + public Node leave(final VarNode varNode) { + final Node init = varNode.getInit(); + final IdentNode ident = varNode.getName(); + final String name = ident.getName(); + + if (init != null) { + addLocalDef(name); + } + + if (init == null) { + // var x; with no init will be treated like a use of x by + // visit(IdentNode) unless we remove the name + // from the localdef list. + removeLocalDef(name); + return varNode; + } + + final Symbol symbol = varNode.getSymbol(); + final boolean isScript = symbol.getBlock().getFunction().isScript(); //see NASHORN-56 + if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) { + // Forbid integers as local vars for now as we have no way to treat them as undefined + newType(symbol, init.getType()); + } else { + newType(symbol, Type.OBJECT); + } + + assert varNode.hasType() : varNode; + + end(varNode); + + return varNode; + } + + @Override + public Node leaveADD(final UnaryNode unaryNode) { + newTemporary(arithType(), unaryNode); + end(unaryNode); + return unaryNode; + } + + @Override + public Node leaveBIT_NOT(final UnaryNode unaryNode) { + newTemporary(Type.INT, unaryNode); + end(unaryNode); + return unaryNode; + } + + @Override + public Node leaveDECINC(final UnaryNode unaryNode) { + // @see assignOffset + ensureAssignmentSlots(getCurrentFunctionNode(), unaryNode.rhs()); + final Type type = arithType(); + newType(unaryNode.rhs().getSymbol(), type); + newTemporary(type, unaryNode); + end(unaryNode); + return unaryNode; + } + + @Override + public Node leaveDELETE(final UnaryNode unaryNode) { + final FunctionNode currentFunctionNode = getCurrentFunctionNode(); + final boolean strictMode = currentFunctionNode.isStrictMode(); + final Node rhs = unaryNode.rhs(); + final Node strictFlagNode = LiteralNode.newInstance(unaryNode, strictMode).accept(this); + + Request request = Request.DELETE; + final RuntimeNode runtimeNode; + final List args = new ArrayList<>(); + + if (rhs instanceof IdentNode) { + // If this is a declared variable or a function parameter, delete always fails (except for globals). + final String name = ((IdentNode)rhs).getName(); + + final boolean failDelete = strictMode || rhs.getSymbol().isParam() || (rhs.getSymbol().isVar() && !rhs.getSymbol().isTopLevel()); + + if (failDelete && rhs.getSymbol().isThis()) { + return LiteralNode.newInstance(unaryNode, true).accept(this); + } + final Node literalNode = LiteralNode.newInstance(unaryNode, name).accept(this); + + if (!failDelete) { + args.add(currentFunctionNode.getScopeNode()); + } + args.add(literalNode); + args.add(strictFlagNode); + + if (failDelete) { + request = Request.FAIL_DELETE; + } + } else if (rhs instanceof AccessNode) { + final Node base = ((AccessNode)rhs).getBase(); + final IdentNode property = ((AccessNode)rhs).getProperty(); + + args.add(base); + args.add(LiteralNode.newInstance(unaryNode, property.getName()).accept(this)); + args.add(strictFlagNode); + + } else if (rhs instanceof IndexNode) { + final Node base = ((IndexNode)rhs).getBase(); + final Node index = ((IndexNode)rhs).getIndex(); + + args.add(base); + args.add(index); + args.add(strictFlagNode); + + } else { + return LiteralNode.newInstance(unaryNode, true).accept(this); + } + + runtimeNode = new RuntimeNode(unaryNode, request, args); + assert runtimeNode.getSymbol() == unaryNode.getSymbol(); //clone constructor should do this + + runtimeNode.accept(this); + return runtimeNode; + } + + + @Override + public Node leaveNEW(final UnaryNode unaryNode) { + newTemporary(Type.OBJECT, unaryNode); + end(unaryNode); + return unaryNode; + } + + @Override + public Node leaveNOT(final UnaryNode unaryNode) { + newTemporary(Type.BOOLEAN, unaryNode); + end(unaryNode); + return unaryNode; + } + + @Override + public Node leaveTYPEOF(final UnaryNode unaryNode) { + final Node rhs = unaryNode.rhs(); + + RuntimeNode runtimeNode; + + List args = new ArrayList<>(); + if (rhs instanceof IdentNode && !rhs.getSymbol().isParam() && !rhs.getSymbol().isVar()) { + args.add(getCurrentFunctionNode().getScopeNode()); + args.add(LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null + } else { + args.add(rhs); + args.add(LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this' + } + + runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args); + assert runtimeNode.getSymbol() == unaryNode.getSymbol(); + + runtimeNode.accept(this); + + end(unaryNode); + + return runtimeNode; + } + + @Override + public Node leave(final RuntimeNode runtimeNode) { + newTemporary(runtimeNode.getRequest().getReturnType(), runtimeNode); + return runtimeNode; + } + + @Override + public Node leaveSUB(final UnaryNode unaryNode) { + newTemporary(arithType(), unaryNode); + end(unaryNode); + return unaryNode; + } + + @Override + public Node leaveVOID(final UnaryNode unaryNode) { + final RuntimeNode runtimeNode = new RuntimeNode(unaryNode, Request.VOID); + runtimeNode.accept(this); + assert runtimeNode.getSymbol().getSymbolType().isObject(); + end(unaryNode); + return runtimeNode; + } + + /** + * Add is a special binary, as it works not only on arithmetic, but for + * strings etc as well. + */ + @Override + public Node leaveADD(final BinaryNode binaryNode) { + final Node lhs = binaryNode.lhs(); + final Node rhs = binaryNode.rhs(); + + ensureTypeNotUnknown(lhs); + ensureTypeNotUnknown(rhs); + newTemporary(Type.widest(lhs.getType(), rhs.getType()), binaryNode); + + end(binaryNode); + + return binaryNode; + } + + @Override + public Node leaveAND(final BinaryNode binaryNode) { + newTemporary(Type.OBJECT, binaryNode); + end(binaryNode); + return binaryNode; + } + + /** + * This is a helper called before an assignment. + * @param binaryNode assignment node + */ + private Node enterAssignmentNode(final BinaryNode binaryNode) { + start(binaryNode); + + final Node lhs = binaryNode.lhs(); + + if (lhs instanceof IdentNode) { + final Block block = getCurrentBlock(); + final IdentNode ident = (IdentNode)lhs; + final String name = ident.getName(); + + Symbol symbol = getCurrentBlock().findSymbol(name); + + if (symbol == null) { + symbol = block.defineSymbol(name, IS_GLOBAL, ident); + binaryNode.setSymbol(symbol); + } else if (!getCurrentFunctionNode().isLocal(symbol)) { + symbol.setIsScope(); + } + + addLocalDef(name); + } + + return binaryNode; + } + + @Override + public Node enterASSIGN(final BinaryNode binaryNode) { + return enterAssignmentNode(binaryNode); + } + + @Override + public Node leaveASSIGN(final BinaryNode binaryNode) { + return leaveAssignmentNode(binaryNode); + } + + @Override + public Node enterASSIGN_ADD(final BinaryNode binaryNode) { + return enterAssignmentNode(binaryNode); + } + + @Override + public Node leaveASSIGN_ADD(final BinaryNode binaryNode) { + final Node lhs = binaryNode.lhs(); + final Node rhs = binaryNode.rhs(); + + final Type widest = Type.widest(lhs.getType(), rhs.getType()); + //Type.NUMBER if we can't prove that the add doesn't overflow. todo + return leaveSelfModifyingAssignmentNode(binaryNode, widest.isNumeric() ? Type.NUMBER : Type.OBJECT); + } + + @Override + public Node enterASSIGN_BIT_AND(final BinaryNode binaryNode) { + return enterAssignmentNode(binaryNode); + } + + @Override + public Node leaveASSIGN_BIT_AND(final BinaryNode binaryNode) { + return leaveSelfModifyingAssignmentNode(binaryNode); + } + + @Override + public Node enterASSIGN_BIT_OR(final BinaryNode binaryNode) { + return enterAssignmentNode(binaryNode); + } + + @Override + public Node leaveASSIGN_BIT_OR(final BinaryNode binaryNode) { + return leaveSelfModifyingAssignmentNode(binaryNode); + } + + @Override + public Node enterASSIGN_BIT_XOR(final BinaryNode binaryNode) { + return enterAssignmentNode(binaryNode); + } + + @Override + public Node leaveASSIGN_BIT_XOR(final BinaryNode binaryNode) { + return leaveSelfModifyingAssignmentNode(binaryNode); + } + + @Override + public Node enterASSIGN_DIV(final BinaryNode binaryNode) { + return enterAssignmentNode(binaryNode); + } + + @Override + public Node leaveASSIGN_DIV(final BinaryNode binaryNode) { + return leaveSelfModifyingAssignmentNode(binaryNode); + } + + @Override + public Node enterASSIGN_MOD(final BinaryNode binaryNode) { + return enterAssignmentNode(binaryNode); + } + + @Override + public Node leaveASSIGN_MOD(final BinaryNode binaryNode) { + return leaveSelfModifyingAssignmentNode(binaryNode); + } + + @Override + public Node enterASSIGN_MUL(final BinaryNode binaryNode) { + return enterAssignmentNode(binaryNode); + } + + @Override + public Node leaveASSIGN_MUL(final BinaryNode binaryNode) { + return leaveSelfModifyingAssignmentNode(binaryNode); + } + + @Override + public Node enterASSIGN_SAR(final BinaryNode binaryNode) { + return enterAssignmentNode(binaryNode); + } + + @Override + public Node leaveASSIGN_SAR(final BinaryNode binaryNode) { + return leaveSelfModifyingAssignmentNode(binaryNode); + } + + @Override + public Node enterASSIGN_SHL(final BinaryNode binaryNode) { + return enterAssignmentNode(binaryNode); + } + + @Override + public Node leaveASSIGN_SHL(final BinaryNode binaryNode) { + return leaveSelfModifyingAssignmentNode(binaryNode); + } + + @Override + public Node enterASSIGN_SHR(final BinaryNode binaryNode) { + return enterAssignmentNode(binaryNode); + } + + @Override + public Node leaveASSIGN_SHR(final BinaryNode binaryNode) { + return leaveSelfModifyingAssignmentNode(binaryNode); + } + + @Override + public Node enterASSIGN_SUB(final BinaryNode binaryNode) { + return enterAssignmentNode(binaryNode); + } + + @Override + public Node leaveASSIGN_SUB(final BinaryNode binaryNode) { + return leaveSelfModifyingAssignmentNode(binaryNode); + } + + @Override + public Node leaveBIT_AND(final BinaryNode binaryNode) { + newTemporary(Type.INT, binaryNode); + return binaryNode; + } + + @Override + public Node leaveBIT_OR(final BinaryNode binaryNode) { + newTemporary(Type.INT, binaryNode); + return binaryNode; + } + + @Override + public Node leaveBIT_XOR(final BinaryNode binaryNode) { + newTemporary(Type.INT, binaryNode); + return binaryNode; + } + + @Override + public Node leaveCOMMARIGHT(final BinaryNode binaryNode) { + newTemporary(binaryNode.rhs().getType(), binaryNode); + return binaryNode; + } + + @Override + public Node leaveCOMMALEFT(final BinaryNode binaryNode) { + newTemporary(binaryNode.lhs().getType(), binaryNode); + return binaryNode; + } + + @Override + public Node leaveDIV(final BinaryNode binaryNode) { + return leaveBinaryArithmetic(binaryNode); + } + + private Node leaveCmp(final BinaryNode binaryNode, final RuntimeNode.Request request) { + final Node lhs = binaryNode.lhs(); + final Node rhs = binaryNode.rhs(); + + newTemporary(Type.BOOLEAN, binaryNode); + ensureTypeNotUnknown(lhs); + ensureTypeNotUnknown(rhs); + + end(binaryNode); + return binaryNode; + } + + //leave a binary node and inherit the widest type of lhs , rhs + private Node leaveBinaryArithmetic(final BinaryNode binaryNode) { + if (!Compiler.shouldUseIntegerArithmetic()) { + newTemporary(Type.NUMBER, binaryNode); + return binaryNode; + } + newTemporary(Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType(), Type.NUMBER), binaryNode); + return binaryNode; + } + + @Override + public Node leaveEQ(final BinaryNode binaryNode) { + return leaveCmp(binaryNode, Request.EQ); + } + + @Override + public Node leaveEQ_STRICT(final BinaryNode binaryNode) { + return leaveCmp(binaryNode, Request.EQ_STRICT); + } + + @Override + public Node leaveGE(final BinaryNode binaryNode) { + return leaveCmp(binaryNode, Request.GE); + } + + @Override + public Node leaveGT(final BinaryNode binaryNode) { + return leaveCmp(binaryNode, Request.GT); + } + + @Override + public Node leaveIN(final BinaryNode binaryNode) { + try { + return new RuntimeNode(binaryNode, Request.IN).accept(this); + } finally { + end(binaryNode); + } + } + + @Override + public Node leaveINSTANCEOF(final BinaryNode binaryNode) { + try { + return new RuntimeNode(binaryNode, Request.INSTANCEOF).accept(this); + } finally { + end(binaryNode); + } + } + + @Override + public Node leaveLE(final BinaryNode binaryNode) { + return leaveCmp(binaryNode, Request.LE); + } + + @Override + public Node leaveLT(final BinaryNode binaryNode) { + return leaveCmp(binaryNode, Request.LT); + } + + @Override + public Node leaveMOD(final BinaryNode binaryNode) { + return leaveBinaryArithmetic(binaryNode); + } + + @Override + public Node leaveMUL(final BinaryNode binaryNode) { + return leaveBinaryArithmetic(binaryNode); + } + + @Override + public Node leaveNE(final BinaryNode binaryNode) { + return leaveCmp(binaryNode, Request.NE); + } + + @Override + public Node leaveNE_STRICT(final BinaryNode binaryNode) { + return leaveCmp(binaryNode, Request.NE_STRICT); + } + + @Override + public Node leaveOR(final BinaryNode binaryNode) { + newTemporary(Type.OBJECT, binaryNode); + end(binaryNode); + return binaryNode; + } + + @Override + public Node leaveSAR(final BinaryNode binaryNode) { + newTemporary(Type.INT, binaryNode); + end(binaryNode); + return binaryNode; + } + + @Override + public Node leaveSHL(final BinaryNode binaryNode) { + newTemporary(Type.INT, binaryNode); + end(binaryNode); + return binaryNode; + } + + @Override + public Node leaveSHR(final BinaryNode binaryNode) { + newTemporary(Type.LONG, binaryNode); + end(binaryNode); + return binaryNode; + } + + @Override + public Node leaveSUB(final BinaryNode binaryNode) { + return leaveBinaryArithmetic(binaryNode); + } + + @Override + public Node leave(final ForNode forNode) { + if (forNode.isForIn()) { + forNode.setIterator(newInternal(getCurrentFunctionNode(), getCurrentFunctionNode().uniqueName(ITERATOR_PREFIX.tag()), Type.OBJECT)); //NASHORN-73 + /* + * Iterators return objects, so we need to widen the scope of the + * init variable if it, for example, has been assigned double type + * see NASHORN-50 + */ + newType(forNode.getInit().getSymbol(), Type.OBJECT); + } + + end(forNode); + + return forNode; + } + + @Override + public Node leave(final TernaryNode ternaryNode) { + final Node lhs = ternaryNode.rhs(); + final Node rhs = ternaryNode.third(); + + ensureTypeNotUnknown(lhs); + ensureTypeNotUnknown(rhs); + + final Type type = Type.widest(lhs.getType(), rhs.getType()); + newTemporary(type, ternaryNode); + + end(ternaryNode); + + return ternaryNode; + } + + private static void initThis(final FunctionNode functionNode) { + final Symbol thisSymbol = functionNode.defineSymbol(THIS.tag(), IS_PARAM | IS_THIS, null); + newType(thisSymbol, Type.OBJECT); + thisSymbol.setNeedsSlot(true); + functionNode.getThisNode().setSymbol(thisSymbol); + LOG.info("Initialized scope symbol: " + thisSymbol); + } + + private static void initScope(final FunctionNode functionNode) { + final Symbol scopeSymbol = functionNode.defineSymbol(SCOPE.tag(), IS_VAR | IS_INTERNAL, null); + newType(scopeSymbol, Type.typeFor(ScriptObject.class)); + scopeSymbol.setNeedsSlot(true); + functionNode.getScopeNode().setSymbol(scopeSymbol); + LOG.info("Initialized scope symbol: " + scopeSymbol); + } + + private static void initReturn(final FunctionNode functionNode) { + final Symbol returnSymbol = functionNode.defineSymbol(SCRIPT_RETURN.tag(), IS_VAR | IS_INTERNAL, null); + newType(returnSymbol, Type.OBJECT); + returnSymbol.setNeedsSlot(true); + functionNode.getResultNode().setSymbol(returnSymbol); + LOG.info("Initialized return symbol: " + returnSymbol); + //return symbol is always object as it's the __return__ thing. What returnType is is another matter though + } + + private void initVarArg(final FunctionNode functionNode) { + if (functionNode.isVarArg()) { + final Symbol varArgsSymbol = functionNode.defineSymbol(VARARGS.tag(), IS_PARAM | IS_INTERNAL, null); + varArgsSymbol.setTypeOverride(Type.OBJECT_ARRAY); + varArgsSymbol.setNeedsSlot(true); + functionNode.getVarArgsNode().setSymbol(varArgsSymbol); + LOG.info("Initialized varargs symbol: " + varArgsSymbol); + + if (functionNode.needsArguments()) { + final String argumentsName = functionNode.getArgumentsNode().getName(); + final Symbol argumentsSymbol = functionNode.defineSymbol(argumentsName, IS_VAR | IS_INTERNAL, null); + newType(argumentsSymbol, Type.typeFor(ScriptObject.class)); + argumentsSymbol.setNeedsSlot(true); + functionNode.getArgumentsNode().setSymbol(argumentsSymbol); + addLocalDef(argumentsName); + LOG.info("Initialized vararg varArgsSymbol=" + varArgsSymbol + " argumentsSymbol=" + argumentsSymbol); + } + } + } + + private static void initCallee(final FunctionNode functionNode) { + assert functionNode.getCalleeNode() != null : functionNode + " has no callee"; + final Symbol calleeSymbol = functionNode.defineSymbol(CALLEE.tag(), IS_PARAM | IS_INTERNAL, null); + newType(calleeSymbol, Type.typeFor(ScriptFunction.class)); + calleeSymbol.setNeedsSlot(true); + functionNode.getCalleeNode().setSymbol(calleeSymbol); + LOG.info("Initialized callee symbol " + calleeSymbol); + } + + /** + * Initialize parameters for function node. This may require specializing + * types if a specialization profile is known + * + * @param functionNode the function node + */ + private void initParameters(final FunctionNode functionNode) { + //If a function is specialized, we don't need to tag either it return + // type or its parameters with the widest (OBJECT) type for safety. + functionNode.setReturnType(Type.UNKNOWN); + + for (final IdentNode ident : functionNode.getParameters()) { + addLocalDef(ident.getName()); + final Symbol paramSymbol = functionNode.defineSymbol(ident.getName(), IS_PARAM, ident); + if (paramSymbol != null) { + newType(paramSymbol, Type.UNKNOWN); + } + + LOG.info("Initialized param " + paramSymbol); + } + } + + /** + * 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 static void finalizeParameters(final FunctionNode functionNode) { + boolean nonObjectParams = false; + List paramSpecializations = new ArrayList<>(); + + for (final IdentNode ident : functionNode.getParameters()) { + final Symbol paramSymbol = ident.getSymbol(); + if (paramSymbol != null) { + Type type = paramSymbol.getSymbolType(); + if (type.isUnknown()) { + type = Type.OBJECT; + } + paramSpecializations.add(type); + if (!type.isObject()) { + nonObjectParams = true; + } + newType(paramSymbol, Type.OBJECT); + } + } + + if (!nonObjectParams) { + paramSpecializations = null; + // Later, when resolving a call to this method, the linker can say "I have a double, an int and an object" as parameters + // here. If the callee has parameter specializations, we can regenerate it with those particular types for speed. + } else { + LOG.info("parameter specialization possible: " + functionNode.getName() + " " + paramSpecializations); + } + + // parameters should not be slots for a function that uses variable arity signature + if (functionNode.isVarArg()) { + for (final IdentNode param : functionNode.getParameters()) { + param.getSymbol().setNeedsSlot(false); + } + } + } + + /** + * Move any properties from a global map into the scope of this method + * @param functionNode the function node for which to init scope vars + */ + private static void initFromPropertyMap(final FunctionNode functionNode) { + // For a script, add scope symbols as defined in the property map + assert functionNode.isScript(); + + final PropertyMap map = Context.getGlobalMap(); + + for (final Property property : map.getProperties()) { + final String key = property.getKey(); + final Symbol symbol = functionNode.defineSymbol(key, IS_GLOBAL, null); + newType(symbol, Type.OBJECT); + LOG.info("Added global symbol from property map " + symbol); + } + } + + private static void ensureTypeNotUnknown(final Node node) { + + final Symbol symbol = node.getSymbol(); + + LOG.info("Ensure type not unknown for: " + symbol); + + /* + * Note that not just unknowns, but params need to be blown + * up to objects, because we can have something like + * + * function f(a) { + * var b = ~a; //b and a are inferred to be int + * return b; + * } + * + * In this case, it would be correct to say that "if you have + * an int at the callsite, just pass it". + * + * However + * + * function f(a) { + * var b = ~a; //b and a are inferred to be int + * return b == 17; //b is still inferred to be int. + * } + * + * can be called with f("17") and if we assume that b is an + * int and don't blow it up to an object in the comparison, we + * are screwed. I hate JavaScript. + * + * This check has to be done for any operation that might take + * objects as parameters, for example +, but not *, which is known + * to coerce types into doubles + */ + if (node.getType().isUnknown() || symbol.isParam()) { + newType(symbol, Type.OBJECT); + symbol.setCanBeUndefined(); + } + } + + private static Symbol pseudoSymbol(final String name) { + return new Symbol(name, 0, Type.OBJECT); + } + + private Symbol exceptionSymbol() { + return newInternal(getCurrentFunctionNode().uniqueName(EXCEPTION_PREFIX.tag()), Type.typeFor(ECMAException.class)); + } + + /** + * In an assignment, recursively make sure that there are slots for + * everything that has to be laid out as temporary storage, which is the + * case if we are assign-op:ing a BaseNode subclass. This has to be + * recursive to handle things like multi dimensional arrays as lhs + * + * see NASHORN-258 + * + * @param functionNode the current function node (has to be passed as it changes in the visitor below) + * @param assignmentDest the destination node of the assignment, e.g. lhs for binary nodes + */ + private static void ensureAssignmentSlots(final FunctionNode functionNode, final Node assignmentDest) { + assignmentDest.accept(new NodeVisitor() { + @Override + public Node leave(final IndexNode indexNode) { + final Node index = indexNode.getIndex(); + index.getSymbol().setNeedsSlot(!index.getSymbol().isConstant()); + return indexNode; + } + }); + } + + /** + * Return the type that arithmetic ops should use. Until we have implemented better type + * analysis (range based) or overflow checks that are fast enough for int arithmetic, + * this is the number type + * @return the arithetic type + */ + private static Type arithType() { + return Compiler.shouldUseIntegerArithmetic() ? Type.INT : Type.NUMBER; + } + + /** + * If types have changed, we can have failed to update vars. For example + * + * var x = 17; //x is int + * x = "apa"; //x is object. This will be converted fine + * + * @param functionNode + */ + private static void finalizeTypes(final FunctionNode functionNode) { + final Set changed = new HashSet<>(); + do { + changed.clear(); + functionNode.accept(new NodeVisitor() { + + private void widen(final Node node, final Type to) { + if (node instanceof LiteralNode) { + return; + } + Type from = node.getType(); + if (!Type.areEquivalent(from, to) && Type.widest(from, to) == to) { + LOG.fine("Had to post pass widen '" + node + "' " + Debug.id(node) + " from " + node.getType() + " to " + to); + newType(node.getSymbol(), to); + changed.add(node); + } + } + + @Override + public Node enter(final FunctionNode node) { + return node.isLazy() ? null : node; + } + + /** + * Eg. + * + * var d = 17; + * var e; + * e = d; //initially typed as int for node type, should retype as double + * e = object; + * + * var d = 17; + * var e; + * e -= d; //initially type number, should number remain with a final conversion supplied by Store. ugly, but the computation result of the sub is numeric + * e = object; + * + */ + @SuppressWarnings("fallthrough") + @Override + public Node leave(final BinaryNode binaryNode) { + final Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType()); + switch (binaryNode.tokenType()) { + default: + if (!binaryNode.isAssignment() || binaryNode.isSelfModifying()) { + break; + } + widen(binaryNode.lhs(), widest); + case ADD: + widen(binaryNode, widest); + break; + } + return binaryNode; + } + }); + } while (!changed.isEmpty()); + } + + /** + * This assign helper is called after an assignment, when all children of + * the assign has been processed. It fixes the types and recursively makes + * sure that everyhing has slots that should have them in the chain. + * + * @param binaryNode assignment node + */ + private Node leaveAssignmentNode(final BinaryNode binaryNode) { + final Node lhs = binaryNode.lhs(); + final Node rhs = binaryNode.rhs(); + + final Type type; + if (rhs.getType().isNumeric()) { + type = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType()); + } else { + type = Type.OBJECT; //force lhs to be an object if not numeric assignment, e.g. strings too. + } + newTemporary(type, binaryNode); + newType(lhs.getSymbol(), type); + end(binaryNode); + return binaryNode; + } + + private Node leaveSelfModifyingAssignmentNode(final BinaryNode binaryNode) { + return leaveSelfModifyingAssignmentNode(binaryNode, binaryNode.getWidestOperationType()); + } + + private Node leaveSelfModifyingAssignmentNode(final BinaryNode binaryNode, final Type destType) { + //e.g. for -=, Number, no wider, destType (binaryNode.getWidestOperationType()) is the coerce type + final Node lhs = binaryNode.lhs(); + + newType(lhs.getSymbol(), destType); //may not narrow if dest is already wider than destType + newTemporary(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine + + ensureAssignmentSlots(getCurrentFunctionNode(), binaryNode); + + end(binaryNode); + return binaryNode; + } + + private static List findLookupBlocksHelper(final FunctionNode currentFunction, final FunctionNode topFunction) { + if (currentFunction.findParentFunction() == topFunction) { + final List blocks = new LinkedList<>(); + + blocks.add(currentFunction.getParent()); + blocks.addAll(currentFunction.getReferencingParentBlocks()); + return blocks; + } + /* + * assumption: all parent blocks of an inner function will always be in the same outer function; + * therefore we can simply skip through intermediate functions. + * @see FunctionNode#addReferencingParentBlock(Block) + */ + return findLookupBlocksHelper(currentFunction.findParentFunction(), topFunction); + } + + private static boolean isFunctionExpressionSelfReference(final Symbol symbol) { + if (symbol.isVar() && symbol.getNode() == symbol.getBlock() && symbol.getNode() instanceof FunctionNode) { + return ((FunctionNode)symbol.getNode()).getIdent().getName().equals(symbol.getName()); + } + return false; + } + + private static Symbol newTemporary(final FunctionNode functionNode, final Type type, final Node node) { + LOG.info("New TEMPORARY added to " + functionNode.getName() + " type=" + type); + return functionNode.newTemporary(type, node); + } + + private Symbol newTemporary(final Type type, final Node node) { + return newTemporary(getCurrentFunctionNode(), type, node); + } + + private Symbol newInternal(final FunctionNode functionNode, final String name, final Type type) { + final Symbol iter = getCurrentFunctionNode().defineSymbol(name, IS_VAR | IS_INTERNAL, null); + iter.setType(type); // NASHORN-73 + return iter; + } + + private Symbol newInternal(final String name, final Type type) { + return newInternal(getCurrentFunctionNode(), name, type); + } + + private static void newType(final Symbol symbol, final Type type) { + final Type oldType = symbol.getSymbolType(); + symbol.setType(type); + + if (symbol.getSymbolType() != oldType) { + LOG.info("New TYPE " + type + " for " + symbol + " (was " + oldType + ")"); + } + + if (symbol.isParam()) { + symbol.setType(type); + LOG.info("Param type change " + symbol); + } + } + + private void clearLocalDefs() { + localDefs = new HashSet<>(); + } + + private boolean isLocalDef(final String name) { + return localDefs.contains(name); + } + + private void addLocalDef(final String name) { + LOG.info("Adding local def of symbol: '" + name + "'"); + localDefs.add(name); + } + + private void removeLocalDef(final String name) { + LOG.info("Removing local def of symbol: '" + name + "'"); + localDefs.remove(name); + } + + private void clearLocalUses() { + localUses = new HashSet<>(); + } + + private void addLocalUse(final String name) { + LOG.info("Adding local use of symbol: '" + name + "'"); + localUses.add(name); + } + + private static String name(final Node node) { + final String cn = node.getClass().getName(); + int lastDot = cn.lastIndexOf('.'); + if (lastDot == -1) { + return cn; + } + return cn.substring(lastDot + 1); + } + + private Node start(final Node node) { + return start(node, true); + } + + private Node 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(getCurrentFunctionNode().getName()). + append("'"); + LOG.info(sb.toString()); + LOG.indent(); + } + + return node; + } + + private Node end(final Node node) { + return end(node, true); + } + + private Node end(final Node 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(getCurrentFunctionNode().getName()); + + if (node.getSymbol() == null) { + sb.append(" "); + } else { + sb.append(" '); + } + + LOG.unindent(); + LOG.info(sb.toString()); + } + + return node; + } +} diff --git a/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java b/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java new file mode 100644 index 00000000000..84cef43764a --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java @@ -0,0 +1,199 @@ +/* + * 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.Condition.EQ; +import static jdk.nashorn.internal.codegen.Condition.GE; +import static jdk.nashorn.internal.codegen.Condition.GT; +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.Label; +import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.BinaryNode; +import jdk.nashorn.internal.ir.Node; +import jdk.nashorn.internal.ir.TernaryNode; +import jdk.nashorn.internal.ir.UnaryNode; + +/** + * Branch optimizer for CodeGenerator. Given a jump condition this helper + * class attempts to simplify the control flow + */ +final class BranchOptimizer { + + private final CodeGenerator codegen; + private final MethodEmitter method; + + BranchOptimizer(final CodeGenerator codegen, final MethodEmitter method) { + this.codegen = codegen; + this.method = method; + } + + void execute(final Node node, final Label label, final boolean state) { + branchOptimizer(node, label, state); + } + + private void load(final Node node) { + codegen.load(node); + } + + private void branchOptimizer(final UnaryNode unaryNode, final Label label, final boolean state) { + final Node rhs = unaryNode.rhs(); + + switch (unaryNode.tokenType()) { + case NOT: + branchOptimizer(rhs, label, !state); + return; + case CONVERT: + if (unaryNode.getType().isBoolean()) { + branchOptimizer(rhs, label, state); + return; + } + break; + default: + break; + } + + // convert to boolean + load(unaryNode); + method.convert(Type.BOOLEAN); + if (state) { + method.ifne(label); + } else { + method.ifeq(label); + } + } + + private void branchOptimizer(final BinaryNode binaryNode, final Label label, final boolean state) { + final Node lhs = binaryNode.lhs(); + final Node rhs = binaryNode.rhs(); + + switch (binaryNode.tokenType()) { + case AND: + if (state) { + final Label skip = new Label("skip"); + branchOptimizer(lhs, skip, false); + branchOptimizer(rhs, label, true); + method.label(skip); + } else { + branchOptimizer(lhs, label, false); + branchOptimizer(rhs, label, false); + } + return; + + case OR: + if (state) { + branchOptimizer(lhs, label, true); + branchOptimizer(rhs, label, true); + } else { + final Label skip = new Label("skip"); + branchOptimizer(lhs, skip, true); + branchOptimizer(rhs, label, false); + method.label(skip); + } + return; + + case EQ: + case EQ_STRICT: + assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol(); + load(lhs); + load(rhs); + method.conditionalJump(state ? EQ : NE, true, label); + return; + + case NE: + case NE_STRICT: + assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol(); + load(lhs); + load(rhs); + method.conditionalJump(state ? NE : EQ, true, label); + return; + + case GE: + assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol(); + load(lhs); + load(rhs); + method.conditionalJump(state ? GE : LT, !state, label); + return; + + case GT: + assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol(); + load(lhs); + load(rhs); + method.conditionalJump(state ? GT : LE, !state, label); + return; + + case LE: + assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol(); + load(lhs); + load(rhs); + method.conditionalJump(state ? LE : GT, state, label); + return; + + case LT: + assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol() + " in " + binaryNode; + load(lhs); + load(rhs); + method.conditionalJump(state ? LT : GE, state, label); + return; + + default: + break; + } + + load(binaryNode); + method.convert(Type.BOOLEAN); + if (state) { + method.ifne(label); + } else { + method.ifeq(label); + } + } + + private void branchOptimizer(final Node 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; + } + } + + load(node); + method.convert(Type.BOOLEAN); + if (state) { + method.ifne(label); + } else { + method.ifeq(label); + } + } +} diff --git a/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java b/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java new file mode 100644 index 00000000000..35e74824958 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java @@ -0,0 +1,623 @@ +/* + * 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.internal.org.objectweb.asm.Opcodes.ACC_FINAL; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE; +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.ACC_SUPER; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKEINTERFACE; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESPECIAL; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; +import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKEVIRTUAL; +import static jdk.internal.org.objectweb.asm.Opcodes.H_NEWINVOKESPECIAL; +import static jdk.internal.org.objectweb.asm.Opcodes.V1_7; +import static jdk.nashorn.internal.codegen.CompilerConstants.CLINIT; +import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS; +import static jdk.nashorn.internal.codegen.CompilerConstants.GET_ARRAY_PREFIX; +import static jdk.nashorn.internal.codegen.CompilerConstants.GET_ARRAY_SUFFIX; +import static jdk.nashorn.internal.codegen.CompilerConstants.GET_MAP; +import static jdk.nashorn.internal.codegen.CompilerConstants.GET_STRING; +import static jdk.nashorn.internal.codegen.CompilerConstants.INIT; +import static jdk.nashorn.internal.codegen.CompilerConstants.SET_MAP; +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 java.io.ByteArrayOutputStream; +import java.io.PrintWriter; +import java.util.Arrays; +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.runtime.PropertyMap; +import jdk.nashorn.internal.runtime.ScriptEnvironment; +import jdk.nashorn.internal.runtime.ScriptObject; +import jdk.nashorn.internal.runtime.Source; + +/** + * The interface responsible for speaking to ASM, emitting classes, + * fields and methods. + *

+ * This file contains the ClassEmitter, which is the master object + * responsible for writing byte codes. It utilizes a MethodEmitter + * for method generation, which also the NodeVisitors own, to keep + * track of the current code generator and what it is doing. + *

+ * There is, however, nothing stopping you from using this in a + * completely self contained environment, for example in ObjectGenerator + * where there are no visitors or external hooks. + *

+ * MethodEmitter makes it simple to generate code for methods without + * having to do arduous type checking. It maintains a type stack + * and will pick the appropriate operation for all operations sent to it + * We also allow chained called to a MethodEmitter for brevity, e.g. + * it is legal to write _new(className).dup() or + * load(slot).load(slot2).xor().store(slot3); + *

+ * If running with assertions enabled, any type conflict, such as different + * bytecode stack sizes or operating on the wrong type will be detected + * and an error thrown. + *

+ * There is also a very nice debug interface that can emit formatted + * bytecodes that have been written. This is enabled by setting the + * environment "nashorn.codegen.debug" to true, or --log=codegen:{@literal } + *

+ * A ClassEmitter implements an Emitter - i.e. it needs to have + * well defined start and end calls for whatever it is generating. Assertions + * detect if this is not true + * + * @see Compiler + */ +public class ClassEmitter implements Emitter { + + /** Sanity check flag - have we started on a class? */ + private boolean classStarted; + + /** Sanity check flag - have we ended this emission? */ + private boolean classEnded; + + /** + * Sanity checks - which methods have we currently + * started for generation in this class? + */ + private final HashSet methodsStarted; + + /** The ASM classwriter that we use for all bytecode operations */ + protected final ClassWriter cw; + + /** The script environment */ + protected final ScriptEnvironment env; + + /** Default flags for class generation - oublic class */ + private static final EnumSet DEFAULT_METHOD_FLAGS = EnumSet.of(Flag.PUBLIC); + + /** Compile unit class name. */ + private String unitClassName; + + /** Set of constants access methods required. */ + private Set> constantMethodNeeded; + + /** + * Constructor - only used internally in this class as it breaks + * abstraction towards ASM or other code generator below + * + * @param env script environment + * @param cw ASM classwriter + */ + private ClassEmitter(final ScriptEnvironment env, final ClassWriter cw) { + assert env != null; + + this.env = env; + this.cw = cw; + this.methodsStarted = new HashSet<>(); + } + + /** + * Constructor + * + * @param env script environment + * @param className name of class to weave + * @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)); + cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, className, null, superClassName, interfaceNames); + } + + /** + * Constructor from the compiler + * + * @param compiler Compiler + * @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, + new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) { + private static final String OBJECT_CLASS = "java/lang/Object"; + + @Override + protected String getCommonSuperClass(final String type1, final String type2) { + try { + return super.getCommonSuperClass(type1, type2); + } catch (final RuntimeException e) { + if (isScriptObject(Compiler.SCRIPTS_PACKAGE, type1) && isScriptObject(Compiler.SCRIPTS_PACKAGE, type2)) { + return className(ScriptObject.class); + } + return OBJECT_CLASS; + } + } + }); + + this.unitClassName = unitClassName; + this.constantMethodNeeded = new HashSet<>(); + + cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, unitClassName, null, pathName(jdk.nashorn.internal.scripts.JS.class.getName()), null); + cw.visitSource(sourceName, null); + + defineCommonStatics(strictMode); + } + + /** + * Convert a binary name to a package/class name. + * + * @param name Binary name. + * @return Package/class name. + */ + private static String pathName(final String name) { + return name.replace('.', '/'); + } + + /** + * Define the static fields common in all scripts. + * @param strictMode Should we generate this method in strict mode + */ + private void defineCommonStatics(final boolean strictMode) { + // source - used to store the source data (text) for this script. Shared across + // compile units. Set externally by the compiler. + field(EnumSet.of(Flag.PRIVATE, Flag.STATIC), SOURCE.tag(), Source.class); + + // constants - used to the constants array for this script. Shared across + // compile units. Set externally by the compiler. + field(EnumSet.of(Flag.PRIVATE, Flag.STATIC), CONSTANTS.tag(), Object[].class); + + // strictMode - was this script compiled in strict mode. Set externally by the compiler. + field(EnumSet.of(Flag.PUBLIC, Flag.STATIC, Flag.FINAL), STRICT_MODE.tag(), boolean.class, strictMode); + } + + /** + * Define static utilities common needed in scripts. These are per compile unit + * and therefore have to be defined here and not in code gen. + */ + private void defineCommonUtilities() { + assert unitClassName != null; + + if (constantMethodNeeded.contains(String.class)) { + // $getString - get the ith entry from the constants table and cast to String. + final MethodEmitter getStringMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), GET_STRING.tag(), String.class, int.class); + getStringMethod.begin(); + getStringMethod.getStatic(unitClassName, CONSTANTS.tag(), CONSTANTS.descriptor()) + .load(Type.INT, 0) + .arrayload() + .checkcast(String.class) + ._return(); + getStringMethod.end(); + } + + if (constantMethodNeeded.contains(PropertyMap.class)) { + // $getMap - get the ith entry from the constants table and cast to PropertyMap. + final MethodEmitter getMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), GET_MAP.tag(), PropertyMap.class, int.class); + getMapMethod.begin(); + getMapMethod.loadConstants(unitClassName) + .load(Type.INT, 0) + .arrayload() + .checkcast(PropertyMap.class) + ._return(); + getMapMethod.end(); + + // $setMap - overwrite an existing map. + final MethodEmitter setMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), SET_MAP.tag(), void.class, int.class, PropertyMap.class); + setMapMethod.begin(); + setMapMethod.loadConstants(unitClassName) + .load(Type.INT, 0) + .load(Type.OBJECT, 1) + .arraystore(); + setMapMethod.returnVoid(); + setMapMethod.end(); + } + + // $getXXXX$array - get the ith entry from the constants table and cast to XXXX[]. + for (final Class cls : constantMethodNeeded) { + if (cls.isArray()) { + defineGetArrayMethod(cls); + } + } + } + + /** + * Constructs a primitive specific method for getting the ith entry from the constants table and cast. + * @param cls Array class. + */ + private void defineGetArrayMethod(final Class cls) { + assert unitClassName != null; + + final String methodName = getArrayMethodName(cls); + final MethodEmitter getArrayMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), methodName, cls, int.class); + + getArrayMethod.begin(); + getArrayMethod.getStatic(unitClassName, CONSTANTS.tag(), CONSTANTS.descriptor()) + .load(Type.INT, 0) + .arrayload() + .checkcast(cls) + .dup() + .arraylength() + .invoke(staticCallNoLookup(Arrays.class, "copyOf", cls, cls, int.class)) + ._return(); + getArrayMethod.end(); + } + + /** + * Generate the name of a get array from constant pool method. + * @param cls Name of array class. + * @return Method name. + */ + static String getArrayMethodName(final Class cls) { + assert cls.isArray(); + return GET_ARRAY_PREFIX.tag() + cls.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.tag(); + } + + /** + * Ensure a get constant method is issued for the class. + * @param cls Class of constant. + */ + void needGetConstantMethod(final Class cls) { + constantMethodNeeded.add(cls); + } + + /** + * Inspect class name and decide whether we are generating a ScriptObject class + * + * @param scriptPrefix the script class prefix for the current script + * @param type the type to check + * + * @return true if type is ScriptObject + */ + private static boolean isScriptObject(final String scriptPrefix, final String type) { + if (type.startsWith(scriptPrefix)) { + return true; + } else if (type.equals(CompilerConstants.className(ScriptObject.class))) { + return true; + } else if (type.startsWith(Compiler.OBJECTS_PACKAGE)) { + return true; + } + + return false; + } + + /** + * Call at beginning of class emission + * @see Emitter + */ + @Override + public void begin() { + classStarted = true; + } + + /** + * Call at end of class emission + * @see Emitter + */ + @Override + public void end() { + assert classStarted; + + if (unitClassName != null) { + defineCommonUtilities(); + } + + cw.visitEnd(); + classStarted = false; + classEnded = true; + assert methodsStarted.isEmpty() : "methodsStarted not empty " + methodsStarted; + } + + /** + * Disassemble an array of byte code. + * @param bytecode byte array representing bytecode + * @return disassembly as human readable string + */ + 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); + } + return new String(baos.toByteArray()); + } + + /** + * @return env used for class emission + */ + ScriptEnvironment getEnv() { + return env; + } + + /** + * Call back from MethodEmitter for method start + * + * @see MethodEmitter + * + * @param method method emitter. + */ + void beginMethod(final MethodEmitter method) { + assert !methodsStarted.contains(method); + methodsStarted.add(method); + } + + /** + * Call back from MethodEmitter for method end + * + * @see MethodEmitter + * + * @param method + */ + void endMethod(final MethodEmitter method) { + assert methodsStarted.contains(method); + methodsStarted.remove(method); + } + + /** + * Add a new method to the class - defaults to public method + * + * @param methodName name of method + * @param rtype return type of the method + * @param ptypes parameter types the method + * + * @return method emitter to use for weaving this method + */ + MethodEmitter method(final String methodName, final Class rtype, final Class... ptypes) { + return method(DEFAULT_METHOD_FLAGS, methodName, rtype, ptypes); //TODO why public default ? + } + + /** + * Add a new method to the class - defaults to public method + * + * @param methodFlags access flags for the method + * @param methodName name of method + * @param rtype return type of the method + * @param ptypes parameter types the method + * + * @return method emitter to use for weaving this method + */ + MethodEmitter method(final EnumSet methodFlags, final String methodName, final Class rtype, final Class... ptypes) { + return new MethodEmitter(this, cw.visitMethod(Flag.getValue(methodFlags), methodName, methodDescriptor(rtype, ptypes), null, null)); + } + + /** + * Add a new method to the class - defaults to public method + * + * @param methodName name of method + * @param descriptor descriptor of method + * + * @return method emitter to use for weaving this method + */ + MethodEmitter method(final String methodName, final String descriptor) { + return method(DEFAULT_METHOD_FLAGS, methodName, descriptor); + } + + /** + * Add a new method to the class - defaults to public method + * + * @param methodFlags access flags for the method + * @param methodName name of method + * @param descriptor descriptor of method + * + * @return method emitter to use for weaving this method + */ + MethodEmitter method(final EnumSet methodFlags, final String methodName, final String descriptor) { + return new MethodEmitter(this, cw.visitMethod(Flag.getValue(methodFlags), methodName, descriptor, null, null)); + } + + /** + * Add a new method to the class, representing a function node + * + * @param functionNode the function node to generate a method for + * @return method emitter to use for weaving this method + */ + MethodEmitter method(final FunctionNode functionNode) { + final MethodVisitor mv = cw.visitMethod( + ACC_PUBLIC | ACC_STATIC | (functionNode.isVarArg() ? ACC_VARARGS : 0), + functionNode.getName(), + new FunctionSignature(functionNode).toString(), + null, + null); + + return new MethodEmitter(this, mv, functionNode); + } + + /** + * Start generating the method in the class + * + * @return method emitter to use for weaving + */ + MethodEmitter clinit() { + return method(EnumSet.of(Flag.STATIC), CLINIT.tag(), void.class); + } + + /** + * Start generating an ()V method in the class + * + * @return method emitter to use for weaving ()V + */ + MethodEmitter init() { + return method(INIT.tag(), void.class); + } + + /** + * Start generating an ()V method in the class + * + * @param ptypes parameter types for constructor + * @return method emitter to use for weaving ()V + */ + MethodEmitter init(final Class... ptypes) { + return method(INIT.tag(), void.class, ptypes); + } + + /** + * Start generating an (...)V method in the class + * + * @param flags access flags for the constructor + * @param ptypes parameter types for the constructor + * + * @return method emitter to use for weaving (...)V + */ + MethodEmitter init(final EnumSet flags, final Class... ptypes) { + return method(flags, INIT.tag(), void.class, ptypes); + } + + /** + * Add a field to the class, initialized to a value + * + * @param fieldFlags flags, e.g. should it be static or public etc + * @param fieldName name of field + * @param fieldType the type of the field + * @param value the value + * + * @see ClassEmitter.Flag + */ + final void field(final EnumSet fieldFlags, final String fieldName, final Class fieldType, final Object value) { + cw.visitField(Flag.getValue(fieldFlags), fieldName, typeDescriptor(fieldType), null, value).visitEnd(); + } + + /** + * Add a field to the class + * + * @param fieldFlags access flags for the field + * @param fieldName name of field + * @param fieldType type of the field + * + * @see ClassEmitter.Flag + */ + final void field(final EnumSet fieldFlags, final String fieldName, final Class fieldType) { + field(fieldFlags, fieldName, fieldType, null); + } + + /** + * Add a field to the class - defaults to public + * + * @param fieldName name of field + * @param fieldType type of field + */ + final void field(final String fieldName, final Class fieldType) { + field(EnumSet.of(Flag.PUBLIC), fieldName, fieldType, null); + } + + /** + * Return a bytecode array from this ClassEmitter. The ClassEmitter must + * have been ended (having its end function called) for this to work. + * + * @return byte code array for generated class, null if class generation hasn't been ended with {@link ClassEmitter#end()} + */ + byte[] toByteArray() { + assert classEnded; + if (!classEnded) { + return null; + } + + return cw.toByteArray(); + } + + /** + * Abstraction for flags used in class emission + * + * We provide abstraction separating these from the underlying bytecode + * emitter. + * + * Flags are provided for method handles, protection levels, static/virtual + * fields/methods. + */ + static enum Flag { + /** method handle with static access */ + HANDLE_STATIC(H_INVOKESTATIC), + /** method handle with new invoke special access */ + HANDLE_NEWSPECIAL(H_NEWINVOKESPECIAL), + /** method handle with invoke special access */ + HANDLE_SPECIAL(H_INVOKESPECIAL), + /** method handle with invoke virtual access */ + HANDLE_VIRTUAL(H_INVOKEVIRTUAL), + /** method handle with invoke interface access */ + HANDLE_INTERFACE(H_INVOKEINTERFACE), + + /** final access */ + FINAL(ACC_FINAL), + /** static access */ + STATIC(ACC_STATIC), + /** public access */ + PUBLIC(ACC_PUBLIC), + /** private access */ + PRIVATE(ACC_PRIVATE); + + private int value; + + private Flag(final int value) { + this.value = value; + } + + /** + * Get the value of this flag + * @return the int value + */ + int getValue() { + return value; + } + + /** + * Return the corresponding ASM flag value for an enum set of flags + * + * @param flags enum set of flags + * @return an integer value representing the flags intrinsic values or:ed together + */ + static int getValue(final EnumSet flags) { + int v = 0; + for (final Flag flag : flags) { + v |= flag.getValue(); + } + return v; + } + } +} diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java new file mode 100644 index 00000000000..2ffb5bd887d --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -0,0 +1,3315 @@ +/* + * 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.ClassEmitter.Flag.HANDLE_STATIC; +import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.PRIVATE; +import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.STATIC; +import static jdk.nashorn.internal.codegen.CompilerConstants.ALLOCATE; +import static jdk.nashorn.internal.codegen.CompilerConstants.GET_MAP; +import static jdk.nashorn.internal.codegen.CompilerConstants.GET_STRING; +import static jdk.nashorn.internal.codegen.CompilerConstants.LEAF; +import static jdk.nashorn.internal.codegen.CompilerConstants.QUICK_PREFIX; +import static jdk.nashorn.internal.codegen.CompilerConstants.REGEX_PREFIX; +import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; +import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_ARRAY_ARG; +import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX; +import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup; +import static jdk.nashorn.internal.codegen.CompilerConstants.interfaceCallNoLookup; +import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor; +import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; +import static jdk.nashorn.internal.codegen.CompilerConstants.staticField; +import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor; +import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL; +import static jdk.nashorn.internal.ir.Symbol.IS_TEMP; +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_FAST_SCOPE; +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_SCOPE; +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT; + +import java.io.PrintWriter; +import java.lang.invoke.MethodHandle; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import jdk.nashorn.internal.codegen.ClassEmitter.Flag; +import jdk.nashorn.internal.codegen.CompilerConstants.Call; +import jdk.nashorn.internal.codegen.RuntimeCallSite.SpecializedRuntimeNode; +import jdk.nashorn.internal.codegen.types.ArrayType; +import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.ir.AccessNode; +import jdk.nashorn.internal.ir.BaseNode; +import jdk.nashorn.internal.ir.BinaryNode; +import jdk.nashorn.internal.ir.Block; +import jdk.nashorn.internal.ir.BreakNode; +import jdk.nashorn.internal.ir.CallNode; +import jdk.nashorn.internal.ir.CaseNode; +import jdk.nashorn.internal.ir.CatchNode; +import jdk.nashorn.internal.ir.ContinueNode; +import jdk.nashorn.internal.ir.DoWhileNode; +import jdk.nashorn.internal.ir.EmptyNode; +import jdk.nashorn.internal.ir.ExecuteNode; +import jdk.nashorn.internal.ir.ForNode; +import jdk.nashorn.internal.ir.FunctionNode; +import jdk.nashorn.internal.ir.IdentNode; +import jdk.nashorn.internal.ir.IfNode; +import jdk.nashorn.internal.ir.IndexNode; +import jdk.nashorn.internal.ir.LineNumberNode; +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.ObjectNode; +import jdk.nashorn.internal.ir.PropertyNode; +import jdk.nashorn.internal.ir.ReferenceNode; +import jdk.nashorn.internal.ir.ReturnNode; +import jdk.nashorn.internal.ir.RuntimeNode; +import jdk.nashorn.internal.ir.RuntimeNode.Request; +import jdk.nashorn.internal.ir.SplitNode; +import jdk.nashorn.internal.ir.SwitchNode; +import jdk.nashorn.internal.ir.Symbol; +import jdk.nashorn.internal.ir.TernaryNode; +import jdk.nashorn.internal.ir.ThrowNode; +import jdk.nashorn.internal.ir.TryNode; +import jdk.nashorn.internal.ir.UnaryNode; +import jdk.nashorn.internal.ir.VarNode; +import jdk.nashorn.internal.ir.WhileNode; +import jdk.nashorn.internal.ir.WithNode; +import jdk.nashorn.internal.ir.debug.ASTWriter; +import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; +import jdk.nashorn.internal.ir.visitor.NodeVisitor; +import jdk.nashorn.internal.parser.Lexer.RegexToken; +import jdk.nashorn.internal.parser.TokenType; +import jdk.nashorn.internal.runtime.CodeInstaller; +import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.ECMAException; +import jdk.nashorn.internal.runtime.Property; +import jdk.nashorn.internal.runtime.PropertyMap; +import jdk.nashorn.internal.runtime.Scope; +import jdk.nashorn.internal.runtime.ScriptFunction; +import jdk.nashorn.internal.runtime.ScriptFunctionData; +import jdk.nashorn.internal.runtime.ScriptObject; +import jdk.nashorn.internal.runtime.ScriptRuntime; +import jdk.nashorn.internal.runtime.Source; +import jdk.nashorn.internal.runtime.Undefined; +import jdk.nashorn.internal.runtime.linker.LinkerCallSite; + +/** + * This is the lowest tier of the code generator. It takes lowered ASTs emitted + * from Lower and emits Java byte code. The byte code emission logic is broken + * out into MethodEmitter. MethodEmitter works internally with a type stack, and + * keeps track of the contents of the byte code stack. This way we avoid a large + * number of special cases on the form + *

+ * if (type == INT) {
+ *     visitInsn(ILOAD, slot);
+ * } else if (type == DOUBLE) {
+ *     visitInsn(DOUBLE, slot);
+ * }
+ * 
+ * This quickly became apparent when the code generator was generalized to work + * with all types, and not just numbers or objects. + *

+ * The CodeGenerator visits nodes only once, tags them as resolved and emits + * bytecode for them. + */ +final class CodeGenerator extends NodeOperatorVisitor { + + /** Name of the Global object, cannot be referred to as .class, @see CodeGenerator */ + private static final String GLOBAL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "Global"; + + /** Name of the ScriptFunctionImpl, cannot be referred to as .class @see FunctionObjectCreator */ + private static final String SCRIPTFUNCTION_IMPL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "ScriptFunctionImpl"; + + private static final String SCRIPTFUNCTION_TRAMPOLINE_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "ScriptFunctionTrampolineImpl"; + + /** Constant data & installation. The only reason the compiler keeps this is because it is assigned + * by reflection in class installation */ + private final Compiler compiler; + + /** Call site flags given to the code generator to be used for all generated call sites */ + private final int callSiteFlags; + + /** How many regexp fields have been emitted */ + private int regexFieldCount; + + /** Map of shared scope call sites */ + private final Map scopeCalls = new HashMap<>(); + + /** When should we stop caching regexp expressions in fields to limit bytecode size? */ + private static final int MAX_REGEX_FIELDS = 2 * 1024; + + /** + * Constructor. + * + * @param compiler + */ + CodeGenerator(final Compiler compiler) { + this.compiler = compiler; + this.callSiteFlags = compiler.getEnv()._callsite_flags; + } + + /** + * Gets the call site flags, adding the strict flag if the current function + * being generated is in strict mode + * + * @return the correct flags for a call site in the current function + */ + int getCallSiteFlags() { + return getCurrentFunctionNode().isStrictMode() ? callSiteFlags | CALLSITE_STRICT : callSiteFlags; + } + + /** + * Load an identity node + * + * @param identNode an identity node to load + * @return the method generator used + */ + private MethodEmitter loadIdent(final IdentNode identNode) { + final Symbol symbol = identNode.getSymbol(); + + if (!symbol.isScope()) { + assert symbol.hasSlot() || symbol.isParam(); + return method.load(symbol); + } + + final String name = symbol.getName(); + + if (CompilerConstants.__FILE__.name().equals(name)) { + return method.load(identNode.getSource().getName()); + } else if (CompilerConstants.__DIR__.name().equals(name)) { + return method.load(identNode.getSource().getBase()); + } else if (CompilerConstants.__LINE__.name().equals(name)) { + return method.load(identNode.getSource().getLine(identNode.position())).convert(Type.OBJECT); + } else { + assert identNode.getSymbol().isScope() : identNode + " is not in scope!"; + + final int flags = CALLSITE_SCOPE | getCallSiteFlags(); + method.loadScope(); + + if (symbol.isFastScope(getCurrentFunctionNode())) { + // Only generate shared scope getter for fast-scope symbols so we know we can dial in correct scope. + if (symbol.getUseCount() > SharedScopeCall.FAST_SCOPE_GET_THRESHOLD) { + return loadSharedScopeVar(identNode.getType(), symbol, flags); + } + return loadFastScopeVar(identNode.getType(), symbol, flags, identNode.isFunction()); + } + return method.dynamicGet(identNode.getType(), identNode.getName(), flags, identNode.isFunction()); + } + } + + private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) { + method.load(symbol.isFastScope(getCurrentFunctionNode()) ? getScopeProtoDepth(getCurrentBlock(), symbol) : -1); + final SharedScopeCall scopeCall = getScopeGet(valueType, symbol, flags | CALLSITE_FAST_SCOPE); + scopeCall.generateInvoke(method); + return method; + } + + private MethodEmitter loadFastScopeVar(final Type valueType, final Symbol symbol, final int flags, final boolean isMethod) { + loadFastScopeProto(symbol, false); + method.dynamicGet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE, isMethod); + return method; + } + + private MethodEmitter storeFastScopeVar(final Type valueType, final Symbol symbol, final int flags) { + loadFastScopeProto(symbol, true); + method.dynamicSet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE); + return method; + } + + private static int getScopeProtoDepth(final Block currentBlock, final Symbol symbol) { + if (currentBlock == symbol.getBlock()) { + return 0; + } + + final int delta = currentBlock.needsScope() ? 1 : 0; + final Block parentBlock = currentBlock.getParent(); + + if (parentBlock != null) { + final int result = getScopeProtoDepth(parentBlock, symbol); + if (result != -1) { + return delta + result; + } + } + + if (currentBlock instanceof FunctionNode) { + for (final Block lookupBlock : ((FunctionNode)currentBlock).getReferencingParentBlocks()) { + final int result = getScopeProtoDepth(lookupBlock, symbol); + if (result != -1) { + return delta + result; + } + } + } + + return -1; + } + + private void loadFastScopeProto(final Symbol symbol, final boolean swap) { + final int depth = getScopeProtoDepth(getCurrentBlock(), symbol); + assert depth != -1; + if(depth > 0) { + if (swap) { + method.swap(); + } + for (int i = 0; i < depth; i++) { + method.invoke(ScriptObject.GET_PROTO); + } + if (swap) { + method.swap(); + } + } + } + + /** + * Generate code that loads this node to the stack. This method is only + * public to be accessible from the maps sub package. Do not call externally + * + * @param node node to load + * + * @return the method emitter used + */ + MethodEmitter load(final Node node) { + return load(node, false); + } + + private MethodEmitter load(final Node node, final boolean baseAlreadyOnStack) { + final Symbol symbol = node.getSymbol(); + + // If we lack symbols, we just generate what we see. + if (symbol == null) { + node.accept(this); + return method; + } + + /* + * The load may be of type IdentNode, e.g. "x", AccessNode, e.g. "x.y" + * or IndexNode e.g. "x[y]". Both AccessNodes and IndexNodes are + * BaseNodes and the logic for loading the base object is reused + */ + final CodeGenerator codegen = this; + + node.accept(new NodeVisitor(getCurrentCompileUnit(), method) { + @Override + public Node enter(final IdentNode identNode) { + loadIdent(identNode); + return null; + } + + @Override + public Node enter(final AccessNode accessNode) { + if (!baseAlreadyOnStack) { + load(accessNode.getBase()).convert(Type.OBJECT); + } + assert method.peekType().isObject(); + method.dynamicGet(node.getType(), accessNode.getProperty().getName(), getCallSiteFlags(), accessNode.isFunction()); + return null; + } + + @Override + public Node enter(final IndexNode indexNode) { + if (!baseAlreadyOnStack) { + load(indexNode.getBase()).convert(Type.OBJECT); + load(indexNode.getIndex()); + } + method.dynamicGetIndex(node.getType(), getCallSiteFlags(), indexNode.isFunction()); + return null; + } + + @Override + public Node enterDefault(final Node otherNode) { + otherNode.accept(codegen); // generate code for whatever we are looking at. + method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there) + return null; + } + }); + + return method; + } + + @Override + public Node enter(final AccessNode accessNode) { + if (accessNode.testResolved()) { + return null; + } + + load(accessNode); + + return null; + } + + /** + * Initialize a specific set of vars to undefined. This has to be done at + * the start of each method for local variables that aren't passed as + * parameters. + * + * @param symbols list of symbols. + */ + private void initSymbols(final Iterable symbols) { + final LinkedList numbers = new LinkedList<>(); + final LinkedList objects = new LinkedList<>(); + + for (final Symbol symbol : symbols) { + /* + * The following symbols are guaranteed to be defined and thus safe + * from having undefined written to them: parameters internals this + * + * Otherwise we must, unless we perform control/escape analysis, + * assign them undefined. + */ + final boolean isInternal = symbol.isParam() || symbol.isInternal() || symbol.isThis() || !symbol.canBeUndefined(); + + if (symbol.hasSlot() && !isInternal) { + assert symbol.getSymbolType().isNumber() || symbol.getSymbolType().isObject() : "no potentially undefined narrower local vars than doubles are allowed: " + symbol + " in " + getCurrentFunctionNode(); + if (symbol.getSymbolType().isNumber()) { + numbers.add(symbol); + } else if (symbol.getSymbolType().isObject()) { + objects.add(symbol); + } + } + } + + initSymbols(numbers, Type.NUMBER); + initSymbols(objects, Type.OBJECT); + } + + private void initSymbols(final LinkedList symbols, final Type type) { + if (symbols.isEmpty()) { + return; + } + + method.loadUndefined(type); + while (!symbols.isEmpty()) { + final Symbol symbol = symbols.removeFirst(); + if (!symbols.isEmpty()) { + method.dup(); + } + method.store(symbol); + } + } + + /** + * Create symbol debug information. + * + * @param block block containing symbols. + */ + private void symbolInfo(final Block block) { + for (final Symbol symbol : block.getFrame().getSymbols()) { + method.localVariable(symbol, block.getEntryLabel(), block.getBreakLabel()); + } + } + + @Override + public Node enter(final Block block) { + if (block.testResolved()) { + return null; + } + + method.label(block.getEntryLabel()); + initLocals(block); + + return block; + } + + @Override + public Node leave(final Block block) { + method.label(block.getBreakLabel()); + symbolInfo(block); + + if (block.needsScope()) { + popBlockScope(block); + } + + return block; + } + + private void popBlockScope(final Block block) { + final Label exitLabel = new Label("block_exit"); + final Label recoveryLabel = new Label("block_catch"); + final Label skipLabel = new Label("skip_catch"); + + /* pop scope a la try-finally */ + method.loadScope(); + method.invoke(ScriptObject.GET_PROTO); + method.storeScope(); + method._goto(skipLabel); + method.label(exitLabel); + + method._catch(recoveryLabel); + method.loadScope(); + method.invoke(ScriptObject.GET_PROTO); + method.storeScope(); + method.athrow(); + method.label(skipLabel); + method._try(block.getEntryLabel(), exitLabel, recoveryLabel, Throwable.class); + } + + @Override + public Node enter(final BreakNode breakNode) { + if (breakNode.testResolved()) { + return null; + } + + for (int i = 0; i < breakNode.getScopeNestingLevel(); i++) { + closeWith(); + } + + method.splitAwareGoto(breakNode.getTargetLabel()); + + return null; + } + + private int loadArgs(final List args) { + return loadArgs(args, null, false, args.size()); + } + + private int loadArgs(final List args, final String signature, final boolean isVarArg, final int argCount) { + // arg have already been converted to objects here. + if (isVarArg || argCount > LinkerCallSite.ARGLIMIT) { + loadArgsArray(args); + return 1; + } + + // pad with undefined if size is too short. argCount is the real number of args + int n = 0; + final Type[] params = signature == null ? null : Type.getMethodArguments(signature); + for (final Node arg : args) { + assert arg != null; + load(arg); + if (n >= argCount) { + method.pop(); // we had to load the arg for its side effects + } else if (params != null) { + method.convert(params[n]); + } + n++; + } + + while (n < argCount) { + method.loadUndefined(Type.OBJECT); + n++; + } + + return argCount; + } + + @Override + public Node enter(final CallNode callNode) { + if (callNode.testResolved()) { + return null; + } + + final List args = callNode.getArgs(); + final Node function = callNode.getFunction(); + final FunctionNode currentFunction = getCurrentFunctionNode(); + final Block currentBlock = getCurrentBlock(); + + function.accept(new NodeVisitor(getCurrentCompileUnit(), method) { + + private void sharedScopeCall(final IdentNode identNode, final int flags) { + final Symbol symbol = identNode.getSymbol(); + int scopeCallFlags = flags; + method.loadScope(); + if (symbol.isFastScope(currentFunction)) { + method.load(getScopeProtoDepth(currentBlock, symbol)); + scopeCallFlags |= CALLSITE_FAST_SCOPE; + } else { + method.load(-1); // Bypass fast-scope code in shared callsite + } + loadArgs(args); + final Type[] paramTypes = method.getTypesFromStack(args.size()); + final SharedScopeCall scopeCall = getScopeCall(symbol, identNode.getType(), callNode.getType(), paramTypes, scopeCallFlags); + scopeCall.generateInvoke(method); + } + + private void scopeCall(final IdentNode node, final int flags) { + load(node); + method.convert(Type.OBJECT); // foo() makes no sense if foo == 3 + // ScriptFunction will see CALLSITE_SCOPE and will bind scope accordingly. + method.loadNull(); //the 'this' + method.dynamicCall(callNode.getType(), 2 + loadArgs(args), flags); + } + + private void evalCall(final IdentNode node, final int flags) { + load(node); + method.convert(Type.OBJECT); // foo() makes no sense if foo == 3 + + final Label not_eval = new Label("not_eval"); + final Label eval_done = new Label("eval_done"); + + // check if this is the real built-in eval + method.dup(); + globalIsEval(); + + method.ifeq(not_eval); + // We don't need ScriptFunction object for 'eval' + method.pop(); + + method.loadScope(); // Load up self (scope). + + final CallNode.EvalArgs evalArgs = callNode.getEvalArgs(); + // load evaluated code + load(evalArgs.getCode()); + method.convert(Type.OBJECT); + // special/extra 'eval' arguments + load(evalArgs.getThis()); + method.load(evalArgs.getLocation()); + method.load(evalArgs.getStrictMode()); + method.convert(Type.OBJECT); + + // direct call to Global.directEval + globalDirectEval(); + method.convert(callNode.getType()); + method._goto(eval_done); + + method.label(not_eval); + // This is some scope 'eval' or global eval replaced by user + // but not the built-in ECMAScript 'eval' function call + method.loadNull(); + method.dynamicCall(callNode.getType(), 2 + loadArgs(args), flags); + + method.label(eval_done); + } + + @Override + public Node enter(final IdentNode node) { + final Symbol symbol = node.getSymbol(); + + if (symbol.isScope()) { + final int flags = getCallSiteFlags() | CALLSITE_SCOPE; + final int useCount = symbol.getUseCount(); + + // Threshold for generating shared scope callsite is lower for fast scope symbols because we know + // we can dial in the correct scope. However, we als need to enable it for non-fast scopes to + // support huge scripts like mandreel.js. + if (callNode.isEval()) { + evalCall(node, flags); + } else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD + || (!symbol.isFastScope(currentFunction) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD) + || callNode.inWithBlock()) { + scopeCall(node, flags); + } else { + sharedScopeCall(node, flags); + } + assert method.peekType().equals(callNode.getType()); + } else { + enterDefault(node); + } + + return null; + } + + @Override + public Node enter(final AccessNode node) { + load(node.getBase()); + method.convert(Type.OBJECT); + method.dup(); + method.dynamicGet(node.getType(), node.getProperty().getName(), getCallSiteFlags(), true); + method.swap(); + method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags()); + assert method.peekType().equals(callNode.getType()); + + return null; + } + + @Override + public Node enter(final ReferenceNode node) { + final FunctionNode callee = node.getReference(); + final boolean isVarArg = callee.isVarArg(); + final int argCount = isVarArg ? -1 : callee.getParameters().size(); + + final String signature = new FunctionSignature(true, callee.needsCallee(), callee.getReturnType(), isVarArg ? null : callee.getParameters()).toString(); + + if (callee.needsCallee()) { + newFunctionObject(callee); + } + + if (callee.isStrictMode()) { // self is undefined + method.loadUndefined(Type.OBJECT); + } else { // get global from scope (which is the self) + globalInstance(); + } + loadArgs(args, signature, isVarArg, argCount); + method.invokestatic(callee.getCompileUnit().getUnitClassName(), callee.getName(), signature); + assert method.peekType().equals(callee.getReturnType()) : method.peekType() + " != " + callee.getReturnType(); + + return null; + } + + @Override + public Node enter(final IndexNode node) { + load(node.getBase()); + method.convert(Type.OBJECT); + method.dup(); + load(node.getIndex()); + final Type indexType = node.getIndex().getType(); + if (indexType.isObject() || indexType.isBoolean()) { + method.convert(Type.OBJECT); //TODO + } + method.dynamicGetIndex(node.getType(), getCallSiteFlags(), true); + method.swap(); + method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags()); + assert method.peekType().equals(callNode.getType()); + + return null; + } + + @Override + protected Node enterDefault(final Node node) { + // Load up function. + load(function); + method.convert(Type.OBJECT); //TODO, e.g. booleans can be used as functions + method.loadNull(); // ScriptFunction will figure out the correct this when it sees CALLSITE_SCOPE + method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags() | CALLSITE_SCOPE); + assert method.peekType().equals(callNode.getType()); + + return null; + } + }); + + method.store(callNode.getSymbol()); + + return null; + } + + @Override + public Node enter(final ContinueNode continueNode) { + if (continueNode.testResolved()) { + return null; + } + + for (int i = 0; i < continueNode.getScopeNestingLevel(); i++) { + closeWith(); + } + + method.splitAwareGoto(continueNode.getTargetLabel()); + + return null; + } + + @Override + public Node enter(final DoWhileNode doWhileNode) { + return enter((WhileNode)doWhileNode); + } + + @Override + public Node enter(final EmptyNode emptyNode) { + return null; + } + + @Override + public Node enter(final ExecuteNode executeNode) { + if (executeNode.testResolved()) { + return null; + } + + final Node expression = executeNode.getExpression(); + expression.accept(this); + + return null; + } + + @Override + public Node enter(final ForNode forNode) { + if (forNode.testResolved()) { + return null; + } + + final Node test = forNode.getTest(); + final Block body = forNode.getBody(); + final Node modify = forNode.getModify(); + + final Label breakLabel = forNode.getBreakLabel(); + final Label continueLabel = forNode.getContinueLabel(); + final Label loopLabel = new Label("loop"); + + Node init = forNode.getInit(); + + if (forNode.isForIn()) { + final Symbol iter = forNode.getIterator(); + + // We have to evaluate the optional initializer expression + // of the iterator variable of the for-in statement. + if (init instanceof VarNode) { + init.accept(this); + init = ((VarNode)init).getName(); + } + + load(modify); + assert modify.getType().isObject(); + method.invoke(forNode.isForEach() ? ScriptRuntime.TO_VALUE_ITERATOR : ScriptRuntime.TO_PROPERTY_ITERATOR); + method.store(iter); + method._goto(continueLabel); + method.label(loopLabel); + + new Store(init) { + @Override + protected void evaluate() { + method.load(iter); + method.invoke(interfaceCallNoLookup(Iterator.class, "next", Object.class)); + } + }.store(); + + body.accept(this); + + method.label(continueLabel); + method.load(iter); + method.invoke(interfaceCallNoLookup(Iterator.class, "hasNext", boolean.class)); + method.ifne(loopLabel); + method.label(breakLabel); + } else { + if (init != null) { + init.accept(this); + } + + final Label testLabel = new Label("test"); + + method._goto(testLabel); + method.label(loopLabel); + body.accept(this); + method.label(continueLabel); + + if (!body.isTerminal() && modify != null) { + load(modify); + } + + method.label(testLabel); + if (test != null) { + new BranchOptimizer(this, method).execute(test, loopLabel, true); + } else { + method._goto(loopLabel); + } + + method.label(breakLabel); + } + + return null; + } + + /** + * Initialize the slots in a frame to undefined. + * + * @param block block with local vars. + */ + private void initLocals(final Block block) { + final FunctionNode function = block.getFunction(); + final boolean isFunctionNode = block == function; + + /* + * Get the symbols from the frame and realign the frame so that all + * slots get correct numbers. The slot numbering is not fixed until + * after initLocals has been run + */ + final Frame frame = block.getFrame(); + final List symbols = frame.getSymbols(); + + /* Fix the predefined slots so they have numbers >= 0, like varargs. */ + frame.realign(); + + if (isFunctionNode) { + if (function.needsParentScope()) { + initParentScope(); + } + if (function.needsArguments()) { + initArguments(function); + } + } + + /* + * Determine if block needs scope, if not, just do initSymbols for this block. + */ + if (block.needsScope()) { + /* + * Determine if function is varargs and consequently variables have to + * be in the scope. + */ + final boolean varsInScope = function.allVarsInScope(); + + // TODO for LET we can do better: if *block* does not contain any eval/with, we don't need its vars in scope. + + final List nameList = new ArrayList<>(); + final List locals = new ArrayList<>(); + + + // Initalize symbols and values + final List newSymbols = new ArrayList<>(); + final List values = new ArrayList<>(); + + final boolean hasArguments = function.needsArguments(); + for (final Symbol symbol : symbols) { + if (symbol.isInternal() || symbol.isThis()) { + continue; + } + + if (symbol.isVar()) { + if(varsInScope || symbol.isScope()) { + nameList.add(symbol.getName()); + newSymbols.add(symbol); + values.add(null); + assert symbol.isScope() : "scope for " + symbol + " should have been set in Lower already " + function.getName(); + assert !symbol.hasSlot() : "slot for " + symbol + " should have been removed in Lower already" + function.getName(); + } else { + assert symbol.hasSlot() : symbol + " should have a slot only, no scope"; + locals.add(symbol); + } + } else if (symbol.isParam() && (varsInScope || hasArguments || symbol.isScope())) { + nameList.add(symbol.getName()); + newSymbols.add(symbol); + values.add(hasArguments ? null : symbol); + assert symbol.isScope() : "scope for " + symbol + " should have been set in Lower already " + function.getName() + " varsInScope="+varsInScope+" hasArguments="+hasArguments+" symbol.isScope()=" + symbol.isScope(); + assert !(hasArguments && symbol.hasSlot()) : "slot for " + symbol + " should have been removed in Lower already " + function.getName(); + } + } + + /* Correct slot numbering again */ + frame.realign(); + + // we may have locals that need to be initialized + initSymbols(locals); + + /* + * Create a new object based on the symbols and values, generate + * bootstrap code for object + */ + final FieldObjectCreator foc = new FieldObjectCreator(this, nameList, newSymbols, values, true, hasArguments) { + @Override + protected Type getValueType(final Symbol value) { + return value.getSymbolType(); + } + + @Override + protected void loadValue(final Symbol value) { + method.load(value); + } + + @Override + protected void loadScope(MethodEmitter m) { + if(function.needsParentScope()) { + m.loadScope(); + } else { + m.loadNull(); + } + } + }; + foc.makeObject(method); + + // runScript(): merge scope into global + if (isFunctionNode && function.isScript()) { + method.invoke(ScriptRuntime.MERGE_SCOPE); + } + + method.storeScope(); + } else { + // Since we don't have a scope, parameters didn't get assigned array indices by the FieldObjectCreator, so + // we need to assign them separately here. + int nextParam = 0; + if (isFunctionNode && function.isVarArg()) { + for (final IdentNode param : function.getParameters()) { + param.getSymbol().setFieldIndex(nextParam++); + } + } + initSymbols(symbols); + } + + // Debugging: print symbols? @see --print-symbols flag + printSymbols(block, (isFunctionNode ? "Function " : "Block in ") + (function.getIdent() == null ? "" : function.getIdent().getName())); + } + + private void initArguments(final FunctionNode function) { + method.loadVarArgs(); + if(function.needsCallee()) { + method.loadCallee(); + } else { + // If function is strict mode, "arguments.callee" is not populated, so we don't necessarily need the + // caller. + assert function.isStrictMode(); + method.loadNull(); + } + method.load(function.getParameters().size()); + globalAllocateArguments(); + method.storeArguments(); + } + + private void initParentScope() { + method.loadCallee(); + method.invoke(ScriptFunction.GET_SCOPE); + method.storeScope(); + } + + @Override + public Node enter(final FunctionNode functionNode) { + if (functionNode.isLazy()) { + return null; + } + + if (functionNode.testResolved()) { + return null; + } + + setCurrentCompileUnit(functionNode.getCompileUnit()); + assert getCurrentCompileUnit() != null; + + method = getCurrentCompileUnit().getClassEmitter().method(functionNode); + functionNode.setMethodEmitter(method); + // Mark end for variable tables. + method.begin(); + method.label(functionNode.getEntryLabel()); + + initLocals(functionNode); + + return functionNode; + } + + @Override + public Node leave(final FunctionNode functionNode) { + // Mark end for variable tables. + method.label(functionNode.getBreakLabel()); + + if (!functionNode.needsScope()) { + method.markerVariable(LEAF.tag(), functionNode.getEntryLabel(), functionNode.getBreakLabel()); + } + + symbolInfo(functionNode); + try { + method.end(); // wrap up this method + } catch (final Throwable t) { + Context.printStackTrace(t); + final VerifyError e = new VerifyError("Code generation bug in \"" + functionNode.getName() + "\": likely stack misaligned: " + t + " " + functionNode.getSource().getName()); + e.initCause(t); + throw e; + } + + return functionNode; + } + + @Override + public Node enter(final IdentNode identNode) { + return null; + } + + @Override + public Node enter(final IfNode ifNode) { + if (ifNode.testResolved()) { + return null; + } + + final Node test = ifNode.getTest(); + final Block pass = ifNode.getPass(); + final Block fail = ifNode.getFail(); + + final Label failLabel = new Label("if_fail"); + final Label afterLabel = fail == null ? failLabel : new Label("if_done"); + + new BranchOptimizer(this, method).execute(test, failLabel, false); + + boolean passTerminal = false; + boolean failTerminal = false; + + pass.accept(this); + if (!pass.hasTerminalFlags()) { + method._goto(afterLabel); //don't fallthru to fail block + } else { + passTerminal = pass.isTerminal(); + } + + if (fail != null) { + method.label(failLabel); + fail.accept(this); + failTerminal = fail.isTerminal(); + } + + //if if terminates, put the after label there + if (!passTerminal || !failTerminal) { + method.label(afterLabel); + } + + return null; + } + + @Override + public Node enter(final IndexNode indexNode) { + if (indexNode.testResolved()) { + return null; + } + + load(indexNode); + + return null; + } + + @Override + public Node enter(final LineNumberNode lineNumberNode) { + if (lineNumberNode.testResolved()) { + return null; + } + + final Label label = new Label("line:" + lineNumberNode.getLineNumber() + " (" + getCurrentFunctionNode().getName() + ")"); + method.label(label); + method.lineNumber(lineNumberNode.getLineNumber(), label); + + return null; + } + + /** + * Load a list of nodes as an array of a specific type + * The array will contain the visited nodes. + * + * @param arrayLiteralNode the array of contents + * @param arrayType the type of the array, e.g. ARRAY_NUMBER or ARRAY_OBJECT + * + * @return the method generator that was used + */ + private MethodEmitter loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) { + assert arrayType == Type.INT_ARRAY || arrayType == Type.NUMBER_ARRAY || arrayType == Type.OBJECT_ARRAY; + + final Node[] nodes = arrayLiteralNode.getValue(); + final Object presets = arrayLiteralNode.getPresets(); + final int[] postsets = arrayLiteralNode.getPostsets(); + final Class type = arrayType.getTypeClass(); + final List units = arrayLiteralNode.getUnits(); + + loadConstant(presets); + + final Type elementType = arrayType.getElementType(); + + if (units != null) { + final CompileUnit savedCompileUnit = getCurrentCompileUnit(); + final MethodEmitter savedMethod = getCurrentMethodEmitter(); + + try { + for (final ArrayUnit unit : units) { + setCurrentCompileUnit(unit.getCompileUnit()); + + final String className = getCurrentCompileUnit().getUnitClassName(); + final String name = getCurrentFunctionNode().uniqueName(SPLIT_PREFIX.tag()); + final String signature = methodDescriptor(type, Object.class, ScriptFunction.class, ScriptObject.class, type); + + method = getCurrentCompileUnit().getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature); + method.setFunctionNode(getCurrentFunctionNode()); + method.begin(); + + fixScopeSlot(); + + method.load(arrayType, SPLIT_ARRAY_ARG.slot()); + + for (int i = unit.getLo(); i < unit.getHi(); i++) { + storeElement(nodes, elementType, postsets[i]); + } + + method._return(); + method.end(); + + savedMethod.loadThis(); + savedMethod.swap(); + savedMethod.loadCallee(); + savedMethod.swap(); + savedMethod.loadScope(); + savedMethod.swap(); + savedMethod.invokestatic(className, name, signature); + } + } finally { + setCurrentCompileUnit(savedCompileUnit); + setCurrentMethodEmitter(savedMethod); + } + + return method; + } + + for (final int postset : postsets) { + storeElement(nodes, elementType, postset); + } + + return method; + } + + private void storeElement(final Node[] nodes, final Type elementType, final int index) { + method.dup(); + method.load(index); + + final Node element = nodes[index]; + + if (element == null) { + method.loadEmpty(elementType); + } else { + assert elementType.isEquivalentTo(element.getType()) : "array element type doesn't match array type"; + load(element); + } + + method.arraystore(); + } + + private MethodEmitter loadArgsArray(final List args) { + final Object[] array = new Object[args.size()]; + loadConstant(array); + + for (int i = 0; i < args.size(); i++) { + method.dup(); + method.load(i); + load(args.get(i)).convert(Type.OBJECT); //has to be upcast to object or we fail + method.arraystore(); + } + + return method; + } + + /** + * Load a constant from the constant array. This is only public to be callable from the objects + * subpackage. Do not call directly. + * + * @param string string to load + */ + void loadConstant(final String string) { + final String unitClassName = getCurrentCompileUnit().getUnitClassName(); + final ClassEmitter classEmitter = getCurrentCompileUnit().getClassEmitter(); + final int index = compiler.getConstantData().add(string); + + method.load(index); + method.invokestatic(unitClassName, GET_STRING.tag(), methodDescriptor(String.class, int.class)); + classEmitter.needGetConstantMethod(String.class); + } + + /** + * Load a constant from the constant array. This is only public to be callable from the objects + * subpackage. Do not call directly. + * + * @param object object to load + */ + void loadConstant(final Object object) { + final String unitClassName = getCurrentCompileUnit().getUnitClassName(); + final ClassEmitter classEmitter = getCurrentCompileUnit().getClassEmitter(); + final int index = compiler.getConstantData().add(object); + final Class cls = object.getClass(); + + if (cls == PropertyMap.class) { + method.load(index); + method.invokestatic(unitClassName, GET_MAP.tag(), methodDescriptor(PropertyMap.class, int.class)); + classEmitter.needGetConstantMethod(PropertyMap.class); + } else if (cls.isArray()) { + method.load(index); + final String methodName = ClassEmitter.getArrayMethodName(cls); + method.invokestatic(unitClassName, methodName, methodDescriptor(cls, int.class)); + classEmitter.needGetConstantMethod(cls); + } else { + method.loadConstants(unitClassName).load(index).arrayload(); + if (cls != Object.class) { + method.checkcast(cls); + } + } + } + + // literal values + private MethodEmitter load(final LiteralNode node) { + final Object value = node.getValue(); + + if (value == null) { + method.loadNull(); + } else if (value instanceof Undefined) { + method.loadUndefined(Type.OBJECT); + } else if (value instanceof String) { + final String string = (String)value; + + if (string.length() > (MethodEmitter.LARGE_STRING_THRESHOLD / 3)) { // 3 == max bytes per encoded char + loadConstant(string); + } else { + method.load(string); + } + } else if (value instanceof RegexToken) { + loadRegex((RegexToken)value); + } else if (value instanceof Boolean) { + method.load((Boolean)value); + } else if (value instanceof Integer) { + method.load((Integer)value); + } else if (value instanceof Long) { + method.load((Long)value); + } else if (value instanceof Double) { + method.load((Double)value); + } else if (node instanceof ArrayLiteralNode) { + final ArrayType type = (ArrayType)node.getType(); + loadArray((ArrayLiteralNode)node, type); + globalAllocateArray(type); + } else { + assert false : "Unknown literal for " + node.getClass() + " " + value.getClass() + " " + value; + } + + return method; + } + + private MethodEmitter loadRegexToken(final RegexToken value) { + method.load(value.getExpression()); + method.load(value.getOptions()); + return globalNewRegExp(); + } + + private MethodEmitter loadRegex(final RegexToken regexToken) { + if (regexFieldCount > MAX_REGEX_FIELDS) { + return loadRegexToken(regexToken); + } + // emit field + final String regexName = getCurrentFunctionNode().uniqueName(REGEX_PREFIX.tag()); + final ClassEmitter classEmitter = getCurrentCompileUnit().getClassEmitter(); + + classEmitter.field(EnumSet.of(PRIVATE, STATIC), regexName, Object.class); + regexFieldCount++; + + // get field, if null create new regex, finally clone regex object + method.getStatic(getCurrentCompileUnit().getUnitClassName(), regexName, typeDescriptor(Object.class)); + method.dup(); + final Label cachedLabel = new Label("cached"); + method.ifnonnull(cachedLabel); + + method.pop(); + loadRegexToken(regexToken); + method.dup(); + method.putStatic(getCurrentCompileUnit().getUnitClassName(), regexName, typeDescriptor(Object.class)); + + method.label(cachedLabel); + globalRegExpCopy(); + + return method; + } + + @SuppressWarnings("rawtypes") + @Override + public Node enter(final LiteralNode literalNode) { + assert literalNode.getSymbol() != null : literalNode + " has no symbol"; + load(literalNode).store(literalNode.getSymbol()); + return null; + } + + @Override + public Node enter(final ObjectNode objectNode) { + if (objectNode.testResolved()) { + return null; + } + + final List elements = objectNode.getElements(); + final int size = elements.size(); + + final List keys = new ArrayList<>(); + final List symbols = new ArrayList<>(); + final List values = new ArrayList<>(); + + boolean hasGettersSetters = false; + + for (int i = 0; i < size; i++) { + final PropertyNode propertyNode = (PropertyNode)elements.get(i); + final Node value = propertyNode.getValue(); + final String key = propertyNode.getKeyName(); + final Symbol symbol = value == null ? null : propertyNode.getSymbol(); + + if (value == null) { + hasGettersSetters = true; + } + + keys.add(key); + symbols.add(symbol); + values.add(value); + } + + new FieldObjectCreator(this, keys, symbols, values) { + @Override + protected Type getValueType(final Node node) { + return node.getType(); + } + + @Override + protected void loadValue(final Node node) { + load(node); + } + + /** + * Ensure that the properties start out as object types so that + * we can do putfield initializations instead of dynamicSetIndex + * which would be the case to determine initial property type + * otherwise. + * + * Use case, it's very expensive to do a million var x = {a:obj, b:obj} + * just to have to invalidate them immediately on initialization + * + * see NASHORN-594 + */ + @Override + protected MapCreator newMapCreator(final Class fieldObjectClass) { + return new MapCreator(fieldObjectClass, keys, symbols) { + @Override + protected int getPropertyFlags(final Symbol symbol, final boolean isVarArg) { + return super.getPropertyFlags(symbol, isVarArg) | Property.IS_ALWAYS_OBJECT; + } + }; + } + + }.makeObject(method); + + method.dup(); + globalObjectPrototype(); + method.invoke(ScriptObject.SET_PROTO); + + if (!hasGettersSetters) { + method.store(objectNode.getSymbol()); + return null; + } + + for (final Node element : elements) { + final PropertyNode propertyNode = (PropertyNode)element; + final Object key = propertyNode.getKey(); + final ReferenceNode getter = (ReferenceNode)propertyNode.getGetter(); + final ReferenceNode setter = (ReferenceNode)propertyNode.getSetter(); + + if (getter == null && setter == null) { + continue; + } + + method.dup().loadKey(key); + + if (getter == null) { + method.loadNull(); + } else { + getter.accept(this); + } + + if (setter == null) { + method.loadNull(); + } else { + setter.accept(this); + } + + method.invoke(ScriptObject.SET_USER_ACCESSORS); + } + + method.store(objectNode.getSymbol()); + + return null; + } + + @Override + public Node enter(final ReferenceNode referenceNode) { + if (referenceNode.testResolved()) { + return null; + } + + newFunctionObject(referenceNode.getReference()); + + return null; + } + + @Override + public Node enter(final ReturnNode returnNode) { + if (returnNode.testResolved()) { + return null; + } + + // Set the split return flag in the scope if this is a split method fragment. + if (method.getSplitNode() != null) { + assert method.getSplitNode().hasReturn() : "unexpected return in split node"; + + method.loadScope(); + method.checkcast(Scope.class); + method.load(0); + method.invoke(Scope.SET_SPLIT_STATE); + } + + final Node expression = returnNode.getExpression(); + if (expression != null) { + load(expression); + } else { + method.loadUndefined(getCurrentFunctionNode().getReturnType()); + } + + method._return(getCurrentFunctionNode().getReturnType()); + + return null; + } + + private static boolean isNullLiteral(final Node node) { + return node instanceof LiteralNode && ((LiteralNode) node).isNull(); + } + + private boolean nullCheck(final RuntimeNode runtimeNode, final List args, final String signature) { + final Request request = runtimeNode.getRequest(); + + if (!Request.isEQ(request) && !Request.isNE(request)) { + return false; + } + + assert args.size() == 2 : "EQ or NE or TYPEOF need two args"; + + Node lhs = args.get(0); + Node rhs = args.get(1); + + if (isNullLiteral(lhs)) { + final Node tmp = lhs; + lhs = rhs; + rhs = tmp; + } + + if (isNullLiteral(rhs)) { + final Label trueLabel = new Label("trueLabel"); + final Label falseLabel = new Label("falseLabel"); + final Label endLabel = new Label("end"); + + load(lhs); + method.dup(); + if (Request.isEQ(request)) { + method.ifnull(trueLabel); + } else if (Request.isNE(request)) { + method.ifnonnull(trueLabel); + } else { + assert false : "Invalid request " + request; + } + + method.label(falseLabel); + load(rhs); + method.invokestatic(CompilerConstants.className(ScriptRuntime.class), request.toString(), signature); + method._goto(endLabel); + + method.label(trueLabel); + // if NE (not strict) this can be "undefined != null" which is supposed to be false + if (request == Request.NE) { + method.loadUndefined(Type.OBJECT); + final Label isUndefined = new Label("isUndefined"); + final Label afterUndefinedCheck = new Label("afterUndefinedCheck"); + method.if_acmpeq(isUndefined); + // not undefined + method.load(true); + method._goto(afterUndefinedCheck); + method.label(isUndefined); + method.load(false); + method.label(afterUndefinedCheck); + } else { + method.pop(); + method.load(true); + } + method.label(endLabel); + method.convert(runtimeNode.getType()); + method.store(runtimeNode.getSymbol()); + + return true; + } + + return false; + } + + private boolean specializationCheck(final RuntimeNode.Request request, final Node node, final List args) { + if (!request.canSpecialize()) { + return false; + } + + assert args.size() == 2; + final Node lhs = args.get(0); + final Node rhs = args.get(1); + + final Type returnType = node.getType(); + load(lhs); + load(rhs); + + Request finalRequest = request; + + final Request reverse = Request.reverse(request); + if (method.peekType().isObject() && reverse != null) { + if (!method.peekType(1).isObject()) { + method.swap(); + finalRequest = reverse; + } + } + + method.dynamicRuntimeCall( + new SpecializedRuntimeNode( + finalRequest, + new Type[] { + method.peekType(1), + method.peekType() + }, + returnType).getInitialName(), + returnType, + finalRequest); + + method.convert(node.getType()); + method.store(node.getSymbol()); + + return true; + } + + private static boolean isReducible(final Request request) { + return Request.isComparison(request) || request == Request.ADD; + } + + @Override + public Node enter(final RuntimeNode runtimeNode) { + if (runtimeNode.testResolved()) { + return null; + } + + /* + * First check if this should be something other than a runtime node + * AccessSpecializer might have changed the type + * + * TODO - remove this - Access Specializer will always know after Attr/Lower + */ + if (runtimeNode.isPrimitive() && !runtimeNode.isFinal() && isReducible(runtimeNode.getRequest())) { + final Node lhs = runtimeNode.getArgs().get(0); + assert runtimeNode.getArgs().size() > 1 : runtimeNode + " must have two args"; + final Node rhs = runtimeNode.getArgs().get(1); + + final Type type = runtimeNode.getType(); + final Symbol symbol = runtimeNode.getSymbol(); + + switch (runtimeNode.getRequest()) { + case EQ: + case EQ_STRICT: + return enterCmp(lhs, rhs, Condition.EQ, type, symbol); + case NE: + case NE_STRICT: + return enterCmp(lhs, rhs, Condition.NE, type, symbol); + case LE: + return enterCmp(lhs, rhs, Condition.LE, type, symbol); + case LT: + return enterCmp(lhs, rhs, Condition.LT, type, symbol); + case GE: + return enterCmp(lhs, rhs, Condition.GE, type, symbol); + case GT: + return enterCmp(lhs, rhs, Condition.GT, type, symbol); + case ADD: + Type widest = Type.widest(lhs.getType(), rhs.getType()); + load(lhs); + method.convert(widest); + load(rhs); + method.convert(widest); + method.add(); + method.convert(type); + method.store(symbol); + return null; + default: + // it's ok to send this one on with only primitive arguments, maybe INSTANCEOF(true, true) or similar + // assert false : runtimeNode + " has all primitive arguments. This is an inconsistent state"; + break; + } + } + + // Get the request arguments. + final List args = runtimeNode.getArgs(); + + if (nullCheck(runtimeNode, args, new FunctionSignature(false, false, runtimeNode.getType(), args).toString())) { + return null; + } + + if (!runtimeNode.isFinal() && specializationCheck(runtimeNode.getRequest(), runtimeNode, args)) { + return null; + } + + for (final Node arg : runtimeNode.getArgs()) { + load(arg).convert(Type.OBJECT); //TODO this should not be necessary below Lower + } + + method.invokestatic( + CompilerConstants.className(ScriptRuntime.class), + runtimeNode.getRequest().toString(), + new FunctionSignature( + false, + false, + runtimeNode.getType(), + runtimeNode.getArgs().size()).toString()); + method.convert(runtimeNode.getType()); + method.store(runtimeNode.getSymbol()); + + return null; + } + + @Override + public Node enter(final SplitNode splitNode) { + if (splitNode.testResolved()) { + return null; + } + + final CompileUnit splitCompileUnit = splitNode.getCompileUnit(); + + final FunctionNode fn = getCurrentFunctionNode(); + final String className = splitCompileUnit.getUnitClassName(); + final String name = splitNode.getName(); + + final Class rtype = fn.getReturnType().getTypeClass(); + final boolean needsArguments = fn.needsArguments(); + final Class[] ptypes = needsArguments ? + new Class[] {ScriptFunction.class, Object.class, ScriptObject.class, Object.class} : + new Class[] {ScriptFunction.class, Object.class, ScriptObject.class}; + + setCurrentCompileUnit(splitCompileUnit); + splitNode.setCompileUnit(splitCompileUnit); + + final Call splitCall = staticCallNoLookup( + className, + name, + methodDescriptor(rtype, ptypes)); + + setCurrentMethodEmitter( + splitCompileUnit.getClassEmitter().method( + EnumSet.of(Flag.PUBLIC, Flag.STATIC), + name, + rtype, + ptypes)); + + method.setFunctionNode(fn); + method.setSplitNode(splitNode); + splitNode.setMethodEmitter(method); + + final MethodEmitter caller = splitNode.getCaller(); + if(fn.needsCallee()) { + caller.loadCallee(); + } else { + caller.loadNull(); + } + caller.loadThis(); + caller.loadScope(); + if (needsArguments) { + caller.loadArguments(); + } + caller.invoke(splitCall); + caller.storeResult(); + + method.begin(); + + method.loadUndefined(fn.getReturnType()); + method.storeResult(); + + fixScopeSlot(); + + return splitNode; + } + + private void fixScopeSlot() { + if (getCurrentFunctionNode().getScopeNode().getSymbol().getSlot() != SCOPE.slot()) { + // TODO hack to move the scope to the expected slot (that's needed because split methods reuse the same slots as the root method) + method.load(Type.typeFor(ScriptObject.class), SCOPE.slot()); + method.storeScope(); + } + } + + @Override + public Node leave(final SplitNode splitNode) { + try { + // Wrap up this method. + method.loadResult(); + method._return(getCurrentFunctionNode().getReturnType()); + method.end(); + } catch (final Throwable t) { + Context.printStackTrace(t); + final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + getCurrentFunctionNode().getSource().getName()); + e.initCause(t); + throw e; + } + + // Handle return from split method if there was one. + final MethodEmitter caller = splitNode.getCaller(); + final List

nametypedefaultdescription
${opt.name} ${opt.shortName == null? "" : opt.shortName}${opt.type}${defValue}${opt.description}