diff --git a/.hgtags b/.hgtags index fde585f8bbb..bf173376ee4 100644 --- a/.hgtags +++ b/.hgtags @@ -182,3 +182,4 @@ ffe6bce5a521be40146af2ac03c509b7bac30595 jdk8-b56 479d3302a26d7607ba271d66973e59ebf58825b6 jdk8-b58 3bd874584fc01aae92fbc8827e2bd04d8b6ace04 jdk8-b59 5e3adc681779037a2d33b7be6f75680619085492 jdk8-b60 +cdaa6122185f9bf512dcd6600f56bfccc4824e8c jdk8-b61 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index dba7899a1e6..7e43143f19e 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -182,3 +182,4 @@ b85b44cced2406792cfb9baab1377ff03e7001d8 jdk8-b55 9367024804874faf8e958adeb333682bab1c0c47 jdk8-b58 dae9821589ccd2611bdf7084269b98e819091770 jdk8-b59 e07f499b9dccb529ecf74172cf6ac11a195ec57a jdk8-b60 +20ff117b509075c3aec4ee3a57990ecd5db5df9c jdk8-b61 diff --git a/README-builds.html b/README-builds.html index 57ded784f9a..446588f7a36 100644 --- a/README-builds.html +++ b/README-builds.html @@ -96,7 +96,8 @@
  • Windows only:
  • @@ -161,7 +162,7 @@
    This file often describes specific requirements for what we call the "minimum build environments" (MBE) for this - specific release of the JDK, + specific release of the JDK, Building with the MBE will generate the most compatible bits that install on, and run correctly on, the most variations of the same base OS and hardware architecture. @@ -241,16 +242,16 @@

    - These same sources do indeed build on many more systems than the - above older generation systems, again the above is just a minimum. + These same sources do indeed build on many more systems than the + above older generation systems, again the above is just a minimum.

    - Compilation problems with newer or different C/C++ compilers is a - common problem. - Similarly, compilation problems related to changes to the + Compilation problems with newer or different C/C++ compilers is a + common problem. + Similarly, compilation problems related to changes to the /usr/include or system header files is also a - common problem with newer or unreleased OS versions. - Please report these types of problems as bugs so that they - can be dealt with accordingly. + common problem with newer or unreleased OS versions. + Please report these types of problems as bugs so that they + can be dealt with accordingly.


    @@ -266,15 +267,15 @@

    After installing Fedora 9 - you need to install several build dependencies. The simplest - way to do it is to execute the following commands as user + you need to install several build dependencies. The simplest + way to do it is to execute the following commands as user root:

    yum-builddep java-1.6.0-openjdk

    yum install gcc gcc-c++

    - In addition, it's necessary to set a few environment variables for the build: + In addition, it's necessary to set a few environment variables for the build:

    export LANG=C ALT_BOOTDIR=/usr/lib/jvm/java-openjdk @@ -283,15 +284,15 @@

    After installing Fedora 10 - you need to install several build dependencies. The simplest - way to do it is to execute the following commands as user + you need to install several build dependencies. The simplest + way to do it is to execute the following commands as user root:

    yum-builddep java-1.6.0-openjdk

    yum install gcc gcc-c++

    - In addition, it's necessary to set a few environment variables for the build: + In addition, it's necessary to set a few environment variables for the build:

    export LANG=C ALT_BOOTDIR=/usr/lib/jvm/java-openjdk @@ -300,15 +301,15 @@

    After installing Fedora 11 - you need to install several build dependencies. The simplest - way to do it is to execute the following commands as user + you need to install several build dependencies. The simplest + way to do it is to execute the following commands as user root:

    yum-builddep java-1.6.0-openjdk

    yum install gcc gcc-c++

    - In addition, it's necessary to set a few environment variables for the build: + In addition, it's necessary to set a few environment variables for the build:

    export LANG=C ALT_BOOTDIR=/usr/lib/jvm/java-openjdk @@ -360,16 +361,16 @@

    Debian 5.0 (Lenny)

    - After installing Debian 5 - you need to install several build dependencies. - The simplest way to install the build dependencies is to - execute the following commands as user root: + After installing Debian 5 + you need to install several build dependencies. + The simplest way to install the build dependencies is to + execute the following commands as user root:

    aptitude build-dep openjdk-6

    aptitude install openjdk-6-jdk libmotif-dev

    - In addition, it's necessary to set a few environment variables for the build: + In addition, it's necessary to set a few environment variables for the build:

    export LANG=C ALT_BOOTDIR=/usr/lib/jvm/java-6-openjdk

    @@ -380,52 +381,52 @@

    Ubuntu 8.04

    - After installing Ubuntu 8.04 - you need to install several build dependencies. + After installing Ubuntu 8.04 + you need to install several build dependencies.

    - First, you need to enable the universe repository in the - Software Sources application and reload the repository - information. The Software Sources application is available - under the System/Administration menu. + First, you need to enable the universe repository in the + Software Sources application and reload the repository + information. The Software Sources application is available + under the System/Administration menu.

    - The simplest way to install the build dependencies is to - execute the following commands: + The simplest way to install the build dependencies is to + execute the following commands:

    sudo aptitude build-dep openjdk-6

    sudo aptitude install openjdk-6-jdk

    - In addition, it's necessary to set a few environment variables for the build: + In addition, it's necessary to set a few environment variables for the build:

    export LANG=C ALT_BOOTDIR=/usr/lib/jvm/java-6-openjdk

    Ubuntu 8.10

    - After installing Ubuntu 8.10 - you need to install several build dependencies. The simplest - way to do it is to execute the following commands: + After installing Ubuntu 8.10 + you need to install several build dependencies. The simplest + way to do it is to execute the following commands:

    sudo aptitude build-dep openjdk-6

    sudo aptitude install openjdk-6-jdk

    - In addition, it's necessary to set a few environment variables for the build: + In addition, it's necessary to set a few environment variables for the build:

    export LANG=C ALT_BOOTDIR=/usr/lib/jvm/java-6-openjdk

    Ubuntu 9.04

    - After installing Ubuntu 9.04 - you need to install several build dependencies. The simplest - way to do it is to execute the following commands: + After installing Ubuntu 9.04 + you need to install several build dependencies. The simplest + way to do it is to execute the following commands:

    sudo aptitude build-dep openjdk-6

    sudo aptitude install openjdk-6-jdk

    - In addition, it's necessary to set a few environment variables for the build: + In addition, it's necessary to set a few environment variables for the build:

    export LANG=C ALT_BOOTDIR=/usr/lib/jvm/java-6-openjdk

    @@ -436,20 +437,20 @@

    OpenSUSE 11.1

    - After installing OpenSUSE 11.1 - you need to install several build dependencies. - The simplest way to install the build dependencies is to - execute the following commands: + After installing OpenSUSE 11.1 + you need to install several build dependencies. + The simplest way to install the build dependencies is to + execute the following commands:

    sudo zypper source-install -d java-1_6_0-openjdk

    sudo zypper install make

    - In addition, it is necessary to set a few environment variables for the build: + In addition, it is necessary to set a few environment variables for the build:

    export LANG=C ALT_BOOTDIR=/usr/lib/jvm/java-1.6.0-openjdk

    - Finally, you need to unset the JAVA_HOME environment variable: + Finally, you need to unset the JAVA_HOME environment variable:

    export -n JAVA_HOME

    @@ -460,14 +461,14 @@

    Mandriva Linux One 2009 Spring

    - After installing Mandriva Linux One 2009 Spring - you need to install several build dependencies. - The simplest way to install the build dependencies is to - execute the following commands as user root: + After installing Mandriva Linux One 2009 Spring + you need to install several build dependencies. + The simplest way to install the build dependencies is to + execute the following commands as user root:

    urpmi java-1.6.0-openjdk-devel ant make gcc gcc-c++ freetype-devel zip unzip libcups2-devel libxrender1-devel libalsa2-devel libstc++-static-devel libxtst6-devel libxi-devel

    - In addition, it is necessary to set a few environment variables for the build: + In addition, it is necessary to set a few environment variables for the build:

    export LANG=C ALT_BOOTDIR=/usr/lib/jvm/java-1.6.0-openjdk

    @@ -478,18 +479,18 @@

    OpenSolaris 2009.06

    - After installing OpenSolaris 2009.06 - you need to install several build dependencies. - The simplest way to install the build dependencies is to - execute the following commands: + After installing OpenSolaris 2009.06 + you need to install several build dependencies. + The simplest way to install the build dependencies is to + execute the following commands:

    pfexec pkg install SUNWgmake SUNWj6dev SUNWant sunstudioexpress SUNWcups SUNWzip SUNWunzip SUNWxwhl SUNWxorg-headers SUNWaudh SUNWfreetype2

    - In addition, it is necessary to set a few environment variables for the build: + In addition, it is necessary to set a few environment variables for the build:

    export LANG=C ALT_COMPILER_PATH=/opt/SunStudioExpress/bin/ ALT_CUPS_HEADERS_PATH=/usr/include/

    - Finally, you need to make sure that the build process can find the Sun Studio compilers: + Finally, you need to make sure that the build process can find the Sun Studio compilers:

    export PATH=$PATH:/opt/SunStudioExpress/bin/

    @@ -687,31 +688,20 @@
  • Windows: - Make sure you start your build inside a bash/sh/ksh shell - and are using a make.exe utility built for that - environment (a cygwin make.exe is not the same - as a make.exe built for something like - MKS). -
    - WARNING: Watch out on some make 3.81 versions, it may - not work due to a lack of support for MS-DOS drive letter paths - like C:/ or C:\. -
    - You may be able to use the information at the - - mozilla developer center - on this topic. -
    - It's hoped that when make 3.82 starts shipping in a future cygwin - release that this MS-DOS path issue will be fixed. -
    - It may be possible to download the version at - - www.cmake.org make.exe. -
    - It might be necessary for you to build your own GNU make 3.81, - see the "Building GNU make" section - in that case. + Make sure you start your build inside a bash/sh/ksh shell and are + using a make.exe utility built for that environment.
    + MKS builds need a native Windows version of GNU make + (see Building GNU make).
    + Cygwin builds need + a make version which was specially compiled for the Cygwin environment + (see Building GNU make). WARNING: + the OpenJDK build with the make utility provided by Cygwin will not + work because it does not support drive letters in paths. Make sure that + your version of make will be found before the Cygwins default make by + setting an appropriate PATH environment variable or by removing + Cygwin's make after you built your own make version.
    + MinGW/MSYS builds can use the default make which + comes with the environment.
  • @@ -727,7 +717,7 @@

    Building GNU make

    - First step is to get the GNU make 3.81 source from + First step is to get the GNU make 3.81 (or newer) source from ftp.gnu.org/pub/gnu/make/. Building is a little different depending on the OS and unix toolset @@ -742,12 +732,24 @@ ./configure && gmake CC=gcc
  • - Windows for CYGWIN: - ./configure && make + Windows for CYGWIN:
    + ./configure
    + Add the line #define HAVE_CYGWIN_SHELL 1 to the end of config.h
    + make
    +
    + This should produce make.exe in the current directory.
  • - Windows for MKS: (CYGWIN is recommended) - ./configure && make -f Makefile.win32 + Windows for MKS:
    + Edit config.h.W32 and uncomment the line #define HAVE_MKS_SHELL 1
    + Set the environment for your native compiler (e.g. by calling:
    + "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /Release /xp /x64) + nmake -f NMakefile.win32 +
    + This should produce WinDebug/make.exe and WinRel/make.exe +
    + If you get the error: NMAKE : fatal error U1045: spawn failed : Permission denied + you have to set the Read & execute permission for the file subproc.bat.
  • @@ -894,39 +896,135 @@

    Windows Paths

    Windows: - Note that GNU make is a historic utility and is based very - heavily on shell scripting, so it does not tolerate the Windows habit + Note that GNU make, the shell and other Unix-tools required during the build + do not tolerate the Windows habit of having spaces in pathnames or the use of the \characters in pathnames. - Luckily on most Windows systems, you can use /instead of \, and - there is always a 'short' pathname without spaces for any path that - contains spaces. - Unfortunately, this short pathname can be somewhat dynamic and the - formula is difficult to explain. - You can use cygpath utility to map pathnames with spaces - or the \character into the C:/ style of pathname - (called 'mixed'), e.g. - cygpath -s -m "path". + Luckily on most Windows systems, you can use /instead of \, and + there is always a short + "8.3" pathname without spaces for any path that contains spaces. + Unfortunately, this short pathname is somewhat dynamic (i.e. dependant on the + other files and directories inside a given directory) and can not be + algorithmicly calculated by only looking at a specific path name.

    The makefiles will try to translate any pathnames supplied to it into the C:/ style automatically. +

    - Note that use of CYGWIN creates a unique problem with regards to + Special care has to be taken if native Windows applications + like nmake or cl are called with file arguments processed + by Unix-tools like make or sh! +

    +
    + +

    Windows build environments

    +
    + Building on Windows requires a Unix-like environment, notably a Unix-like shell. + There are several such environments available of which + MKS, + Cygwin and + MinGW/MSYS are currently supported for + the OpenJDK build. One of the differences of these three systems is the way + they handle Windows path names, particularly path names which contain + spaces, backslashes as path separators and possibly drive letters. Depending + on the use case and the specifics of each environment these path problems can + be solved by a combination of quoting whole paths, translating backslashes to + forward slashes, escaping backslashes with additional backslashes and + translating the path names to their + "8.3" version. +

    + As of this writing (MKS ver. 9.4, Cygwin ver. 1.7.9, MinGW/MSYS 1.0.17), + MKS builds are known to be the fastest Windows builds while MingGW/MSYS + builds are slightly slower (about 10%) than MKS builds and Cygwin builds + require nearly twice the time (about 180%) of MKS builds (e.g. on a + DualCore i7 notebook with 8GB of RAM, HDD and 64-bit Windows 7 operating system + the complete OpenJDK 8 product build takes about 49min with MKS, 54min with + MinGW/MSYS and 88min with Cygwin). +

    +

    + Mixing tools from the different Unix emulation environments is not a good + idea and will probably not work! +

    +

    + MKS: is a commercial product which includes + all the Unix utilities which are required to build the OpenJDK except GNU + make. In pre-OpenJDK times it was the only supported build environment on + Windows. The MKS tools support Windows paths with drive letters and + forward slashes as path separator. Paths in environment variables like (for + example) PATH are separated by semicolon ';'. +

    +

    + Recent versions of MKS provide the dosname utility to convert paths + with spaces to short (8.3) path names,e .g. + dosname -s "path". +

    +

    + If you are using the MKS environment, you need a native Windows version + of Gnu make which you can easily build yourself. +

    +

    + Cygwin: + is an open source, Linux-like environment which tries to emulate + a complete POSIX layer on Windows. It tries to be smart about path names + and can usually handle all kinds of paths if they are correctly quoted + or escaped although internally it maps drive letters <drive>: + to a virtual directory /cygdrive/<drive>. +

    +

    + You can always use the cygpath utility to map pathnames with spaces + or the backslash character into the C:/ style of pathname + (called 'mixed'), e.g. cygpath -s -m "path". +

    +

    + Note that the use of CYGWIN creates a unique problem with regards to setting PATH. Normally on Windows the PATH variable contains directories - separated with the ";" character (Solaris and Linux uses ":"). + separated with the ";" character (Solaris and Linux use ":"). With CYGWIN, it uses ":", but that means that paths like "C:/path" cannot be placed in the CYGWIN version of PATH and instead CYGWIN uses something like /cygdrive/c/path which CYGWIN understands, but only CYGWIN understands. - So be careful with paths on Windows. +

    +

    + If you are using the Cygwin environment, you need to + compile your own version + of GNU make because the default Cygwin make can not handle drive letters in paths. +

    +

    + MinGW/MSYS: + MinGW ("Minimalist GNU for Windows") is a collection of free Windows + specific header files and import libraries combined with GNU toolsets that + allow one to produce native Windows programs that do not rely on any + 3rd-party C runtime DLLs. MSYS is a supplement to MinGW which allows building + applications and programs which rely on traditional UNIX tools to + be present. Among others this includes tools like bash and make. +

    +

    + Like Cygwin, MinGW/MSYS can handle different types of path formats. They + are internally converted to paths with forward slashes and drive letters + <drive>: replaced by a virtual + directory /<drive>. Additionally, MSYS automatically + detects binaries compiled for the MSYS environment and feeds them with the + internal, Unix-style path names. If native Windows applications are called + from within MSYS programs their path arguments are automatically converted + back to Windows style path names with drive letters and backslashes as + path separators. This may cause problems for Windows applications which + use forward slashes as parameter separator (e.g. cl /nologo /I) + because MSYS may wrongly + replace such parameters by drive letters. +

    +

    + If you are using the MinGW/MSYS system you can use the default make + version supplied by the environment. +

    Basic Windows Check List

    1. - Install the - CYGWIN product. + Install one of the + CYGWIN, MinGW/MSYS or + MKS environments.
    2. Install the @@ -1097,9 +1195,9 @@ Sun Studio 12 Update 1 Compilers (containing version 5.10 of the C and C++ compilers) is required, - including specific patches. + including specific patches.

      - The Solaris SPARC patch list is: + The Solaris SPARC patch list is:

      • 118683-05: SunOS 5.10: Patch for profiling libraries and assembler @@ -1286,7 +1384,8 @@ The XRender header file is included with the other X11 header files in the package SFWxwinc on new enough versions of Solaris and will be installed in - /usr/X11/include/X11/extensions/Xrender.h + /usr/X11/include/X11/extensions/Xrender.h or + /usr/openwin/share/include/X11/extensions/Xrender.h

        Linux: XRender header files are required for building the @@ -1456,7 +1555,9 @@ Devel make The GNU version of the 'make' utility built for CYGWIN.
        - NOTE: See the GNU make section + NOTE: the Cygwin make can not be used to build the + OpenJDK. You only need it to build your own version of make + (see the GNU make section) m4.exe @@ -1521,6 +1622,21 @@ So it's important that the Visual Studio paths in PATH preceed the CYGWIN path /usr/bin.

    + Minimalist GNU for Windows (MinGW/MSYS) +
    + Alternatively, the set of unix command tools for the OpenJDK build on + Windows can be supplied by + MinGW/MSYS. +

    + In addition to the tools which will be installed by default, you have + to manually install the msys-zip and msys-unzip packages. + This can be easily done with the MinGW command line installer:
    +
    + mingw-get.exe install msys-zip
    + mingw-get.exe install msys-unzip
    +
    +

    +
    Microsoft DirectX 9.0 SDK header files and libraries
    Microsoft DirectX 9.0 SDK (Summer 2004) @@ -1781,10 +1897,10 @@
    ALT_OPENWIN_HOME
    - The top-level directory of the libraries and include files for the platform's - graphical programming environment. The default location is platform specific. - For example, on Linux it defaults to /usr/X11R6/. -
    + The top-level directory of the libraries and include files for the platform's + graphical programming environment. The default location is platform specific. + For example, on Linux it defaults to /usr/X11R6/. +
    Windows specific:
    @@ -1792,9 +1908,9 @@
    The location of the Microsoft Windows SDK where some tools will be - located. - The default is whatever WINDOWSSDKDIR is set to - (or WindowsSdkDir) or the path + located. + The default is whatever WINDOWSSDKDIR is set to + (or WindowsSdkDir) or the path
    c:\Program Files\Microsoft SDKs\Windows\v7.0a
    @@ -1823,17 +1939,17 @@ is that ALT_COMPILER_PATH is set to point to the cross-compiler and that any cross-compilation specific flags are passed using EXTRA_CFLAGS. - The ALT_OPENWIN_HOME variable should - also be set to point to the graphical header files (e.g. X11) provided with - the cross-compiler. + The ALT_OPENWIN_HOME variable should + also be set to point to the graphical header files (e.g. X11) provided with + the cross-compiler. When cross-compiling we skip execution of any demos etc that may be built, and also skip binary-file verification.
    EXTRA_CFLAGS
    - Used to pass cross-compilation options to the cross-compiler. + Used to pass cross-compilation options to the cross-compiler. These are added to the CFLAGS and CXXFLAGS variables. -
    +
    USE_ONLY_BOOTDIR_TOOLS
    Used primarily for cross-compilation builds (and always set in that case) @@ -1868,23 +1984,23 @@
    BUILD_HEADLESS_ONLY
    Used when the build environment has no graphical capabilities at all. This - excludes building anything that requires graphical libraries to be available. + excludes building anything that requires graphical libraries to be available.
    JAVASE_EMBEDDED
    - Used to indicate this is a build of the Oracle Java SE Embedded product. - This will enable the directives included in the SE-Embedded specific build - files. + Used to indicate this is a build of the Oracle Java SE Embedded product. + This will enable the directives included in the SE-Embedded specific build + files.
    LIBZIP_CAN_USE_MMAP
    - If set to false, disables the use of mmap by the zip utility. Otherwise, - mmap will be used. + If set to false, disables the use of mmap by the zip utility. Otherwise, + mmap will be used.
    COMPRESS_JARS
    - If set to true, causes certain jar files that would otherwise be built without - compression, to use compression. + If set to true, causes certain jar files that would otherwise be built without + compression, to use compression.
    diff --git a/corba/.hgtags b/corba/.hgtags index 8f91b19e721..68fb9749256 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -182,3 +182,4 @@ f3ab4163ae012965fc8acdfc25ce0fece8d6906d jdk8-b57 18462a19f7bd66d38015f61ea549a5e0c0c889a3 jdk8-b58 d54dc53e223ed9ce7d5f4d2cd02ad9d5def3c2db jdk8-b59 207ef43ba69ead6cbbab415d81834545e4d46747 jdk8-b60 +0e08ba7648fb3faa0986cb217887d7c4990977f3 jdk8-b61 diff --git a/corba/make/common/shared/Defs-utils.gmk b/corba/make/common/shared/Defs-utils.gmk index 40bf4687263..1de3dde0ba5 100644 --- a/corba/make/common/shared/Defs-utils.gmk +++ b/corba/make/common/shared/Defs-utils.gmk @@ -151,16 +151,26 @@ CD = cd # intrinsic unix command ifeq ($(PLATFORM),windows) ifdef USING_CYGWIN # Intrinsic unix command, with backslash-escaped character interpretation - ECHO = $(UNIXCOMMAND_PATH)echo -e - ZIPEXE = $(UNIXCOMMAND_PATH)zip - UNZIP = $(UNIXCOMMAND_PATH)unzip + ECHO = $(UNIXCOMMAND_PATH)echo -e + ZIPEXE = $(UNIXCOMMAND_PATH)zip + UNZIP = $(UNIXCOMMAND_PATH)unzip + # Some CYGWIN nawk versions require BINMODE=w for proper '\r' interpretation + NAWK = $(UNIXCOMMAND_PATH)awk -v BINMODE=w else - ZIPEXE = $(UTILS_DEVTOOL_PATH)zip - UNZIP = $(UTILS_DEVTOOL_PATH)unzip + ifdef USING_MSYS + ECHO = $(UTILS_COMMAND_PATH)echo -e + ZIPEXE = $(UTILS_DEVTOOL_PATH)zip + UNZIP = $(UTILS_DEVTOOL_PATH)unzip + NAWK = $(UNIXCOMMAND_PATH)awk + else + ZIPEXE = $(UTILS_DEVTOOL_PATH)zip + UNZIP = $(UTILS_DEVTOOL_PATH)unzip + NAWK = $(UNIXCOMMAND_PATH)awk + endif endif # Re-define some utilities LEX =# override GNU Make intrinsic: no lex on windows - NAWK = $(UNIXCOMMAND_PATH)awk + SHA1SUM = $(UNIXCOMMAND_PATH)openssl sha1 endif # Linux specific diff --git a/corba/make/common/shared/Defs-windows.gmk b/corba/make/common/shared/Defs-windows.gmk index 1521d9461c3..812e6038dda 100644 --- a/corba/make/common/shared/Defs-windows.gmk +++ b/corba/make/common/shared/Defs-windows.gmk @@ -91,6 +91,15 @@ define OptFullPath $(shell if [ "$1" != "" -a -d "$1" ]; then $(CYGPATH_CMD) "$1"; else echo "$1"; fi) endef else +ifdef USING_MSYS +DOSPATH_CMD:=$(shell cd $(JDK_TOPDIR) 2> $(DEV_NULL) && pwd)/make/tools/msys_build_scripts/dospath.sh +define FullPath +$(subst \,/,$(shell $(DOSPATH_CMD) $1)) +endef +define OptFullPath +$(shell if [ "$1" != "" -a -d "$1" ]; then (cd $1 && pwd); else echo "$1"; fi) +endef +else # Temporary until we upgrade to MKS 8.7, MKS pwd returns mixed mode path define FullPath $(shell cd $1 2> $(DEV_NULL) && pwd) @@ -99,6 +108,7 @@ define OptFullPath $(shell if [ "$1" != "" -a -d "$1" ]; then (cd $1 && pwd); else echo "$1"; fi) endef endif +endif # System drive ifdef SYSTEMDRIVE @@ -112,14 +122,21 @@ _system_drive:=$(call CheckValue,_system_drive,C:) # UNIXCOMMAND_PATH: path to where the most common Unix commands are. # NOTE: Must end with / so that it could be empty, allowing PATH usage. -ifndef UNIXCOMMAND_PATH - ifdef ALT_UNIXCOMMAND_PATH +# With cygwin, use this as is; don't use FullPath on it. +ifdef ALT_UNIXCOMMAND_PATH + ifdef USING_CYGWIN + UNIXCOMMAND_PATH :=$(call PrefixPath,$(ALT_UNIXCOMMAND_PATH)) + else xALT_UNIXCOMMAND_PATH :="$(subst \,/,$(ALT_UNIXCOMMAND_PATH))" fxALT_UNIXCOMMAND_PATH :=$(call FullPath,$(xALT_UNIXCOMMAND_PATH)) UNIXCOMMAND_PATH :=$(call PrefixPath,$(fxALT_UNIXCOMMAND_PATH)) + endif +else + ifdef USING_CYGWIN + UNIXCOMMAND_PATH :=$(call PrefixPath,/usr/bin) else - ifdef USING_CYGWIN - UNIXCOMMAND_PATH :=$(call PrefixPath,/usr/bin) + ifdef USING_MSYS + UNIXCOMMAND_PATH :=$(call PrefixPath,/bin) else ifdef ROOTDIR xROOTDIR :="$(subst \,/,$(ROOTDIR))" @@ -131,41 +148,35 @@ ifndef UNIXCOMMAND_PATH ifneq ($(_rootdir),) UNIXCOMMAND_PATH :=$(call PrefixPath,$(_rootdir)/mksnt) endif - endif - endif - UNIXCOMMAND_PATH:=$(call AltCheckSpaces,UNIXCOMMAND_PATH) - export UNIXCOMMAND_PATH + endif # USING_MSYS + endif # USING_CYGWIN endif +UNIXCOMMAND_PATH:=$(call AltCheckSpaces,UNIXCOMMAND_PATH) +export UNIXCOMMAND_PATH # Get version of MKS or CYGWIN -ifdef USING_CYGWIN - ifndef CYGWIN_VER - _CYGWIN_VER :=$(shell $(UNAME)) - CYGWIN_VER :=$(call GetVersion,$(_CYGWIN_VER)) - export CYGWIN_VER +ifdef USING_MKS + _MKS_VER :=$(shell $(MKSINFO) 2>&1 | $(GREP) Release | $(TAIL) -1 | $(SED) -e 's@.*\(Release.*\)@\1@') + MKS_VER :=$(call GetVersion,$(_MKS_VER)) + # At this point, we can re-define FullPath to use DOSNAME_CMD + CHECK_MKS87:=$(call CheckVersions,$(MKS_VER),8.7) + TRY_DOSNAME:=false + ifeq ($(CHECK_MKS87),same) + TRY_DOSNAME:=true endif -else # MKS -_MKS_VER :=$(shell $(MKSINFO) 2>&1 | $(GREP) Release | $(TAIL) -1 | $(SED) -e 's@.*\(Release.*\)@\1@') -MKS_VER :=$(call GetVersion,$(_MKS_VER)) -# At this point, we can re-define FullPath to use DOSNAME_CMD -CHECK_MKS87:=$(call CheckVersions,$(MKS_VER),8.7) -TRY_DOSNAME:=false -ifeq ($(CHECK_MKS87),same) -TRY_DOSNAME:=true -endif -# Newer should be ok -ifeq ($(CHECK_MKS87),newer) -TRY_DOSNAME:=true -endif -ifeq ($(TRY_DOSNAME),true) -ifeq ($(shell $(UNIXCOMMAND_PATH)dosname -s $(_system_drive)/ 2> $(DEV_NULL)),$(_system_drive)/) -_DOSNAME=$(UNIXCOMMAND_PATH)dosname -DOSNAME_CMD:=$(_DOSNAME) -s + # Newer should be ok + ifeq ($(CHECK_MKS87),newer) + TRY_DOSNAME:=true + endif + ifeq ($(TRY_DOSNAME),true) + ifeq ($(shell $(UNIXCOMMAND_PATH)dosname -s $(_system_drive)/ 2> $(DEV_NULL)),$(_system_drive)/) + _DOSNAME=$(UNIXCOMMAND_PATH)dosname + DOSNAME_CMD:=$(_DOSNAME) -s define FullPath $(subst //,/,$(shell echo $1 | $(DOSNAME_CMD) 2> $(DEV_NULL))) endef -endif # test dosname -s -endif # TRY_DOSNAME + endif # test dosname -s + endif # TRY_DOSNAME endif # MKS # We try to get references to what we need via the default component @@ -240,6 +251,8 @@ endif # DEVTOOLS_PATH: for other tools required for building (such as zip, etc.) # NOTE: Must end with / so that it could be empty, allowing PATH usage. ifndef DEVTOOLS_PATH + # DEVTOOLS_PATH: for other tools required for building (such as zip, etc.) + # NOTE: Must end with / so that it could be empty, allowing PATH usage. ifdef ALT_DEVTOOLS_PATH xALT_DEVTOOLS_PATH :="$(subst \,/,$(ALT_DEVTOOLS_PATH))" fxALT_DEVTOOLS_PATH :=$(call FullPath,$(xALT_DEVTOOLS_PATH)) @@ -248,10 +261,14 @@ ifndef DEVTOOLS_PATH ifdef USING_CYGWIN DEVTOOLS_PATH :=$(UNIXCOMMAND_PATH) else - xDEVTOOLS_PATH :="$(_system_drive)/utils" - fxDEVTOOLS_PATH :=$(call FullPath,$(xDEVTOOLS_PATH)) - DEVTOOLS_PATH :=$(call PrefixPath,$(fxDEVTOOLS_PATH)) - endif + ifdef USING_MSYS + DEVTOOLS_PATH :=$(UNIXCOMMAND_PATH) + else + xDEVTOOLS_PATH :="$(_system_drive)/utils" + fxDEVTOOLS_PATH :=$(call FullPath,$(xDEVTOOLS_PATH)) + DEVTOOLS_PATH :=$(call PrefixPath,$(fxDEVTOOLS_PATH)) + endif # USING_MSYS + endif # USING_CYGWIN endif DEVTOOLS_PATH:=$(call AltCheckSpaces,DEVTOOLS_PATH) export DEVTOOLS_PATH diff --git a/corba/make/common/shared/Platform.gmk b/corba/make/common/shared/Platform.gmk index 822c1e787b8..0b3edf4fa8b 100644 --- a/corba/make/common/shared/Platform.gmk +++ b/corba/make/common/shared/Platform.gmk @@ -65,6 +65,8 @@ PLATFORM_SHARED=done # REQUIRED_WINDOWS_NAME windows only: basic name of windows # REQUIRED_WINDOWS_VERSION windows only: specific version of windows # USING_CYGWIN windows only: true or false +# USING_MSYS windows only: true or false +# USING_MKS windows only: true or false # WINDOWS_NT_VERSION_STRING windows only: long version name # REQUIRED_OS_VERSION required OS version, e.g. 5.10, 2.4 # REQUIRED_FREE_SPACE minimum disk space needed for outputdir @@ -327,6 +329,8 @@ endif # Windows with and without CYGWIN will be slightly different ifeq ($(SYSTEM_UNAME), Windows_NT) PLATFORM = windows + USING_MKS = true + export USING_MKS OS_VERSION := $(shell uname -r) WINDOWS_NT_VERSION_STRING=Windows_NT REQUIRED_MKS_VER=6.1 @@ -339,6 +343,11 @@ ifneq (,$(findstring CYGWIN,$(SYSTEM_UNAME))) WINDOWS_NT_VERSION_STRING=CYGWIN_NT REQUIRED_CYGWIN_VER=4.0 endif +ifneq (,$(findstring MINGW,$(SYSTEM_UNAME))) + PLATFORM = windows + USING_MSYS = true + export USING_MSYS +endif # Platform settings specific to Windows ifeq ($(PLATFORM), windows) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 4f1b3692f38..0da4f9dddd5 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -285,3 +285,5 @@ f2e12eb74117c917c0bb264694c02de4a6a15a10 hs25-b03 1cc7a2a11d00832e3d07f81f3744a6883422db7e hs25-b04 3cfd05b2219a29649741a52637696f06acf24a4e jdk8-b60 b261523fe66c40a02968f0aa7e73602491bb3386 hs25-b05 +4547dc71db765276e027b0c2780b724bae0a07d3 jdk8-b61 +d0337c31c8be7716369b4e7c3bd5f352983c6a06 hs25-b06 diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index ef0a7519680..14577a1280c 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2012 HS_MAJOR_VER=25 HS_MINOR_VER=0 -HS_BUILD_NUMBER=05 +HS_BUILD_NUMBER=06 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index 9de2da9fc8b..ae394e36e75 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -67,7 +67,7 @@ #define JAVA_CLASSFILE_MAGIC 0xCAFEBABE #define JAVA_MIN_SUPPORTED_VERSION 45 -#define JAVA_MAX_SUPPORTED_VERSION 51 +#define JAVA_MAX_SUPPORTED_VERSION 52 #define JAVA_MAX_SUPPORTED_MINOR_VERSION 0 // Used for two backward compatibility reasons: diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index 7e8c39cdd3b..d74a6174a99 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -413,8 +413,7 @@ char* java_lang_String::as_utf8_string(oop java_string, int start, int len) { } bool java_lang_String::equals(oop java_string, jchar* chars, int len) { - assert(SharedSkipVerify || - java_string->klass() == SystemDictionary::String_klass(), + assert(java_string->klass() == SystemDictionary::String_klass(), "must be java_string"); typeArrayOop value = java_lang_String::value(java_string); int offset = java_lang_String::offset(java_string); diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index 3fa7267ba0f..f0e61daf2ac 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -1699,6 +1699,9 @@ void SystemDictionary::always_strong_oops_do(OopClosure* blk) { blk->do_oop(&_system_loader_lock_obj); dictionary()->always_strong_oops_do(blk); + + // Visit extra methods + invoke_method_table()->oops_do(blk); } void SystemDictionary::always_strong_classes_do(KlassClosure* closure) { diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index bc103b492d7..ac8b70017e0 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -2395,7 +2395,7 @@ void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) { if (VerifyBeforeGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { - Universe::verify(true); + Universe::verify(); } // Snapshot the soft reference policy to be used in this collection cycle. @@ -2419,7 +2419,7 @@ void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) { if (VerifyDuringGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { gclog_or_tty->print("Verify before initial mark: "); - Universe::verify(true); + Universe::verify(); } { bool res = markFromRoots(false); @@ -2431,7 +2431,7 @@ void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) { if (VerifyDuringGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { gclog_or_tty->print("Verify before re-mark: "); - Universe::verify(true); + Universe::verify(); } checkpointRootsFinal(false, clear_all_soft_refs, init_mark_was_synchronous); @@ -2443,7 +2443,7 @@ void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) { if (VerifyDuringGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { gclog_or_tty->print("Verify before sweep: "); - Universe::verify(true); + Universe::verify(); } sweep(false); assert(_collectorState == Resizing, "Incorrect state"); @@ -2459,7 +2459,7 @@ void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) { if (VerifyDuringGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { gclog_or_tty->print("Verify before reset: "); - Universe::verify(true); + Universe::verify(); } reset(false); assert(_collectorState == Idling, "Collector state should " @@ -2486,7 +2486,7 @@ void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) { if (VerifyAfterGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { - Universe::verify(true); + Universe::verify(); } if (TraceCMSState) { gclog_or_tty->print_cr("CMS Thread " INTPTR_FORMAT @@ -5668,7 +5668,7 @@ void CMSCollector::do_remark_non_parallel() { if (VerifyDuringGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification - Universe::verify(true); + Universe::verify(); } { TraceTime t("root rescan", PrintGCDetails, false, gclog_or_tty); diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp index eb8f9504f26..eacd2a9f6e0 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp @@ -64,7 +64,7 @@ void VM_CMS_Operation::verify_before_gc() { FreelistLocker x(_collector); MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); Universe::heap()->prepare_for_verify(); - Universe::verify(true); + Universe::verify(); } } @@ -74,7 +74,7 @@ void VM_CMS_Operation::verify_after_gc() { HandleMark hm; FreelistLocker x(_collector); MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); - Universe::verify(true); + Universe::verify(); } } diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index a06b01cae37..d3dc1eb7bb7 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -426,11 +426,11 @@ ConcurrentMark::ConcurrentMark(ReservedSpace rs, uint max_regions) : _markStack(this), // _finger set in set_non_marking_state - _max_task_num(MAX2((uint)ParallelGCThreads, 1U)), + _max_worker_id(MAX2((uint)ParallelGCThreads, 1U)), // _active_tasks set in set_non_marking_state // _tasks set inside the constructor - _task_queues(new CMTaskQueueSet((int) _max_task_num)), - _terminator(ParallelTaskTerminator((int) _max_task_num, _task_queues)), + _task_queues(new CMTaskQueueSet((int) _max_worker_id)), + _terminator(ParallelTaskTerminator((int) _max_worker_id, _task_queues)), _has_overflown(false), _concurrent(false), @@ -481,17 +481,17 @@ ConcurrentMark::ConcurrentMark(ReservedSpace rs, uint max_regions) : _root_regions.init(_g1h, this); - _tasks = NEW_C_HEAP_ARRAY(CMTask*, _max_task_num, mtGC); - _accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_task_num, mtGC); + _tasks = NEW_C_HEAP_ARRAY(CMTask*, _max_worker_id, mtGC); + _accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_worker_id, mtGC); - _count_card_bitmaps = NEW_C_HEAP_ARRAY(BitMap, _max_task_num, mtGC); - _count_marked_bytes = NEW_C_HEAP_ARRAY(size_t*, _max_task_num, mtGC); + _count_card_bitmaps = NEW_C_HEAP_ARRAY(BitMap, _max_worker_id, mtGC); + _count_marked_bytes = NEW_C_HEAP_ARRAY(size_t*, _max_worker_id, mtGC); BitMap::idx_t card_bm_size = _card_bm.size(); // so that the assertion in MarkingTaskQueue::task_queue doesn't fail - _active_tasks = _max_task_num; - for (int i = 0; i < (int) _max_task_num; ++i) { + _active_tasks = _max_worker_id; + for (uint i = 0; i < _max_worker_id; ++i) { CMTaskQueue* task_queue = new CMTaskQueue(); task_queue->initialize(); _task_queues->register_queue(i, task_queue); @@ -638,7 +638,7 @@ void ConcurrentMark::reset() { // We do reset all of them, since different phases will use // different number of active threads. So, it's easiest to have all // of them ready. - for (int i = 0; i < (int) _max_task_num; ++i) { + for (uint i = 0; i < _max_worker_id; ++i) { _tasks[i]->reset(_nextMarkBitMap); } @@ -648,7 +648,7 @@ void ConcurrentMark::reset() { } void ConcurrentMark::set_phase(uint active_tasks, bool concurrent) { - assert(active_tasks <= _max_task_num, "we should not have more"); + assert(active_tasks <= _max_worker_id, "we should not have more"); _active_tasks = active_tasks; // Need to update the three data structures below according to the @@ -659,7 +659,7 @@ void ConcurrentMark::set_phase(uint active_tasks, bool concurrent) { _concurrent = concurrent; // We propagate this to all tasks, not just the active ones. - for (int i = 0; i < (int) _max_task_num; ++i) + for (uint i = 0; i < _max_worker_id; ++i) _tasks[i]->set_concurrent(concurrent); if (concurrent) { @@ -818,9 +818,9 @@ void ConcurrentMark::checkpointRootsInitialPost() { * doesn't manipulate any data structures afterwards. */ -void ConcurrentMark::enter_first_sync_barrier(int task_num) { +void ConcurrentMark::enter_first_sync_barrier(uint worker_id) { if (verbose_low()) { - gclog_or_tty->print_cr("[%d] entering first barrier", task_num); + gclog_or_tty->print_cr("[%u] entering first barrier", worker_id); } if (concurrent()) { @@ -834,11 +834,11 @@ void ConcurrentMark::enter_first_sync_barrier(int task_num) { // more work if (verbose_low()) { - gclog_or_tty->print_cr("[%d] leaving first barrier", task_num); + gclog_or_tty->print_cr("[%u] leaving first barrier", worker_id); } - // let task 0 do this - if (task_num == 0) { + // 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 @@ -858,9 +858,9 @@ void ConcurrentMark::enter_first_sync_barrier(int task_num) { // then go into the second barrier } -void ConcurrentMark::enter_second_sync_barrier(int task_num) { +void ConcurrentMark::enter_second_sync_barrier(uint worker_id) { if (verbose_low()) { - gclog_or_tty->print_cr("[%d] entering second barrier", task_num); + gclog_or_tty->print_cr("[%u] entering second barrier", worker_id); } if (concurrent()) { @@ -873,7 +873,7 @@ void ConcurrentMark::enter_second_sync_barrier(int task_num) { // at this point everything should be re-initialised and ready to go if (verbose_low()) { - gclog_or_tty->print_cr("[%d] leaving second barrier", task_num); + gclog_or_tty->print_cr("[%u] leaving second barrier", worker_id); } } @@ -1120,8 +1120,8 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { HandleMark hm; // handle scope gclog_or_tty->print(" VerifyDuringGC:(before)"); Universe::heap()->prepare_for_verify(); - Universe::verify(/* silent */ false, - /* option */ VerifyOption_G1UsePrevMarking); + Universe::verify(/* silent */ false, + /* option */ VerifyOption_G1UsePrevMarking); } G1CollectorPolicy* g1p = g1h->g1_policy(); @@ -1159,8 +1159,8 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { HandleMark hm; // handle scope gclog_or_tty->print(" VerifyDuringGC:(after)"); Universe::heap()->prepare_for_verify(); - Universe::verify(/* silent */ false, - /* option */ VerifyOption_G1UseNextMarking); + Universe::verify(/* silent */ false, + /* option */ VerifyOption_G1UseNextMarking); } assert(!restart_for_overflow(), "sanity"); } @@ -1811,8 +1811,8 @@ void ConcurrentMark::cleanup() { HandleMark hm; // handle scope gclog_or_tty->print(" VerifyDuringGC:(before)"); Universe::heap()->prepare_for_verify(); - Universe::verify(/* silent */ false, - /* option */ VerifyOption_G1UsePrevMarking); + Universe::verify(/* silent */ false, + /* option */ VerifyOption_G1UsePrevMarking); } G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy(); @@ -1966,8 +1966,8 @@ void ConcurrentMark::cleanup() { HandleMark hm; // handle scope gclog_or_tty->print(" VerifyDuringGC:(after)"); Universe::heap()->prepare_for_verify(); - Universe::verify(/* silent */ false, - /* option */ VerifyOption_G1UsePrevMarking); + Universe::verify(/* silent */ false, + /* option */ VerifyOption_G1UsePrevMarking); } g1h->verify_region_sets_optional(); @@ -2113,9 +2113,9 @@ class G1CMParKeepAliveAndDrainClosure: public OopClosure { if (!_cm->has_overflown()) { oop obj = oopDesc::load_decode_heap_oop(p); if (_cm->verbose_high()) { - gclog_or_tty->print_cr("\t[%d] we're looking at location " + gclog_or_tty->print_cr("\t[%u] we're looking at location " "*"PTR_FORMAT" = "PTR_FORMAT, - _task->task_id(), p, (void*) obj); + _task->worker_id(), p, (void*) obj); } _task->deal_with_reference(obj); @@ -2144,7 +2144,7 @@ class G1CMParKeepAliveAndDrainClosure: public OopClosure { } } else { if (_cm->verbose_high()) { - gclog_or_tty->print_cr("\t[%d] CM Overflow", _task->task_id()); + gclog_or_tty->print_cr("\t[%u] CM Overflow", _task->worker_id()); } } } @@ -2160,8 +2160,8 @@ class G1CMParDrainMarkingStackClosure: public VoidClosure { void do_void() { do { if (_cm->verbose_high()) { - gclog_or_tty->print_cr("\t[%d] Drain: Calling do marking_step", - _task->task_id()); + gclog_or_tty->print_cr("\t[%u] Drain: Calling do marking_step", + _task->worker_id()); } // We call CMTask::do_marking_step() to completely drain the local and @@ -2300,7 +2300,7 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { // We use the work gang from the G1CollectedHeap and we utilize all // the worker threads. uint active_workers = g1h->workers() ? g1h->workers()->active_workers() : 1U; - active_workers = MAX2(MIN2(active_workers, _max_task_num), 1U); + active_workers = MAX2(MIN2(active_workers, _max_worker_id), 1U); G1CMRefProcTaskExecutor par_task_executor(g1h, this, g1h->workers(), active_workers); @@ -2619,7 +2619,7 @@ void ConcurrentMark::clearRangeBothBitmaps(MemRegion mr) { } HeapRegion* -ConcurrentMark::claim_region(int task_num) { +ConcurrentMark::claim_region(uint worker_id) { // "checkpoint" the finger HeapWord* finger = _finger; @@ -2657,10 +2657,10 @@ ConcurrentMark::claim_region(int task_num) { HeapWord* limit = curr_region->next_top_at_mark_start(); if (verbose_low()) { - gclog_or_tty->print_cr("[%d] curr_region = "PTR_FORMAT" " + gclog_or_tty->print_cr("[%u] curr_region = "PTR_FORMAT" " "["PTR_FORMAT", "PTR_FORMAT"), " "limit = "PTR_FORMAT, - task_num, curr_region, bottom, end, limit); + worker_id, curr_region, bottom, end, limit); } // Is the gap between reading the finger and doing the CAS too long? @@ -2673,22 +2673,22 @@ ConcurrentMark::claim_region(int task_num) { assert(_finger >= end, "the finger should have moved forward"); if (verbose_low()) { - gclog_or_tty->print_cr("[%d] we were successful with region = " - PTR_FORMAT, task_num, curr_region); + gclog_or_tty->print_cr("[%u] we were successful with region = " + PTR_FORMAT, worker_id, curr_region); } if (limit > bottom) { if (verbose_low()) { - gclog_or_tty->print_cr("[%d] region "PTR_FORMAT" is not empty, " - "returning it ", task_num, curr_region); + gclog_or_tty->print_cr("[%u] region "PTR_FORMAT" is not empty, " + "returning it ", worker_id, curr_region); } return curr_region; } else { assert(limit == bottom, "the region limit should be at bottom"); if (verbose_low()) { - gclog_or_tty->print_cr("[%d] region "PTR_FORMAT" is empty, " - "returning NULL", task_num, curr_region); + gclog_or_tty->print_cr("[%u] region "PTR_FORMAT" is empty, " + "returning NULL", worker_id, curr_region); } // we return NULL and the caller should try calling // claim_region() again. @@ -2697,10 +2697,10 @@ ConcurrentMark::claim_region(int task_num) { } else { assert(_finger > finger, "the finger should have moved forward"); if (verbose_low()) { - gclog_or_tty->print_cr("[%d] somebody else moved the finger, " + gclog_or_tty->print_cr("[%u] somebody else moved the finger, " "global finger = "PTR_FORMAT", " "our finger = "PTR_FORMAT, - task_num, _finger, finger); + worker_id, _finger, finger); } // read it again @@ -2783,7 +2783,7 @@ void ConcurrentMark::verify_no_cset_oops(bool verify_stacks, _markStack.oops_do(&cl); // Verify entries on the task queues - for (int i = 0; i < (int) _max_task_num; i += 1) { + for (uint i = 0; i < _max_worker_id; i += 1) { cl.set_phase(VerifyNoCSetOopsQueues, i); OopTaskQueue* queue = _task_queues->queue(i); queue->oops_do(&cl); @@ -2822,7 +2822,7 @@ void ConcurrentMark::verify_no_cset_oops(bool verify_stacks, } // Verify the task fingers - assert(parallel_marking_threads() <= _max_task_num, "sanity"); + assert(parallel_marking_threads() <= _max_worker_id, "sanity"); for (int i = 0; i < (int) parallel_marking_threads(); i += 1) { CMTask* task = _tasks[i]; HeapWord* task_finger = task->finger(); @@ -2849,7 +2849,7 @@ void ConcurrentMark::clear_marking_state(bool clear_overflow) { } _finger = _heap_start; - for (int i = 0; i < (int)_max_task_num; ++i) { + for (uint i = 0; i < _max_worker_id; ++i) { OopTaskQueue* queue = _task_queues->queue(i); queue->set_empty(); } @@ -2862,15 +2862,15 @@ class AggregateCountDataHRClosure: public HeapRegionClosure { ConcurrentMark* _cm; CardTableModRefBS* _ct_bs; BitMap* _cm_card_bm; - size_t _max_task_num; + uint _max_worker_id; public: AggregateCountDataHRClosure(G1CollectedHeap* g1h, BitMap* cm_card_bm, - size_t max_task_num) : + uint max_worker_id) : _g1h(g1h), _cm(g1h->concurrent_mark()), _ct_bs((CardTableModRefBS*) (g1h->barrier_set())), - _cm_card_bm(cm_card_bm), _max_task_num(max_task_num) { } + _cm_card_bm(cm_card_bm), _max_worker_id(max_worker_id) { } bool doHeapRegion(HeapRegion* hr) { if (hr->continuesHumongous()) { @@ -2927,7 +2927,7 @@ class AggregateCountDataHRClosure: public HeapRegionClosure { uint hrs_index = hr->hrs_index(); size_t marked_bytes = 0; - for (int i = 0; (size_t)i < _max_task_num; i += 1) { + for (uint i = 0; i < _max_worker_id; i += 1) { size_t* marked_bytes_array = _cm->count_marked_bytes_array_for(i); BitMap* task_card_bm = _cm->count_card_bitmap_for(i); @@ -2935,7 +2935,7 @@ class AggregateCountDataHRClosure: public HeapRegionClosure { // add it to the running total for this region. marked_bytes += marked_bytes_array[hrs_index]; - // Now union the bitmaps[0,max_task_num)[start_idx..limit_idx) + // Now union the bitmaps[0,max_worker_id)[start_idx..limit_idx) // into the global card bitmap. BitMap::idx_t scan_idx = task_card_bm->get_next_one_offset(start_idx, limit_idx); @@ -2967,22 +2967,22 @@ protected: G1CollectedHeap* _g1h; ConcurrentMark* _cm; BitMap* _cm_card_bm; - size_t _max_task_num; + uint _max_worker_id; int _active_workers; public: G1AggregateCountDataTask(G1CollectedHeap* g1h, ConcurrentMark* cm, BitMap* cm_card_bm, - size_t max_task_num, + uint max_worker_id, int n_workers) : AbstractGangTask("Count Aggregation"), _g1h(g1h), _cm(cm), _cm_card_bm(cm_card_bm), - _max_task_num(max_task_num), + _max_worker_id(max_worker_id), _active_workers(n_workers) { } void work(uint worker_id) { - AggregateCountDataHRClosure cl(_g1h, _cm_card_bm, _max_task_num); + AggregateCountDataHRClosure cl(_g1h, _cm_card_bm, _max_worker_id); if (G1CollectedHeap::use_parallel_gc_threads()) { _g1h->heap_region_par_iterate_chunked(&cl, worker_id, @@ -3001,7 +3001,7 @@ void ConcurrentMark::aggregate_count_data() { 1); G1AggregateCountDataTask g1_par_agg_task(_g1h, this, &_card_bm, - _max_task_num, n_workers); + _max_worker_id, n_workers); if (G1CollectedHeap::use_parallel_gc_threads()) { assert(_g1h->check_heap_region_claim_values(HeapRegion::InitialClaimValue), @@ -3030,9 +3030,9 @@ void ConcurrentMark::clear_all_count_data() { _region_bm.clear(); uint max_regions = _g1h->max_regions(); - assert(_max_task_num != 0, "unitialized"); + assert(_max_worker_id > 0, "uninitialized"); - for (int i = 0; (size_t) i < _max_task_num; i += 1) { + for (uint i = 0; i < _max_worker_id; i += 1) { BitMap* task_card_bm = count_card_bitmap_for(i); size_t* marked_bytes_array = count_marked_bytes_array_for(i); @@ -3062,7 +3062,7 @@ void ConcurrentMark::abort() { clear_all_count_data(); // Empty mark stack clear_marking_state(); - for (int i = 0; i < (int)_max_task_num; ++i) { + for (uint i = 0; i < _max_worker_id; ++i) { _tasks[i]->clear_region_fields(); } _has_aborted = true; @@ -3154,8 +3154,8 @@ bool ConcurrentMark::containing_cards_are_marked(void* start, void ConcurrentMark::print_finger() { gclog_or_tty->print_cr("heap ["PTR_FORMAT", "PTR_FORMAT"), global finger = "PTR_FORMAT, _heap_start, _heap_end, _finger); - for (int i = 0; i < (int) _max_task_num; ++i) { - gclog_or_tty->print(" %d: "PTR_FORMAT, i, _tasks[i]->finger()); + for (uint i = 0; i < _max_worker_id; ++i) { + gclog_or_tty->print(" %u: "PTR_FORMAT, i, _tasks[i]->finger()); } gclog_or_tty->print_cr(""); } @@ -3165,8 +3165,8 @@ void CMTask::scan_object(oop obj) { assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant"); if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%d] we're scanning object "PTR_FORMAT, - _task_id, (void*) obj); + gclog_or_tty->print_cr("[%u] we're scanning object "PTR_FORMAT, + _worker_id, (void*) obj); } size_t obj_size = obj->size(); @@ -3245,8 +3245,8 @@ void CMTask::setup_for_region(HeapRegion* hr) { "claim_region() should have filtered out continues humongous regions"); if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] setting up for region "PTR_FORMAT, - _task_id, hr); + gclog_or_tty->print_cr("[%u] setting up for region "PTR_FORMAT, + _worker_id, hr); } _curr_region = hr; @@ -3261,9 +3261,9 @@ void CMTask::update_region_limit() { if (limit == bottom) { if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] found an empty region " + gclog_or_tty->print_cr("[%u] found an empty region " "["PTR_FORMAT", "PTR_FORMAT")", - _task_id, bottom, limit); + _worker_id, bottom, limit); } // The region was collected underneath our feet. // We set the finger to bottom to ensure that the bitmap @@ -3294,8 +3294,8 @@ void CMTask::update_region_limit() { void CMTask::giveup_current_region() { assert(_curr_region != NULL, "invariant"); if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] giving up region "PTR_FORMAT, - _task_id, _curr_region); + gclog_or_tty->print_cr("[%u] giving up region "PTR_FORMAT, + _worker_id, _curr_region); } clear_region_fields(); } @@ -3321,7 +3321,7 @@ void CMTask::reset(CMBitMap* nextMarkBitMap) { guarantee(nextMarkBitMap != NULL, "invariant"); if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] resetting", _task_id); + gclog_or_tty->print_cr("[%u] resetting", _worker_id); } _nextMarkBitMap = nextMarkBitMap; @@ -3415,9 +3415,9 @@ void CMTask::regular_clock_call() { _all_clock_intervals_ms.add(last_interval_ms); if (_cm->verbose_medium()) { - gclog_or_tty->print_cr("[%d] regular clock, interval = %1.2lfms, " + gclog_or_tty->print_cr("[%u] regular clock, interval = %1.2lfms, " "scanned = %d%s, refs reached = %d%s", - _task_id, last_interval_ms, + _worker_id, last_interval_ms, _words_scanned, (_words_scanned >= _words_scanned_limit) ? " (*)" : "", _refs_reached, @@ -3449,8 +3449,8 @@ void CMTask::regular_clock_call() { SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); if (!_draining_satb_buffers && satb_mq_set.process_completed_buffers()) { if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] aborting to deal with pending SATB buffers", - _task_id); + gclog_or_tty->print_cr("[%u] aborting to deal with pending SATB buffers", + _worker_id); } // we do need to process SATB buffers, we'll abort and restart // the marking task to do so @@ -3475,7 +3475,7 @@ void CMTask::decrease_limits() { // scanning limit so that the clock is called earlier. if (_cm->verbose_medium()) { - gclog_or_tty->print_cr("[%d] decreasing limits", _task_id); + gclog_or_tty->print_cr("[%u] decreasing limits", _worker_id); } _words_scanned_limit = _real_words_scanned_limit - @@ -3503,16 +3503,16 @@ void CMTask::move_entries_to_global_stack() { if (!_cm->mark_stack_push(buffer, n)) { if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] aborting due to global stack overflow", - _task_id); + gclog_or_tty->print_cr("[%u] aborting due to global stack overflow", + _worker_id); } set_has_aborted(); } else { // the transfer was successful if (_cm->verbose_medium()) { - gclog_or_tty->print_cr("[%d] pushed %d entries to the global stack", - _task_id, n); + gclog_or_tty->print_cr("[%u] pushed %d entries to the global stack", + _worker_id, n); } statsOnly( int tmp_size = _cm->mark_stack_size(); if (tmp_size > _global_max_size) { @@ -3539,8 +3539,8 @@ void CMTask::get_entries_from_global_stack() { statsOnly( ++_global_transfers_from; _global_pops += n ); if (_cm->verbose_medium()) { - gclog_or_tty->print_cr("[%d] popped %d entries from the global stack", - _task_id, n); + gclog_or_tty->print_cr("[%u] popped %d entries from the global stack", + _worker_id, n); } for (int i = 0; i < n; ++i) { bool success = _task_queue->push(buffer[i]); @@ -3575,8 +3575,8 @@ void CMTask::drain_local_queue(bool partially) { if (_task_queue->size() > target_size) { if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%d] draining local queue, target size = %d", - _task_id, target_size); + gclog_or_tty->print_cr("[%u] draining local queue, target size = %d", + _worker_id, target_size); } oop obj; @@ -3585,7 +3585,7 @@ void CMTask::drain_local_queue(bool partially) { statsOnly( ++_local_pops ); if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%d] popped "PTR_FORMAT, _task_id, + gclog_or_tty->print_cr("[%u] popped "PTR_FORMAT, _worker_id, (void*) obj); } @@ -3603,8 +3603,8 @@ void CMTask::drain_local_queue(bool partially) { } if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%d] drained local queue, size = %d", - _task_id, _task_queue->size()); + gclog_or_tty->print_cr("[%u] drained local queue, size = %d", + _worker_id, _task_queue->size()); } } } @@ -3631,8 +3631,8 @@ void CMTask::drain_global_stack(bool partially) { if (_cm->mark_stack_size() > target_size) { if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] draining global_stack, target size %d", - _task_id, target_size); + gclog_or_tty->print_cr("[%u] draining global_stack, target size %d", + _worker_id, target_size); } while (!has_aborted() && _cm->mark_stack_size() > target_size) { @@ -3641,8 +3641,8 @@ void CMTask::drain_global_stack(bool partially) { } if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] drained global stack, size = %d", - _task_id, _cm->mark_stack_size()); + gclog_or_tty->print_cr("[%u] drained global stack, size = %d", + _worker_id, _cm->mark_stack_size()); } } } @@ -3663,7 +3663,7 @@ void CMTask::drain_satb_buffers() { CMObjectClosure oc(this); SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); if (G1CollectedHeap::use_parallel_gc_threads()) { - satb_mq_set.set_par_closure(_task_id, &oc); + satb_mq_set.set_par_closure(_worker_id, &oc); } else { satb_mq_set.set_closure(&oc); } @@ -3672,9 +3672,9 @@ void CMTask::drain_satb_buffers() { // until we run out of buffers or we need to abort. if (G1CollectedHeap::use_parallel_gc_threads()) { while (!has_aborted() && - satb_mq_set.par_apply_closure_to_completed_buffer(_task_id)) { + satb_mq_set.par_apply_closure_to_completed_buffer(_worker_id)) { if (_cm->verbose_medium()) { - gclog_or_tty->print_cr("[%d] processed an SATB buffer", _task_id); + gclog_or_tty->print_cr("[%u] processed an SATB buffer", _worker_id); } statsOnly( ++_satb_buffers_processed ); regular_clock_call(); @@ -3683,7 +3683,7 @@ void CMTask::drain_satb_buffers() { while (!has_aborted() && satb_mq_set.apply_closure_to_completed_buffer()) { if (_cm->verbose_medium()) { - gclog_or_tty->print_cr("[%d] processed an SATB buffer", _task_id); + gclog_or_tty->print_cr("[%u] processed an SATB buffer", _worker_id); } statsOnly( ++_satb_buffers_processed ); regular_clock_call(); @@ -3693,7 +3693,7 @@ void CMTask::drain_satb_buffers() { if (!concurrent() && !has_aborted()) { // We should only do this during remark. if (G1CollectedHeap::use_parallel_gc_threads()) { - satb_mq_set.par_iterate_closure_all_threads(_task_id); + satb_mq_set.par_iterate_closure_all_threads(_worker_id); } else { satb_mq_set.iterate_closure_all_threads(); } @@ -3706,7 +3706,7 @@ void CMTask::drain_satb_buffers() { satb_mq_set.completed_buffers_num() == 0, "invariant"); if (G1CollectedHeap::use_parallel_gc_threads()) { - satb_mq_set.set_par_closure(_task_id, NULL); + satb_mq_set.set_par_closure(_worker_id, NULL); } else { satb_mq_set.set_closure(NULL); } @@ -3717,8 +3717,8 @@ void CMTask::drain_satb_buffers() { } void CMTask::print_stats() { - gclog_or_tty->print_cr("Marking Stats, task = %d, calls = %d", - _task_id, _calls); + gclog_or_tty->print_cr("Marking Stats, task = %u, calls = %d", + _worker_id, _calls); gclog_or_tty->print_cr(" Elapsed time = %1.2lfms, Termination time = %1.2lfms", _elapsed_time_ms, _termination_time_ms); gclog_or_tty->print_cr(" Step Times (cum): num = %d, avg = %1.2lfms, sd = %1.2lfms", @@ -3866,7 +3866,7 @@ void CMTask::do_marking_step(double time_target_ms, G1CollectorPolicy* g1_policy = _g1h->g1_policy(); assert(_task_queues != NULL, "invariant"); assert(_task_queue != NULL, "invariant"); - assert(_task_queues->queue(_task_id) == _task_queue, "invariant"); + assert(_task_queues->queue(_worker_id) == _task_queue, "invariant"); assert(!_claimed, "only one thread should claim this task at any one time"); @@ -3898,9 +3898,9 @@ void CMTask::do_marking_step(double time_target_ms, ++_calls; if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] >>>>>>>>>> START, call = %d, " + gclog_or_tty->print_cr("[%u] >>>>>>>>>> START, call = %d, " "target = %1.2lfms >>>>>>>>>>", - _task_id, _calls, _time_target_ms); + _worker_id, _calls, _time_target_ms); } // Set up the bitmap and oop closures. Anything that uses them is @@ -3948,10 +3948,10 @@ void CMTask::do_marking_step(double time_target_ms, MemRegion mr = MemRegion(_finger, _region_limit); if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] we're scanning part " + gclog_or_tty->print_cr("[%u] we're scanning part " "["PTR_FORMAT", "PTR_FORMAT") " "of region "PTR_FORMAT, - _task_id, _finger, _region_limit, _curr_region); + _worker_id, _finger, _region_limit, _curr_region); } // Let's iterate over the bitmap of the part of the @@ -4007,17 +4007,17 @@ void CMTask::do_marking_step(double time_target_ms, assert(_finger == NULL, "invariant"); assert(_region_limit == NULL, "invariant"); if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] trying to claim a new region", _task_id); + gclog_or_tty->print_cr("[%u] trying to claim a new region", _worker_id); } - HeapRegion* claimed_region = _cm->claim_region(_task_id); + HeapRegion* claimed_region = _cm->claim_region(_worker_id); if (claimed_region != NULL) { // Yes, we managed to claim one statsOnly( ++_regions_claimed ); if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] we successfully claimed " + gclog_or_tty->print_cr("[%u] we successfully claimed " "region "PTR_FORMAT, - _task_id, claimed_region); + _worker_id, claimed_region); } setup_for_region(claimed_region); @@ -4044,7 +4044,7 @@ void CMTask::do_marking_step(double time_target_ms, "at this point we should be out of regions"); if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] all regions claimed", _task_id); + gclog_or_tty->print_cr("[%u] all regions claimed", _worker_id); } // Try to reduce the number of available SATB buffers so that @@ -4068,17 +4068,17 @@ void CMTask::do_marking_step(double time_target_ms, "only way to reach here"); if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] starting to steal", _task_id); + gclog_or_tty->print_cr("[%u] starting to steal", _worker_id); } while (!has_aborted()) { oop obj; statsOnly( ++_steal_attempts ); - if (_cm->try_stealing(_task_id, &_hash_seed, obj)) { + if (_cm->try_stealing(_worker_id, &_hash_seed, obj)) { if (_cm->verbose_medium()) { - gclog_or_tty->print_cr("[%d] stolen "PTR_FORMAT" successfully", - _task_id, (void*) obj); + gclog_or_tty->print_cr("[%u] stolen "PTR_FORMAT" successfully", + _worker_id, (void*) obj); } statsOnly( ++_steals ); @@ -4116,7 +4116,7 @@ void CMTask::do_marking_step(double time_target_ms, assert(_task_queue->size() == 0, "only way to reach here"); if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] starting termination protocol", _task_id); + gclog_or_tty->print_cr("[%u] starting termination protocol", _worker_id); } _termination_start_time_ms = os::elapsedVTime() * 1000.0; @@ -4131,7 +4131,7 @@ void CMTask::do_marking_step(double time_target_ms, if (finished) { // We're all done. - if (_task_id == 0) { + if (_worker_id == 0) { // let's allow task 0 to do this if (concurrent()) { assert(_cm->concurrent_marking_in_progress(), "invariant"); @@ -4153,15 +4153,15 @@ void CMTask::do_marking_step(double time_target_ms, guarantee(!_cm->mark_stack_overflow(), "only way to reach here"); if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] all tasks terminated", _task_id); + gclog_or_tty->print_cr("[%u] all tasks terminated", _worker_id); } } else { // Apparently there's more work to do. Let's abort this task. It // will restart it and we can hopefully find more things to do. if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] apparently there is more work to do", - _task_id); + gclog_or_tty->print_cr("[%u] apparently there is more work to do", + _worker_id); } set_has_aborted(); @@ -4200,10 +4200,10 @@ void CMTask::do_marking_step(double time_target_ms, // will achieve this with the use of two barrier sync points. if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] detected overflow", _task_id); + gclog_or_tty->print_cr("[%u] detected overflow", _worker_id); } - _cm->enter_first_sync_barrier(_task_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, @@ -4215,39 +4215,39 @@ void CMTask::do_marking_step(double time_target_ms, clear_region_fields(); // ...and enter the second barrier. - _cm->enter_second_sync_barrier(_task_id); + _cm->enter_second_sync_barrier(_worker_id); // At this point everything has bee re-initialised and we're // ready to restart. } if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] <<<<<<<<<< ABORTING, target = %1.2lfms, " + gclog_or_tty->print_cr("[%u] <<<<<<<<<< ABORTING, target = %1.2lfms, " "elapsed = %1.2lfms <<<<<<<<<<", - _task_id, _time_target_ms, elapsed_time_ms); + _worker_id, _time_target_ms, elapsed_time_ms); if (_cm->has_aborted()) { - gclog_or_tty->print_cr("[%d] ========== MARKING ABORTED ==========", - _task_id); + gclog_or_tty->print_cr("[%u] ========== MARKING ABORTED ==========", + _worker_id); } } } else { if (_cm->verbose_low()) { - gclog_or_tty->print_cr("[%d] <<<<<<<<<< FINISHED, target = %1.2lfms, " + gclog_or_tty->print_cr("[%u] <<<<<<<<<< FINISHED, target = %1.2lfms, " "elapsed = %1.2lfms <<<<<<<<<<", - _task_id, _time_target_ms, elapsed_time_ms); + _worker_id, _time_target_ms, elapsed_time_ms); } } _claimed = false; } -CMTask::CMTask(int task_id, +CMTask::CMTask(uint worker_id, ConcurrentMark* cm, size_t* marked_bytes, BitMap* card_bm, CMTaskQueue* task_queue, CMTaskQueueSet* task_queues) : _g1h(G1CollectedHeap::heap()), - _task_id(task_id), _cm(cm), + _worker_id(worker_id), _cm(cm), _claimed(false), _nextMarkBitMap(NULL), _hash_seed(17), _task_queue(task_queue), diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp index abb46e1065c..5bac7a6b34d 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp @@ -399,9 +399,9 @@ protected: // last claimed region // marking tasks - uint _max_task_num; // maximum task number + uint _max_worker_id;// maximum worker id uint _active_tasks; // task num currently active - CMTask** _tasks; // task queue array (max_task_num len) + CMTask** _tasks; // task queue array (max_worker_id len) CMTaskQueueSet* _task_queues; // task queue set ParallelTaskTerminator _terminator; // for termination @@ -492,10 +492,10 @@ protected: ParallelTaskTerminator* terminator() { return &_terminator; } // It claims the next available region to be scanned by a marking - // task. It might return NULL if the next region is empty or we have - // run out of regions. In the latter case, out_of_regions() + // task/thread. It might return NULL if the next region is empty or + // we have run out of regions. In the latter case, out_of_regions() // determines whether we've really run out of regions or the task - // should call claim_region() again. This might seem a bit + // should call claim_region() again. This might seem a bit // awkward. Originally, the code was written so that claim_region() // either successfully returned with a non-empty region or there // were no more regions to be claimed. The problem with this was @@ -505,7 +505,7 @@ protected: // method. So, this way, each task will spend very little time in // claim_region() and is allowed to call the regular clock method // frequently. - HeapRegion* claim_region(int task); + HeapRegion* claim_region(uint worker_id); // It determines whether we've run out of regions to scan. bool out_of_regions() { return _finger == _heap_end; } @@ -537,8 +537,8 @@ protected: bool has_aborted() { return _has_aborted; } // Methods to enter the two overflow sync barriers - void enter_first_sync_barrier(int task_num); - void enter_second_sync_barrier(int task_num); + void enter_first_sync_barrier(uint worker_id); + void enter_second_sync_barrier(uint worker_id); ForceOverflowSettings* force_overflow_conc() { return &_force_overflow_conc; @@ -626,14 +626,14 @@ public: double all_task_accum_vtime() { double ret = 0.0; - for (int i = 0; i < (int)_max_task_num; ++i) + for (uint i = 0; i < _max_worker_id; ++i) ret += _accum_task_vtime[i]; return ret; } // Attempts to steal an object from the task queues of other tasks - bool try_stealing(int task_num, int* hash_seed, oop& obj) { - return _task_queues->steal(task_num, hash_seed, obj); + bool try_stealing(uint worker_id, int* hash_seed, oop& obj) { + return _task_queues->steal(worker_id, hash_seed, obj); } ConcurrentMark(ReservedSpace rs, uint max_regions); @@ -823,7 +823,7 @@ public: // Returns the card bitmap for a given task or worker id. BitMap* count_card_bitmap_for(uint worker_id) { - assert(0 <= worker_id && worker_id < _max_task_num, "oob"); + assert(0 <= worker_id && worker_id < _max_worker_id, "oob"); assert(_count_card_bitmaps != NULL, "uninitialized"); BitMap* task_card_bm = &_count_card_bitmaps[worker_id]; assert(task_card_bm->size() == _card_bm.size(), "size mismatch"); @@ -833,7 +833,7 @@ public: // Returns the array containing the marked bytes for each region, // for the given worker or task id. size_t* count_marked_bytes_array_for(uint worker_id) { - assert(0 <= worker_id && worker_id < _max_task_num, "oob"); + assert(0 <= worker_id && worker_id < _max_worker_id, "oob"); assert(_count_marked_bytes != NULL, "uninitialized"); size_t* marked_bytes_array = _count_marked_bytes[worker_id]; assert(marked_bytes_array != NULL, "uninitialized"); @@ -939,7 +939,7 @@ private: global_stack_transfer_size = 16 }; - int _task_id; + uint _worker_id; G1CollectedHeap* _g1h; ConcurrentMark* _cm; CMBitMap* _nextMarkBitMap; @@ -1115,8 +1115,8 @@ public: _elapsed_time_ms = os::elapsedTime() * 1000.0 - _elapsed_time_ms; } - // returns the task ID - int task_id() { return _task_id; } + // returns the worker ID associated with this task. + uint worker_id() { return _worker_id; } // From TerminatorTerminator. It determines whether this task should // exit the termination protocol after it's entered it. @@ -1170,7 +1170,7 @@ public: _finger = new_finger; } - CMTask(int task_num, ConcurrentMark *cm, + CMTask(uint worker_id, ConcurrentMark *cm, size_t* marked_bytes, BitMap* card_bm, CMTaskQueue* task_queue, CMTaskQueueSet* task_queues); 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 7f69234a5b7..f084bca5a77 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp @@ -279,7 +279,7 @@ inline void CMTask::push(oop obj) { assert(_nextMarkBitMap->isMarked(objAddr), "invariant"); if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%d] pushing "PTR_FORMAT, _task_id, (void*) obj); + gclog_or_tty->print_cr("[%u] pushing "PTR_FORMAT, _worker_id, (void*) obj); } if (!_task_queue->push(obj)) { @@ -287,9 +287,9 @@ inline void CMTask::push(oop obj) { // to the global stack. if (_cm->verbose_medium()) { - gclog_or_tty->print_cr("[%d] task queue overflow, " + gclog_or_tty->print_cr("[%u] task queue overflow, " "moving entries to the global stack", - _task_id); + _worker_id); } move_entries_to_global_stack(); @@ -318,8 +318,8 @@ inline void CMTask::push(oop obj) { inline void CMTask::deal_with_reference(oop obj) { if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%d] we're dealing with reference = "PTR_FORMAT, - _task_id, (void*) obj); + gclog_or_tty->print_cr("[%u] we're dealing with reference = "PTR_FORMAT, + _worker_id, (void*) obj); } ++_refs_reached; @@ -335,8 +335,8 @@ inline void CMTask::deal_with_reference(oop obj) { HeapRegion* hr = _g1h->heap_region_containing_raw(obj); if (!hr->obj_allocated_since_next_marking(obj)) { if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%d] "PTR_FORMAT" is not considered marked", - _task_id, (void*) obj); + gclog_or_tty->print_cr("[%u] "PTR_FORMAT" is not considered marked", + _worker_id, (void*) obj); } // we need to mark it first @@ -350,8 +350,8 @@ inline void CMTask::deal_with_reference(oop obj) { if (_finger != NULL && objAddr < _finger) { if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%d] below the local finger ("PTR_FORMAT"), " - "pushing it", _task_id, _finger); + gclog_or_tty->print_cr("[%u] below the local finger ("PTR_FORMAT"), " + "pushing it", _worker_id, _finger); } push(obj); } else if (_curr_region != NULL && objAddr < _region_limit) { @@ -367,9 +367,9 @@ inline void CMTask::deal_with_reference(oop obj) { // correctness problems. if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%d] below the global finger " + gclog_or_tty->print_cr("[%u] below the global finger " "("PTR_FORMAT"), pushing it", - _task_id, global_finger); + _worker_id, global_finger); } push(obj); } else { @@ -382,9 +382,9 @@ inline void CMTask::deal_with_reference(oop obj) { // see long comment above if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%d] below the global finger " + gclog_or_tty->print_cr("[%u] below the global finger " "("PTR_FORMAT"), pushing it", - _task_id, global_finger); + _worker_id, global_finger); } push(obj); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index f023f932ab8..471e638de19 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -3388,6 +3388,7 @@ void G1CollectedHeap::print_on(outputStream* st) const { st->print("%u survivors (" SIZE_FORMAT "K)", survivor_regions, (size_t) survivor_regions * HeapRegion::GrainBytes / K); st->cr(); + MetaspaceAux::print_on(st); } void G1CollectedHeap::print_extended_on(outputStream* st) const { diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp index c84de6e9e68..e26d2a6951d 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp @@ -111,9 +111,9 @@ inline void G1CMOopClosure::do_oop_nv(T* p) { oop obj = oopDesc::load_decode_heap_oop(p); if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%d] we're looking at location " + gclog_or_tty->print_cr("[%u] we're looking at location " "*"PTR_FORMAT" = "PTR_FORMAT, - _task->task_id(), p, (void*) obj); + _task->worker_id(), p, (void*) obj); } _task->deal_with_reference(obj); } diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp index 44e764f7ae7..a37555d2c3b 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp @@ -139,7 +139,7 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { if (VerifyBeforeGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification gclog_or_tty->print(" VerifyBeforeGC:"); - Universe::verify(true); + Universe::verify(); } // Verify object start arrays @@ -341,7 +341,7 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) { if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification gclog_or_tty->print(" VerifyAfterGC:"); - Universe::verify(false); + Universe::verify(); } // Re-verify object start arrays diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp index 7a077621277..fc6d5ef59d3 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp @@ -983,7 +983,7 @@ void PSParallelCompact::pre_compact(PreGCValues* pre_gc_values) if (VerifyBeforeGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification gclog_or_tty->print(" VerifyBeforeGC:"); - Universe::verify(true); + Universe::verify(); } // Verify object start arrays @@ -2184,7 +2184,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification gclog_or_tty->print(" VerifyAfterGC:"); - Universe::verify(false); + Universe::verify(); } // Re-verify object start arrays diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp index 370311d1c9c..f68b1b5a446 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp @@ -315,7 +315,7 @@ bool PSScavenge::invoke_no_policy() { if (VerifyBeforeGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification gclog_or_tty->print(" VerifyBeforeGC:"); - Universe::verify(true); + Universe::verify(); } { @@ -639,7 +639,7 @@ bool PSScavenge::invoke_no_policy() { if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification gclog_or_tty->print(" VerifyAfterGC:"); - Universe::verify(false); + Universe::verify(); } heap->print_heap_after_gc(); diff --git a/hotspot/src/share/vm/memory/allocation.cpp b/hotspot/src/share/vm/memory/allocation.cpp index b5067c2f6ea..56c7b63fbe5 100644 --- a/hotspot/src/share/vm/memory/allocation.cpp +++ b/hotspot/src/share/vm/memory/allocation.cpp @@ -92,6 +92,26 @@ void* ResourceObj::operator new(size_t size, allocation_type type, MEMFLAGS flag return res; } +void* ResourceObj::operator new(size_t size, const std::nothrow_t& nothrow_constant, + allocation_type type, MEMFLAGS flags) { + //should only call this with std::nothrow, use other operator new() otherwise + address res; + switch (type) { + case C_HEAP: + res = (address)AllocateHeap(size, flags, CALLER_PC, AllocFailStrategy::RETURN_NULL); + DEBUG_ONLY(if (res!= NULL) set_allocation_type(res, C_HEAP);) + break; + case RESOURCE_AREA: + // new(size) sets allocation type RESOURCE_AREA. + res = (address)operator new(size, std::nothrow); + break; + default: + ShouldNotReachHere(); + } + return res; +} + + void ResourceObj::operator delete(void* p) { assert(((ResourceObj *)p)->allocated_on_C_heap(), "delete only allowed for C_HEAP objects"); @@ -506,7 +526,7 @@ void Arena::signal_out_of_memory(size_t sz, const char* whence) const { } // Grow a new Chunk -void* Arena::grow( size_t x ) { +void* Arena::grow(size_t x, AllocFailType alloc_failmode) { // Get minimal required size. Either real big, or even bigger for giant objs size_t len = MAX2(x, (size_t) Chunk::size); @@ -514,7 +534,10 @@ void* Arena::grow( size_t x ) { _chunk = new (len) Chunk(len); if (_chunk == NULL) { - signal_out_of_memory(len * Chunk::aligned_overhead_size(), "Arena::grow"); + if (alloc_failmode == AllocFailStrategy::EXIT_OOM) { + signal_out_of_memory(len * Chunk::aligned_overhead_size(), "Arena::grow"); + } + return NULL; } if (k) k->set_next(_chunk); // Append new chunk to end of linked list else _first = _chunk; @@ -529,13 +552,16 @@ void* Arena::grow( size_t x ) { // Reallocate storage in Arena. -void *Arena::Arealloc(void* old_ptr, size_t old_size, size_t new_size) { +void *Arena::Arealloc(void* old_ptr, size_t old_size, size_t new_size, AllocFailType alloc_failmode) { assert(new_size >= 0, "bad size"); if (new_size == 0) return NULL; #ifdef ASSERT if (UseMallocOnly) { // always allocate a new object (otherwise we'll free this one twice) - char* copy = (char*)Amalloc(new_size); + char* copy = (char*)Amalloc(new_size, alloc_failmode); + if (copy == NULL) { + return NULL; + } size_t n = MIN2(old_size, new_size); if (n > 0) memcpy(copy, old_ptr, n); Afree(old_ptr,old_size); // Mostly done to keep stats accurate @@ -561,7 +587,10 @@ void *Arena::Arealloc(void* old_ptr, size_t old_size, size_t new_size) { } // Oops, got to relocate guts - void *new_ptr = Amalloc(new_size); + void *new_ptr = Amalloc(new_size, alloc_failmode); + if (new_ptr == NULL) { + return NULL; + } memcpy( new_ptr, c_old, old_size ); Afree(c_old,old_size); // Mostly done to keep stats accurate return new_ptr; diff --git a/hotspot/src/share/vm/memory/allocation.hpp b/hotspot/src/share/vm/memory/allocation.hpp index 6bae79f8133..30662b8e5da 100644 --- a/hotspot/src/share/vm/memory/allocation.hpp +++ b/hotspot/src/share/vm/memory/allocation.hpp @@ -53,6 +53,12 @@ #endif #endif +class AllocFailStrategy { +public: + enum AllocFailEnum { EXIT_OOM, RETURN_NULL }; +}; +typedef AllocFailStrategy::AllocFailEnum AllocFailType; + // All classes in the virtual machine must be subclassed // by one of the following allocation classes: // @@ -315,7 +321,8 @@ protected: Chunk *_first; // First chunk Chunk *_chunk; // current chunk char *_hwm, *_max; // High water mark and max in current chunk - void* grow(size_t x); // Get a new Chunk of at least size x + // Get a new Chunk of at least size x + void* grow(size_t x, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); size_t _size_in_bytes; // Size of arena (used for native memory tracking) NOT_PRODUCT(static julong _bytes_allocated;) // total #bytes allocated since start @@ -350,14 +357,14 @@ protected: void operator delete(void* p); // Fast allocate in the arena. Common case is: pointer test + increment. - void* Amalloc(size_t x) { + void* Amalloc(size_t x, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { assert(is_power_of_2(ARENA_AMALLOC_ALIGNMENT) , "should be a power of 2"); x = ARENA_ALIGN(x); debug_only(if (UseMallocOnly) return malloc(x);) check_for_overflow(x, "Arena::Amalloc"); NOT_PRODUCT(inc_bytes_allocated(x);) if (_hwm + x > _max) { - return grow(x); + return grow(x, alloc_failmode); } else { char *old = _hwm; _hwm += x; @@ -365,13 +372,13 @@ protected: } } // Further assume size is padded out to words - void *Amalloc_4(size_t x) { + void *Amalloc_4(size_t x, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { assert( (x&(sizeof(char*)-1)) == 0, "misaligned size" ); debug_only(if (UseMallocOnly) return malloc(x);) check_for_overflow(x, "Arena::Amalloc_4"); NOT_PRODUCT(inc_bytes_allocated(x);) if (_hwm + x > _max) { - return grow(x); + return grow(x, alloc_failmode); } else { char *old = _hwm; _hwm += x; @@ -381,7 +388,7 @@ protected: // Allocate with 'double' alignment. It is 8 bytes on sparc. // In other cases Amalloc_D() should be the same as Amalloc_4(). - void* Amalloc_D(size_t x) { + void* Amalloc_D(size_t x, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { assert( (x&(sizeof(char*)-1)) == 0, "misaligned size" ); debug_only(if (UseMallocOnly) return malloc(x);) #if defined(SPARC) && !defined(_LP64) @@ -392,7 +399,7 @@ protected: check_for_overflow(x, "Arena::Amalloc_D"); NOT_PRODUCT(inc_bytes_allocated(x);) if (_hwm + x > _max) { - return grow(x); // grow() returns a result aligned >= 8 bytes. + return grow(x, alloc_failmode); // grow() returns a result aligned >= 8 bytes. } else { char *old = _hwm; _hwm += x; @@ -412,7 +419,8 @@ protected: if (((char*)ptr) + size == _hwm) _hwm = (char*)ptr; } - void *Arealloc( void *old_ptr, size_t old_size, size_t new_size ); + void *Arealloc( void *old_ptr, size_t old_size, size_t new_size, + AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); // Move contents of this arena into an empty arena Arena *move_contents(Arena *empty_arena); @@ -458,9 +466,12 @@ private: //%note allocation_1 -extern char* resource_allocate_bytes(size_t size); -extern char* resource_allocate_bytes(Thread* thread, size_t size); -extern char* resource_reallocate_bytes( char *old, size_t old_size, size_t new_size); +extern char* resource_allocate_bytes(size_t size, + AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); +extern char* resource_allocate_bytes(Thread* thread, size_t size, + AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); +extern char* resource_reallocate_bytes( char *old, size_t old_size, size_t new_size, + AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); extern void resource_free_bytes( char *old, size_t size ); //---------------------------------------------------------------------- @@ -496,6 +507,8 @@ class ResourceObj ALLOCATION_SUPER_CLASS_SPEC { public: void* operator new(size_t size, allocation_type type, MEMFLAGS flags); + void* operator new(size_t size, const std::nothrow_t& nothrow_constant, + allocation_type type, MEMFLAGS flags); void* operator new(size_t size, Arena *arena) { address res = (address)arena->Amalloc(size); DEBUG_ONLY(set_allocation_type(res, ARENA);) @@ -506,6 +519,13 @@ class ResourceObj ALLOCATION_SUPER_CLASS_SPEC { DEBUG_ONLY(set_allocation_type(res, RESOURCE_AREA);) return res; } + + void* operator new(size_t size, const std::nothrow_t& nothrow_constant) { + address res = (address)resource_allocate_bytes(size, AllocFailStrategy::RETURN_NULL); + DEBUG_ONLY(if (res != NULL) set_allocation_type(res, RESOURCE_AREA);) + return res; + } + void operator delete(void* p); }; diff --git a/hotspot/src/share/vm/memory/allocation.inline.hpp b/hotspot/src/share/vm/memory/allocation.inline.hpp index 804faa2a17a..ead6fb12b21 100644 --- a/hotspot/src/share/vm/memory/allocation.inline.hpp +++ b/hotspot/src/share/vm/memory/allocation.inline.hpp @@ -48,7 +48,8 @@ inline void inc_stat_counter(volatile julong* dest, julong add_value) { #endif // allocate using malloc; will fail if no memory available -inline char* AllocateHeap(size_t size, MEMFLAGS flags, address pc = 0) { +inline char* AllocateHeap(size_t size, MEMFLAGS flags, address pc = 0, + AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { if (pc == 0) { pc = CURRENT_PC; } @@ -56,16 +57,17 @@ inline char* AllocateHeap(size_t size, MEMFLAGS flags, address pc = 0) { #ifdef ASSERT if (PrintMallocFree) trace_heap_malloc(size, "AllocateHeap", p); #endif - if (p == NULL) vm_exit_out_of_memory(size, "AllocateHeap"); + if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) vm_exit_out_of_memory(size, "AllocateHeap"); return p; } -inline char* ReallocateHeap(char *old, size_t size, MEMFLAGS flags) { +inline char* ReallocateHeap(char *old, size_t size, MEMFLAGS flags, + AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { char* p = (char*) os::realloc(old, size, flags, CURRENT_PC); #ifdef ASSERT if (PrintMallocFree) trace_heap_malloc(size, "ReallocateHeap", p); #endif - if (p == NULL) vm_exit_out_of_memory(size, "ReallocateHeap"); + if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) vm_exit_out_of_memory(size, "ReallocateHeap"); return p; } @@ -91,11 +93,13 @@ template void* CHeapObj::operator new(size_t size, template void* CHeapObj::operator new (size_t size, const std::nothrow_t& nothrow_constant, address caller_pc) { #ifdef ASSERT - void* p = os::malloc(size, F, (caller_pc != 0 ? caller_pc : CALLER_PC)); + void* p = (void*)AllocateHeap(size, F, (caller_pc != 0 ? caller_pc : CALLER_PC), + AllocFailStrategy::RETURN_NULL); if (PrintMallocFree) trace_heap_malloc(size, "CHeapObj-new", p); return p; #else - return os::malloc(size, F, (caller_pc != 0 ? caller_pc : CALLER_PC)); + return (void *) AllocateHeap(size, F, (caller_pc != 0 ? caller_pc : CALLER_PC), + AllocFailStrategy::RETURN_NULL); #endif } diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index 0b6db282497..13778b06d50 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -447,7 +447,7 @@ void GenCollectedHeap::do_collection(bool full, prepared_for_verification = true; } gclog_or_tty->print(" VerifyBeforeGC:"); - Universe::verify(true); + Universe::verify(); } COMPILER2_PRESENT(DerivedPointerTable::clear()); @@ -519,7 +519,7 @@ void GenCollectedHeap::do_collection(bool full, total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification gclog_or_tty->print(" VerifyAfterGC:"); - Universe::verify(false); + Universe::verify(); } if (PrintGCDetails) { diff --git a/hotspot/src/share/vm/memory/resourceArea.cpp b/hotspot/src/share/vm/memory/resourceArea.cpp index 28d5943b592..12a56d0f4be 100644 --- a/hotspot/src/share/vm/memory/resourceArea.cpp +++ b/hotspot/src/share/vm/memory/resourceArea.cpp @@ -45,15 +45,15 @@ debug_only(int ResourceArea::_warned;) // to suppress multiple warnings // The following routines are declared in allocation.hpp and used everywhere: // Allocation in thread-local resource area -extern char* resource_allocate_bytes(size_t size) { - return Thread::current()->resource_area()->allocate_bytes(size); +extern char* resource_allocate_bytes(size_t size, AllocFailType alloc_failmode) { + return Thread::current()->resource_area()->allocate_bytes(size, alloc_failmode); } -extern char* resource_allocate_bytes(Thread* thread, size_t size) { - return thread->resource_area()->allocate_bytes(size); +extern char* resource_allocate_bytes(Thread* thread, size_t size, AllocFailType alloc_failmode) { + return thread->resource_area()->allocate_bytes(size, alloc_failmode); } -extern char* resource_reallocate_bytes( char *old, size_t old_size, size_t new_size){ - return (char*)Thread::current()->resource_area()->Arealloc(old, old_size, new_size); +extern char* resource_reallocate_bytes( char *old, size_t old_size, size_t new_size, AllocFailType alloc_failmode){ + return (char*)Thread::current()->resource_area()->Arealloc(old, old_size, new_size, alloc_failmode); } extern void resource_free_bytes( char *old, size_t size ) { diff --git a/hotspot/src/share/vm/memory/resourceArea.hpp b/hotspot/src/share/vm/memory/resourceArea.hpp index 567f41d400a..f42c0f62457 100644 --- a/hotspot/src/share/vm/memory/resourceArea.hpp +++ b/hotspot/src/share/vm/memory/resourceArea.hpp @@ -68,7 +68,7 @@ public: debug_only(_nesting = 0;); } - char* allocate_bytes(size_t size) { + char* allocate_bytes(size_t size, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { #ifdef ASSERT if (_nesting < 1 && !_warned++) fatal("memory leak: allocating without ResourceMark"); @@ -78,7 +78,7 @@ public: return (*save = (char*)os::malloc(size, mtThread)); } #endif - return (char*)Amalloc(size); + return (char*)Amalloc(size, alloc_failmode); } debug_only(int nesting() const { return _nesting; }); diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index a4af5a8c98f..35cc0db712e 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -1268,10 +1268,6 @@ void Universe::print_heap_after_gc(outputStream* st, bool ignore_extended) { } void Universe::verify(bool silent, VerifyOption option) { - if (SharedSkipVerify) { - return; - } - // The use of _verify_in_progress is a temporary work around for // 6320749. Don't bother with a creating a class to set and clear // it since it is only used in this method and the control flow is diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index 12e0acb3ce0..ca7b09c7b19 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.hpp @@ -435,8 +435,14 @@ class Universe: AllStatic { // Debugging static bool verify_in_progress() { return _verify_in_progress; } - static void verify(bool silent = false, - VerifyOption option = VerifyOption_Default ); + static void verify(bool silent, VerifyOption option); + static void verify(bool silent) { + verify(silent, VerifyOption_Default /* option */); + } + static void verify() { + verify(false /* silent */); + } + static int verify_count() { return _verify_count; } // The default behavior is to call print_on() on gclog_or_tty. static void print(); diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp index 94546f0d71a..06a99aff6b0 100644 --- a/hotspot/src/share/vm/oops/klass.cpp +++ b/hotspot/src/share/vm/oops/klass.cpp @@ -356,12 +356,11 @@ void Klass::set_next_sibling(Klass* s) { } void Klass::append_to_sibling_list() { - debug_only(if (!SharedSkipVerify) verify();) + debug_only(verify();) // add ourselves to superklass' subklass list InstanceKlass* super = superklass(); if (super == NULL) return; // special case: class Object - assert(SharedSkipVerify || - (!super->is_interface() // interfaces cannot be supers + assert((!super->is_interface() // interfaces cannot be supers && (super->superklass() == NULL || !is_interface())), "an interface can only be a subklass of Object"); Klass* prev_first_subklass = super->subklass_oop(); @@ -371,7 +370,7 @@ void Klass::append_to_sibling_list() { } // make ourselves the superklass' first subklass super->set_subklass(this); - debug_only(if (!SharedSkipVerify) verify();) + debug_only(verify();) } void Klass::remove_from_sibling_list() { diff --git a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp index 22871642434..c3e744bd32e 100644 --- a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp +++ b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp @@ -1135,7 +1135,7 @@ static jint invoke_primitive_field_callback_for_static_fields // get offset and field value int offset = field->field_offset(); - address addr = (address)klass + offset; + address addr = (address)klass->java_mirror() + offset; jvalue value; copy_to_jvalue(&value, addr, value_type); diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index e073cbcd007..e783883ebe0 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -3539,10 +3539,6 @@ class CommandLineFlags { product(uintx, SharedDummyBlockSize, 0, \ "Size of dummy block used to shift heap addresses (in bytes)") \ \ - diagnostic(bool, SharedSkipVerify, false, \ - "Skip assert() and verify() which page-in unwanted shared " \ - "objects. ") \ - \ diagnostic(bool, EnableInvokeDynamic, true, \ "support JSR 292 (method handles, invokedynamic, " \ "anonymous classes") \ diff --git a/hotspot/src/share/vm/runtime/handles.cpp b/hotspot/src/share/vm/runtime/handles.cpp index 0ba6c984ef8..cb53088ee69 100644 --- a/hotspot/src/share/vm/runtime/handles.cpp +++ b/hotspot/src/share/vm/runtime/handles.cpp @@ -48,7 +48,7 @@ oop* HandleArea::allocate_handle(oop obj) { assert(_handle_mark_nesting > 1, "memory leak: allocating handle outside HandleMark"); assert(_no_handle_mark_nesting == 0, "allocating handle inside NoHandleMark"); - assert(SharedSkipVerify || obj->is_oop(), "sanity check"); + assert(obj->is_oop(), "sanity check"); return real_allocate_handle(obj); } diff --git a/hotspot/src/share/vm/runtime/handles.hpp b/hotspot/src/share/vm/runtime/handles.hpp index 4a2e9ff8252..cab3dc581f9 100644 --- a/hotspot/src/share/vm/runtime/handles.hpp +++ b/hotspot/src/share/vm/runtime/handles.hpp @@ -110,11 +110,11 @@ class Handle VALUE_OBJ_CLASS_SPEC { /* Constructors */ \ type##Handle () : Handle() {} \ type##Handle (type##Oop obj) : Handle((oop)obj) { \ - assert(SharedSkipVerify || is_null() || ((oop)obj)->is_a(), \ + assert(is_null() || ((oop)obj)->is_a(), \ "illegal type"); \ } \ type##Handle (Thread* thread, type##Oop obj) : Handle(thread, (oop)obj) { \ - assert(SharedSkipVerify || is_null() || ((oop)obj)->is_a(), "illegal type"); \ + assert(is_null() || ((oop)obj)->is_a(), "illegal type"); \ } \ \ /* Operators for ease of use */ \ @@ -201,11 +201,11 @@ class instanceKlassHandle : public KlassHandle { /* Constructors */ instanceKlassHandle () : KlassHandle() {} instanceKlassHandle (const Klass* k) : KlassHandle(k) { - assert(SharedSkipVerify || k == NULL || k->oop_is_instance(), + assert(k == NULL || k->oop_is_instance(), "illegal type"); } instanceKlassHandle (Thread* thread, const Klass* k) : KlassHandle(thread, k) { - assert(SharedSkipVerify || k == NULL || k->oop_is_instance(), + assert(k == NULL || k->oop_is_instance(), "illegal type"); } /* Access to klass part */ diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 6c46e129835..0ed9a4b1fee 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -177,7 +177,8 @@ void* Thread::allocate(size_t size, bool throw_excpt, MEMFLAGS flags) { const int alignment = markOopDesc::biased_lock_alignment; size_t aligned_size = size + (alignment - sizeof(intptr_t)); void* real_malloc_addr = throw_excpt? AllocateHeap(aligned_size, flags, CURRENT_PC) - : os::malloc(aligned_size, flags, CURRENT_PC); + : AllocateHeap(aligned_size, flags, CURRENT_PC, + AllocFailStrategy::RETURN_NULL); void* aligned_addr = (void*) align_size_up((intptr_t) real_malloc_addr, alignment); assert(((uintptr_t) aligned_addr + (uintptr_t) size) <= ((uintptr_t) real_malloc_addr + (uintptr_t) aligned_size), @@ -191,7 +192,7 @@ void* Thread::allocate(size_t size, bool throw_excpt, MEMFLAGS flags) { return aligned_addr; } else { return throw_excpt? AllocateHeap(size, flags, CURRENT_PC) - : os::malloc(size, flags, CURRENT_PC); + : AllocateHeap(size, flags, CURRENT_PC, AllocFailStrategy::RETURN_NULL); } } diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index ec2f7852fe0..ed747fb6cdd 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -110,7 +110,7 @@ class Thread: public ThreadShadow { void* _real_malloc_address; public: void* operator new(size_t size) { return allocate(size, true); } - void* operator new(size_t size, std::nothrow_t& nothrow_constant) { return allocate(size, false); } + void* operator new(size_t size, const std::nothrow_t& nothrow_constant) { return allocate(size, false); } void operator delete(void* p); protected: diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp index 76164058e01..51d59c44532 100644 --- a/hotspot/src/share/vm/utilities/debug.cpp +++ b/hotspot/src/share/vm/utilities/debug.cpp @@ -477,7 +477,7 @@ extern "C" void verify() { } // Ensure Eden top is correct before verification Universe::heap()->prepare_for_verify(); - Universe::verify(true); + Universe::verify(); if (!safe) SafepointSynchronize::set_is_not_at_safepoint(); } diff --git a/hotspot/test/runtime/6929067/Test6929067.sh b/hotspot/test/runtime/6929067/Test6929067.sh index c08aa6b8f09..e4b649df82b 100644 --- a/hotspot/test/runtime/6929067/Test6929067.sh +++ b/hotspot/test/runtime/6929067/Test6929067.sh @@ -4,6 +4,7 @@ ## @test Test6929067.sh ## @bug 6929067 ## @summary Stack guard pages should be removed when thread is detached +## @compile T.java ## @run shell Test6929067.sh ## @@ -33,31 +34,97 @@ case "$OS" in ;; esac -# Choose arch: i386 or amd64 (test is Linux-specific) +${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Xinternalversion > vm_version.out 2>&1 + +# Bitness: # Cannot simply look at TESTVMOPTS as -d64 is not # passed if there is only a 64-bit JVM available. -${TESTJAVA}/bin/java ${TESTVMOPTS} -version 2>1 | grep "64-Bit" >/dev/null +grep "64-Bit" vm_version.out > ${NULL} if [ "$?" = "0" ] then - ARCH=amd64 + COMP_FLAG="-m64" else - ARCH=i386 + COMP_FLAG="-m32" fi -LD_LIBRARY_PATH=.:${TESTJAVA}/jre/lib/${ARCH}/client:/usr/openwin/lib:/usr/dt/lib:/usr/lib:$LD_LIBRARY_PATH + +# Architecture: +# Translate uname output to JVM directory name, but permit testing +# 32-bit x86 on an x64 platform. +ARCH=`uname -m` +case "$ARCH" in + x86_64) + if [ "$COMP_FLAG" = "-m32" ]; then + ARCH=i386 + else + ARCH=amd64 + fi + ;; + ppc64) + if [ "$COMP_FLAG" = "-m32" ]; then + ARCH=ppc + else + ARCH=ppc64 + fi + ;; + sparc64) + if [ "$COMP_FLAG" = "-m32" ]; then + ARCH=sparc + else + ARCH=sparc64 + fi + ;; + arm*) + # 32-bit ARM machine: compiler may not recognise -m32 + COMP_FLAG="" + ARCH=arm + ;; + aarch64) + # 64-bit arm machine, could be testing 32 or 64-bit: + if [ "$COMP_FLAG" = "-m32" ]; then + ARCH=arm + else + ARCH=aarch64 + fi + ;; + i586) + ARCH=i386 + ;; + i686) + ARCH=i386 + ;; + # Assuming other ARCH values need no translation +esac + + +# VM type: need to know server or client +VMTYPE=client +grep Server vm_version.out > ${NULL} +if [ "$?" = "0" ] +then + VMTYPE=server +fi + + +LD_LIBRARY_PATH=.:${TESTJAVA}/jre/lib/${ARCH}/${VMTYPE}:/usr/lib:$LD_LIBRARY_PATH export LD_LIBRARY_PATH -THIS_DIR=`pwd` - -cp ${TESTSRC}${FS}invoke.c ${THIS_DIR} -cp ${TESTSRC}${FS}T.java ${THIS_DIR} +cp ${TESTSRC}${FS}invoke.c . +# Copy the result of our @compile action: +cp ${TESTCLASSES}${FS}T.class . ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -fullversion -${TESTJAVA}${FS}bin${FS}javac T.java +echo "Architecture: ${ARCH}" +echo "Compilation flag: ${COMP_FLAG}" +echo "VM type: ${VMTYPE}" + +gcc -DLINUX ${COMP_FLAG} -o invoke \ + -I${TESTJAVA}/include -I${TESTJAVA}/include/linux \ + -L${TESTJAVA}/jre/lib/${ARCH}/${VMTYPE} \ + -ljvm -lpthread invoke.c -gcc -o invoke -I${TESTJAVA}/include -I${TESTJAVA}/include/linux invoke.c ${TESTJAVA}/jre/lib/${ARCH}/client/libjvm.so ./invoke exit $? diff --git a/jaxp/.hgtags b/jaxp/.hgtags index c07ba52711e..5c329132e45 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -182,3 +182,4 @@ f19d63b2119a0092f016203981ffef5cc31bc3c5 jdk8-b56 1cb19abb3f7b40bf233b349cd2f51f02d37a9f5b jdk8-b58 af9e8b0f1900b631a8a0fcccff9f1514fe58c808 jdk8-b59 2d1dff5310daaf226421a8c92823cb8afcf35f31 jdk8-b60 +6b1db0b41d2f6e2a7b3bdbc8a8db823b47752906 jdk8-b61 diff --git a/jaxws/.hgtags b/jaxws/.hgtags index f0a4da5c4ba..7d6a6df637a 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -182,3 +182,4 @@ b51b611209f159f94dd2ce3dc2c56daa6d6ac1df jdk8-b57 cac4c393706343df778a13dc6c84cad0f8c237c9 jdk8-b58 ae107401be116f9e384d3a23192f543828e03da5 jdk8-b59 5c5a65ad5291b7cefcdc308f627cf2b195cf2b69 jdk8-b60 +97e5e74e2a341d9142ce28043912a3c255e28e03 jdk8-b61 diff --git a/jdk/.hgtags b/jdk/.hgtags index 804a1e63a0c..de1a543ff2e 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -182,3 +182,5 @@ e8569a473cee7f4955bd9e76a9bdf6c6a07ced27 jdk8-b52 d94613ac03d8de375ef60493e2bb76dbd30d875d jdk8-b58 abad1f417bd3df4296631fc943cd3b7f5062c88a jdk8-b59 cec8fa02f15634acd7d02d04b0b2d8c044cdbaaa jdk8-b60 +61ddb3fd000a09ab05bff1940b0ac211661e94cf jdk8-b61 +50b8b17449d200c66bfd68fb4f3a9197432c9e2b jdk8-b62 diff --git a/jdk/THIRD_PARTY_README b/jdk/THIRD_PARTY_README index 759733bfceb..6dc1b331638 100644 --- a/jdk/THIRD_PARTY_README +++ b/jdk/THIRD_PARTY_README @@ -2,11 +2,11 @@ DO NOT TRANSLATE OR LOCALIZE. ----------------------------- %% This notice is provided with respect to ASM Bytecode Manipulation -Framework v3.1, which is included with JRE 7, JDK 7, and OpenJDK 7. +Framework v4.0, which is included with JRE 8, and JDK 8. --- begin of LICENSE --- -Copyright (c) 2000-2005 INRIA, France Telecom +Copyright (c) 2000-2011 France Télécom All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/jdk/make/Makefile b/jdk/make/Makefile index 2e5032d0f15..ceb1492bb4e 100644 --- a/jdk/make/Makefile +++ b/jdk/make/Makefile @@ -233,7 +233,7 @@ import_product: all build:: sanity-all post-sanity-all -SUBDIRS = tools java javax sun com +SUBDIRS = tools java javax sun com jdk ifeq ($(PLATFORM), macosx) SUBDIRS += apple endif diff --git a/jdk/make/com/sun/java/pack/Makefile b/jdk/make/com/sun/java/pack/Makefile index 5882683fe04..e8c256d3e9b 100644 --- a/jdk/make/com/sun/java/pack/Makefile +++ b/jdk/make/com/sun/java/pack/Makefile @@ -94,9 +94,9 @@ ifeq ($(PLATFORM), windows) LDOUTPUT = -Fe # JDK name required here - RC_FLAGS += /D "JDK_FNAME=$(PGRM).exe" \ - /D "JDK_INTERNAL_NAME=$(PGRM)" \ - /D "JDK_FTYPE=0x1L" + RC_FLAGS += -D "JDK_FNAME=$(PGRM).exe" \ + -D "JDK_INTERNAL_NAME=$(PGRM)" \ + -D "JDK_FTYPE=0x1L" RES = $(OBJDIR)/$(PGRM).res else @@ -161,7 +161,7 @@ $(UNPACK_EXE): $(UNPACK_EXE_FILES_o) updatefiles winres $(CP) mapfile-vers-unpack200 $(TEMPDIR)/mapfile-vers $(LINKER) $(LDDFLAGS) $(sort $(UNPACK_EXE_FILES_o)) $(RES) $(LIBCXX) $(LDOUTPUT)$(TEMPDIR)/unpack200$(EXE_SUFFIX) ifdef MT - $(MT) /manifest $(OBJDIR)/unpack200$(EXE_SUFFIX).manifest /outputresource:$(TEMPDIR)/unpack200$(EXE_SUFFIX);#1 + $(MT) -manifest $(OBJDIR)/unpack200$(EXE_SUFFIX).manifest -outputresource:$(TEMPDIR)/unpack200$(EXE_SUFFIX);#1 endif $(CP) $(TEMPDIR)/unpack200$(EXE_SUFFIX) $(UNPACK_EXE) @$(call binary_file_verification,$@) diff --git a/jdk/make/common/Defs-windows.gmk b/jdk/make/common/Defs-windows.gmk index 7afe0b515e0..50a5a66c477 100644 --- a/jdk/make/common/Defs-windows.gmk +++ b/jdk/make/common/Defs-windows.gmk @@ -78,7 +78,7 @@ ifeq ($(COMPILER_VERSION), VS2010) MS_RUNTIME_LIBRARIES = $(MSVCRNN_DLL) endif -EXTRA_LFLAGS += /LIBPATH:$(DXSDK_LIB_PATH) +EXTRA_LFLAGS += -LIBPATH:$(DXSDK_LIB_PATH) # Full Debug Symbols has been enabled on Windows since JDK1.4.1. # The Full Debug Symbols (FDS) default for VARIANT == OPT builds is @@ -198,7 +198,7 @@ CC_OPT = $(CC_OPT/$(OPTIMIZATION_LEVEL)) # -MTd Use static debug version (better than -MDd, no runtime issues) # -D_DEBUG Change use of malloc/free/etc to use special debug ones (-MTd) # -# NOTE: We also will use /D _STATIC_CPPLIB so we don't need msvcpnn.dll +# NOTE: We also will use -D _STATIC_CPPLIB so we don't need msvcpnn.dll # # If MS_RUNTIME_STATIC is requested we may have a problem, it is no longer # supported by VS2010 @@ -223,12 +223,12 @@ ifeq ($(MFC_DEBUG), true) endif # Always add _STATIC_CPPLIB definition -STATIC_CPPLIB_OPTION = /D _STATIC_CPPLIB +STATIC_CPPLIB_OPTION = -D _STATIC_CPPLIB # Silence the warning about using _STATIC_CPPLIB ifneq ($(SHOW_ALL_WARNINGS),true) # Needed with VS2010 to turn off the deprecated warning. - STATIC_CPPLIB_OPTION += /D _DISABLE_DEPRECATE_STATIC_CPPLIB + STATIC_CPPLIB_OPTION += -D _DISABLE_DEPRECATE_STATIC_CPPLIB endif MS_RUNTIME_OPTION += $(STATIC_CPPLIB_OPTION) @@ -242,7 +242,7 @@ ifeq ($(CC_VERSION),msvc) # -Od Turns off optimization and speeds compilation # -YX -Fp/.../foobar.pch Use precompiled headers (try someday?) # -nologo Don't print out startup message - # /D _STATIC_CPPLIB + # -D _STATIC_CPPLIB # Use static link for the C++ runtime (so msvcpnn.dll not needed) # ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) @@ -258,12 +258,12 @@ ifeq ($(CC_VERSION),msvc) CFLAGS_COMMON += $(MS_RUNTIME_OPTION) $(CFLAGS_$(COMPILER_VERSION)) ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - LDEBUG = /debug + LDEBUG = -debug endif ifeq ($(VTUNE_SUPPORT), true) OTHER_CFLAGS = -Z7 -Ox - LDEBUG += /pdb:NONE + LDEBUG += -pdb:NONE endif # VS2010, always need safe exception handlers, not needed on 64bit @@ -272,7 +272,7 @@ ifeq ($(CC_VERSION),msvc) endif # LFLAGS are the flags given to $(LINK) and used to build the actual DLL file - BASELFLAGS = -nologo /opt:REF /incremental:no + BASELFLAGS = -nologo -opt:REF -incremental:no LFLAGS = $(BASELFLAGS) $(LDEBUG) $(EXTRA_LFLAGS) $(LFLAGS_$(COMPILER_VERSION)) LDDFLAGS += $(LFLAGS_$(COMPILER_VERSION)) @@ -404,7 +404,7 @@ else JDK_UPDATE_VER := 0 endif -RC_FLAGS = /l 0x409 /r +RC_FLAGS = -l 0x409 -r ifeq ($(VARIANT), OPT) RC_FLAGS += -d NDEBUG diff --git a/jdk/make/common/Demo.gmk b/jdk/make/common/Demo.gmk index 3aba9a62c07..9163cf76513 100644 --- a/jdk/make/common/Demo.gmk +++ b/jdk/make/common/Demo.gmk @@ -292,9 +292,9 @@ endif ifeq ($(PLATFORM),windows) # JDK name required here -RC_FLAGS += /D "JDK_FNAME=$(LIBRARY).dll" \ - /D "JDK_INTERNAL_NAME=$(LIBRARY)" \ - /D "JDK_FTYPE=0x2L" +RC_FLAGS += -D "JDK_FNAME=$(LIBRARY).dll" \ + -D "JDK_INTERNAL_NAME=$(LIBRARY)" \ + -D "JDK_FTYPE=0x2L" endif # Native library building diff --git a/jdk/make/common/Library.gmk b/jdk/make/common/Library.gmk index b04095c93e2..4b080304d1f 100644 --- a/jdk/make/common/Library.gmk +++ b/jdk/make/common/Library.gmk @@ -206,9 +206,9 @@ endif @$(ECHO) Created $@ # JDK name required here -RC_FLAGS += /D "JDK_FNAME=$(LIBRARY).dll" \ - /D "JDK_INTERNAL_NAME=$(LIBRARY)" \ - /D "JDK_FTYPE=0x2L" +RC_FLAGS += -D "JDK_FNAME=$(LIBRARY).dll" \ + -D "JDK_INTERNAL_NAME=$(LIBRARY)" \ + -D "JDK_FTYPE=0x2L" $(OBJDIR)/$(LIBRARY).res: $(VERSIONINFO_RESOURCE) ifndef LOCAL_RESOURCE_FILE diff --git a/jdk/make/common/Program.gmk b/jdk/make/common/Program.gmk index 094d18ff997..b319ee41889 100644 --- a/jdk/make/common/Program.gmk +++ b/jdk/make/common/Program.gmk @@ -157,9 +157,9 @@ $(ACTUAL_PROGRAM):: classes $(INIT) # ifeq ($(PLATFORM), windows) # JDK name required here - RC_FLAGS += /D "JDK_FNAME=$(PROGRAM)$(EXE_SUFFIX)" \ - /D "JDK_INTERNAL_NAME=$(PROGRAM)" \ - /D "JDK_FTYPE=0x1L" + RC_FLAGS += -D "JDK_FNAME=$(PROGRAM)$(EXE_SUFFIX)" \ + -D "JDK_INTERNAL_NAME=$(PROGRAM)" \ + -D "JDK_FTYPE=0x1L" $(OBJDIR)/$(PROGRAM).res: $(VERSIONINFO_RESOURCE) @$(prep-target) @@ -201,11 +201,11 @@ endif @$(prep-target) @set -- $?; \ $(ECHO) Rebuilding $@ because of $$1 $$2 $$3 $$4 $$5 $$6 $${7:+...}; - $(LINK) -out:$@ /STACK:$(STACK_SIZE) \ + $(LINK) -out:$@ -STACK:$(STACK_SIZE) \ $(MAP_OPTION) $(LFLAGS) $(LDFLAGS) \ @$(OBJDIR)/$(PROGRAM).lcf $(LDLIBS) ifdef MT - $(MT) /manifest $(OBJDIR)/$(PROGRAM).exe.manifest /outputresource:$@;#1 + $(MT) -manifest $(OBJDIR)/$(PROGRAM).exe.manifest /outputresource:$@;#1 endif @$(call binary_file_verification,$@) ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) diff --git a/jdk/make/common/Release.gmk b/jdk/make/common/Release.gmk index 7d04d3e14e2..15aa7c96c6c 100644 --- a/jdk/make/common/Release.gmk +++ b/jdk/make/common/Release.gmk @@ -348,15 +348,15 @@ TOOLS = \ sun/tools/serialver \ sun/tools/tree \ sun/tools/util \ - sun/security/tools/JarBASE64Encoder.class \ - sun/security/tools/JarSigner.class \ - sun/security/tools/JarSignerParameters.class \ - sun/security/tools/JarSignerResources.class \ - sun/security/tools/JarSignerResources_ja.class \ - sun/security/tools/JarSignerResources_zh_CN.class \ - sun/security/tools/SignatureFile\$$Block.class \ - sun/security/tools/SignatureFile.class \ - sun/security/tools/TimestampedSigner.class \ + sun/security/tools/jarsigner/JarBASE64Encoder.class \ + sun/security/tools/jarsigner/Main.class \ + sun/security/tools/jarsigner/JarSignerParameters.class \ + sun/security/tools/jarsigner/Resources.class \ + sun/security/tools/jarsigner/Resources_ja.class \ + sun/security/tools/jarsigner/Resources_zh_CN.class \ + sun/security/tools/jarsigner/SignatureFile\$$Block.class \ + sun/security/tools/jarsigner/SignatureFile.class \ + sun/security/tools/jarsigner/TimestampedSigner.class \ sun/rmi/rmic \ sun/applet \ sun/jvmstat \ @@ -572,15 +572,15 @@ $(NOT_RT_JAR_LIST): FRC $(ECHO) "sun/tools/serialver/" >> $@ $(ECHO) "sun/tools/tree/" >> $@ $(ECHO) "sun/tools/util/" >> $@ - $(ECHO) "sun/security/tools/JarBASE64Encoder.class" >> $@ - $(ECHO) "sun/security/tools/JarSigner.class" >> $@ - $(ECHO) "sun/security/tools/JarSignerParameters.class" >> $@ - $(ECHO) "sun/security/tools/JarSignerResources.class" >> $@ - $(ECHO) "sun/security/tools/JarSignerResources_ja.class" >> $@ - $(ECHO) "sun/security/tools/JarSignerResources_zh_CN.class" >> $@ - $(ECHO) "sun/security/tools/SignatureFile\$$Block.class" >> $@ - $(ECHO) "sun/security/tools/SignatureFile.class" >> $@ - $(ECHO) "sun/security/tools/TimestampedSigner.class" >> $@ + $(ECHO) "sun/security/tools/jarsigner/JarBASE64Encoder.class" >> $@ + $(ECHO) "sun/security/tools/jarsigner/Main.class" >> $@ + $(ECHO) "sun/security/tools/jarsigner/JarSignerParameters.class" >> $@ + $(ECHO) "sun/security/tools/jarsigner/Resources.class" >> $@ + $(ECHO) "sun/security/tools/jarsigner/Resources_ja.class" >> $@ + $(ECHO) "sun/security/tools/jarsigner/Resources_zh_CN.class" >> $@ + $(ECHO) "sun/security/tools/jarsigner/SignatureFile\$$Block.class" >> $@ + $(ECHO) "sun/security/tools/jarsigner/SignatureFile.class" >> $@ + $(ECHO) "sun/security/tools/jarsigner/TimestampedSigner.class" >> $@ $(ECHO) "sun/security/provider/Sun.class" >> $@ $(ECHO) "sun/security/rsa/SunRsaSign.class" >> $@ $(ECHO) "sun/security/ssl/" >> $@ @@ -784,11 +784,22 @@ initial-image-jre:: initial-image-jre-setup \ $(RT_JAR) $(RESOURCES_JAR) $(JSSE_JAR) $(JFR_JAR) \ $(BUILDMETAINDEX_JARFILE) @# Copy in bin directory +ifeq ($(USING_MSYS),true) + # No cpio in MinGW/MSYS + $(CD) $(OUTPUTDIR) && $(TAR) -cf - bin | ($(CD) $(JRE_IMAGE_DIR) && $(TAR) -xpf -) +else $(CD) $(OUTPUTDIR) && $(FIND) bin -depth | $(CPIO) -pdum $(JRE_IMAGE_DIR) +endif @# CTE plugin security change require new empty directory lib/applet $(MKDIR) -p $(JRE_IMAGE_DIR)/lib/applet @# Copy in lib directory +ifeq ($(USING_MSYS),true) + # No cpio in MinGW/MSYS + $(CD) $(OUTPUTDIR) && $(TAR) -cf - lib | ($(CD) $(JRE_IMAGE_DIR) && $(TAR) -xpf -) +else $(CD) $(OUTPUTDIR) && $(FIND) lib -depth | $(CPIO) -pdum $(JRE_IMAGE_DIR) +endif + ifeq ($(USING_CYGWIN),true) $(RM) -rf $(JRE_IMAGE_DIR)/[A-Za-z]: $(RM) -rf $(OUTPUTDIR)/[A-Za-z]: @@ -919,11 +930,17 @@ endif # only places from which we copy everything), but because the presence # of this file causes cygwin's find to bomb out, thus breaking the build # in "install". + initial-image-jdk-setup: $(RM) -r $(JDK_IMAGE_DIR) $(MKDIR) -p $(JDK_IMAGE_DIR)/jre +ifeq ($(USING_MSYS),true) + ($(CD) $(JRE_IMAGE_DIR) && $(TAR) -cf - . \ + | ($(CD) $(JDK_IMAGE_DIR)/jre && $(TAR) -xpf -)) +else ($(CD) $(JRE_IMAGE_DIR) && $(FIND) . -depth -print \ | $(CPIO) -pdum $(JDK_IMAGE_DIR)/jre ) +endif ifeq ($(USING_CYGWIN),true) $(RM) -rf $(JRE_IMAGE_DIR)/[A-Za-z]: $(RM) -rf $(JDK_IMAGE_DIR)/jre/[A-Za-z]: diff --git a/jdk/make/common/internal/Defs-jaxws.gmk b/jdk/make/common/internal/Defs-jaxws.gmk index f0ba12b292a..2cee63a8ac8 100644 --- a/jdk/make/common/internal/Defs-jaxws.gmk +++ b/jdk/make/common/internal/Defs-jaxws.gmk @@ -34,6 +34,10 @@ IMPORT_RT_PACKAGES += \ javax/xml/ws \ javax/jws \ javax/annotation \ + com/sun/org/glassfish \ + com/sun/istack/internal \ + com/sun/istack/internal/localization \ + com/sun/istack/internal/logging \ com/sun/xml/internal/bind \ com/sun/xml/internal/fastinfoset \ com/sun/xml/internal/messaging \ diff --git a/jdk/make/common/shared/Defs-utils.gmk b/jdk/make/common/shared/Defs-utils.gmk index 9bc05d6f69b..573f7ccaa80 100644 --- a/jdk/make/common/shared/Defs-utils.gmk +++ b/jdk/make/common/shared/Defs-utils.gmk @@ -169,15 +169,19 @@ CD = cd # intrinsic unix command ifeq ($(PLATFORM),windows) ifdef USING_CYGWIN # Intrinsic unix command, with backslash-escaped character interpretation - ECHO = $(UNIXCOMMAND_PATH)echo -e - ZIPEXE = $(UNIXCOMMAND_PATH)zip - UNZIP = $(UNIXCOMMAND_PATH)unzip + ECHO = $(UNIXCOMMAND_PATH)echo -e + ZIPEXE = $(UNIXCOMMAND_PATH)zip + UNZIP = $(UNIXCOMMAND_PATH)unzip # Some CYGWIN nawk versions require BINMODE=w for proper '\r' interpretation - NAWK = $(UNIXCOMMAND_PATH)awk -v BINMODE=w + NAWK = $(UNIXCOMMAND_PATH)awk -v BINMODE=w else ZIPEXE = $(UTILS_DEVTOOL_PATH)zip UNZIP = $(UTILS_DEVTOOL_PATH)unzip NAWK = $(UNIXCOMMAND_PATH)awk + ifdef USING_MSYS + ECHO = $(UTILS_COMMAND_PATH)echo -e + AR = $(UTILS_DEVTOOL_PATH)ar + endif endif # Re-define some utilities LEX =# override GNU Make intrinsic: no lex on windows diff --git a/jdk/make/common/shared/Defs-windows.gmk b/jdk/make/common/shared/Defs-windows.gmk index af611f3aab2..c4ccdbca4ea 100644 --- a/jdk/make/common/shared/Defs-windows.gmk +++ b/jdk/make/common/shared/Defs-windows.gmk @@ -112,6 +112,15 @@ define OptFullPath $(shell if [ "$1" != "" -a -d "$1" ]; then $(CYGPATH_CMD) "$1" 2> $(DEV_NULL); else echo "$1"; fi) endef else +ifdef USING_MSYS +DOSPATH_CMD:=$(shell cd $(JDK_TOPDIR) 2> $(DEV_NULL) && pwd)/make/tools/msys_build_scripts/dospath.sh +define FullPath +$(subst \,/,$(shell $(DOSPATH_CMD) $1)) +endef +define OptFullPath +$(shell if [ "$1" != "" -a -d "$1" ]; then (cd $1 && pwd); else echo "$1"; fi) +endef +else # Temporary until we upgrade to MKS 8.7, MKS pwd returns mixed mode path define FullPath $(shell cd $1 2> $(DEV_NULL) && pwd) @@ -120,6 +129,7 @@ define OptFullPath $(shell if [ "$1" != "" -a -d "$1" ]; then (cd $1 && pwd); else echo "$1"; fi) endef endif +endif # System drive ifdef SYSTEMDRIVE @@ -146,43 +156,47 @@ else ifdef USING_CYGWIN UNIXCOMMAND_PATH :=$(call PrefixPath,/usr/bin) else - ifdef ROOTDIR - xROOTDIR :="$(subst \,/,$(ROOTDIR))" - _rootdir :=$(call FullPath,$(xROOTDIR)) + ifdef USING_MSYS + UNIXCOMMAND_PATH :=$(call PrefixPath,/bin) else - xROOTDIR :="$(_system_drive)/mksnt" - _rootdir :=$(call FullPath,$(xROOTDIR)) - endif - ifneq ($(_rootdir),) - UNIXCOMMAND_PATH :=$(call PrefixPath,$(_rootdir)/mksnt) - endif - endif + ifdef ROOTDIR + xROOTDIR :="$(subst \,/,$(ROOTDIR))" + _rootdir :=$(call FullPath,$(xROOTDIR)) + else + xROOTDIR :="$(_system_drive)/mksnt" + _rootdir :=$(call FullPath,$(xROOTDIR)) + endif + ifneq ($(_rootdir),) + UNIXCOMMAND_PATH :=$(call PrefixPath,$(_rootdir)/mksnt) + endif + endif # USING_MSYS + endif # USING_CYGWIN endif UNIXCOMMAND_PATH:=$(call AltCheckSpaces,UNIXCOMMAND_PATH) # Get version of MKS or CYGWIN -ifndef USING_CYGWIN -_MKS_VER :=$(shell $(MKSINFO) 2>&1 | $(GREP) Release | $(TAIL) -1 | $(SED) -e 's@.*\(Release.*\)@\1@') -MKS_VER :=$(call GetVersion,$(_MKS_VER)) -# At this point, we can re-define FullPath to use DOSNAME_CMD -CHECK_MKS87:=$(call CheckVersions,$(MKS_VER),8.7) -TRY_DOSNAME:=false -ifeq ($(CHECK_MKS87),same) -TRY_DOSNAME:=true -endif -# Newer should be ok -ifeq ($(CHECK_MKS87),newer) -TRY_DOSNAME:=true -endif -ifeq ($(TRY_DOSNAME),true) -ifeq ($(shell $(UNIXCOMMAND_PATH)dosname -s $(_system_drive)/ 2> $(DEV_NULL)),$(_system_drive)/) -_DOSNAME=$(UNIXCOMMAND_PATH)dosname -DOSNAME_CMD:=$(_DOSNAME) -s +ifdef USING_MKS + _MKS_VER :=$(shell $(MKSINFO) 2>&1 | $(GREP) Release | $(TAIL) -1 | $(SED) -e 's@.*\(Release.*\)@\1@') + MKS_VER :=$(call GetVersion,$(_MKS_VER)) + # At this point, we can re-define FullPath to use DOSNAME_CMD + CHECK_MKS87:=$(call CheckVersions,$(MKS_VER),8.7) + TRY_DOSNAME:=false + ifeq ($(CHECK_MKS87),same) + TRY_DOSNAME:=true + endif + # Newer should be ok + ifeq ($(CHECK_MKS87),newer) + TRY_DOSNAME:=true + endif + ifeq ($(TRY_DOSNAME),true) + ifeq ($(shell $(UNIXCOMMAND_PATH)dosname -s $(_system_drive)/ 2> $(DEV_NULL)),$(_system_drive)/) + _DOSNAME=$(UNIXCOMMAND_PATH)dosname + DOSNAME_CMD:=$(_DOSNAME) -s define FullPath $(subst //,/,$(shell echo $1 | $(DOSNAME_CMD) 2> $(DEV_NULL))) endef -endif # test dosname -s -endif # TRY_DOSNAME + endif # test dosname -s + endif # TRY_DOSNAME endif # MKS # We try to get references to what we need via the default component @@ -440,10 +454,14 @@ else ifdef USING_CYGWIN DEVTOOLS_PATH :=$(UNIXCOMMAND_PATH) else - xDEVTOOLS_PATH :="$(_system_drive)/utils" - fxDEVTOOLS_PATH :=$(call FullPath,$(xDEVTOOLS_PATH)) - DEVTOOLS_PATH :=$(call PrefixPath,$(fxDEVTOOLS_PATH)) - endif + ifdef USING_MSYS + DEVTOOLS_PATH :=$(UNIXCOMMAND_PATH) + else + xDEVTOOLS_PATH :="$(_system_drive)/utils" + fxDEVTOOLS_PATH :=$(call FullPath,$(xDEVTOOLS_PATH)) + DEVTOOLS_PATH :=$(call PrefixPath,$(fxDEVTOOLS_PATH)) + endif # USING_MSYS + endif # USING_CYGWIN endif DEVTOOLS_PATH:=$(call AltCheckSpaces,DEVTOOLS_PATH) @@ -636,7 +654,7 @@ HOTSPOT_LIB_PATH:=$(call AltCheckValue,HOTSPOT_LIB_PATH) # Special define for checking the binaries -# All windows dll and exe files should have been built with /NXCOMPAT +# All windows dll and exe files should have been built with -NXCOMPAT # and be setup for dynamic base addresses. # In addition, we should not be dependent on certain dll files that # we do not or cannot redistribute. @@ -648,37 +666,37 @@ else BANNED_DLLS=msvcp100[.]dll|msvcr100d[.]dll|msvcrtd[.]dll endif -# Check for /safeseh (only used on 32bit) +# Check for -safeseh (only used on 32bit) define binary_file_safeseh_verification # binary_file ( \ - $(ECHO) "Checking for /SAFESEH usage in: $1" && \ - if [ "`$(DUMPBIN) /loadconfig $1 | $(EGREP) -i 'Safe Exception Handler Table'`" = "" ] ; then \ + $(ECHO) "Checking for -SAFESEH usage in: $1" && \ + if [ "`$(DUMPBIN) -loadconfig $1 | $(EGREP) -i 'Safe Exception Handler Table'`" = "" ] ; then \ $(ECHO) "ERROR: Did not find 'Safe Exception Handler Table' in loadconfig: $1" ; \ - $(DUMPBIN) /loadconfig $1 ; \ + $(DUMPBIN) -loadconfig $1 ; \ exit 6 ; \ fi ; \ ) endef -# Check for /NXCOMPAT usage +# Check for -NXCOMPAT usage define binary_file_nxcompat_verification # binary_file ( \ - $(ECHO) "Checking for /NXCOMPAT usage in: $1" && \ - if [ "`$(DUMPBIN) /headers $1 | $(EGREP) -i 'NX compatible'`" = "" ] ; then \ + $(ECHO) "Checking for -NXCOMPAT usage in: $1" && \ + if [ "`$(DUMPBIN) -headers $1 | $(EGREP) -i 'NX compatible'`" = "" ] ; then \ $(ECHO) "ERROR: Did not find 'NX compatible' in headers: $1" ; \ - $(DUMPBIN) /headers $1 ; \ + $(DUMPBIN) -headers $1 ; \ exit 7 ; \ fi ; \ ) endef -# Check for /DYNAMICBASE usage +# Check for -DYNAMICBASE usage define binary_file_dynamicbase_verification # binary_file ( \ - $(ECHO) "Checking for /DYNAMICBASE usage in: $1" && \ - if [ "`$(DUMPBIN) /headers $1 | $(EGREP) -i 'Dynamic base'`" = "" ] ; then \ + $(ECHO) "Checking for -DYNAMICBASE usage in: $1" && \ + if [ "`$(DUMPBIN) -headers $1 | $(EGREP) -i 'Dynamic base'`" = "" ] ; then \ $(ECHO) "ERROR: Did not find 'Dynamic base' in headers: $1" ; \ - $(DUMPBIN) /headers $1 ; \ + $(DUMPBIN) -headers $1 ; \ exit 8 ; \ fi ; \ ) @@ -688,9 +706,9 @@ endef define binary_file_dll_verification # binary_file ( \ $(ECHO) "Checking for banned dependencies in: $1" && \ - if [ "`$(DUMPBIN) /dependents $1 | $(EGREP) -i '$(BANNED_DLLS)'`" != "" ] ; then \ + if [ "`$(DUMPBIN) -dependents $1 | $(EGREP) -i '$(BANNED_DLLS)'`" != "" ] ; then \ $(ECHO) "ERROR: Found use of $(BANNED_DLLS)"; \ - $(DUMPBIN) /dependents $1 ; \ + $(DUMPBIN) -dependents $1 ; \ exit 9 ; \ fi ; \ ) diff --git a/jdk/make/common/shared/Platform.gmk b/jdk/make/common/shared/Platform.gmk index 49e6cbda78e..aeaeabe42f6 100644 --- a/jdk/make/common/shared/Platform.gmk +++ b/jdk/make/common/shared/Platform.gmk @@ -70,6 +70,8 @@ PLATFORM_SHARED=done # LIBARCH32 solaris only: sparc or i386 # LIBARCH64 solaris only: sparcv9 or amd64 # USING_CYGWIN windows only: true or false +# USING_MSYS windows only: true or false +# USING_MKS windows only: true or false # ISHIELD_TEMP_MIN windows only: minimum disk space in temp area # Only run uname once in this make session. @@ -306,6 +308,8 @@ endif # Windows with and without CYGWIN will be slightly different ifeq ($(SYSTEM_UNAME), Windows_NT) PLATFORM = windows + USING_MKS = true + export USING_MKS endif ifneq (,$(findstring CYGWIN,$(SYSTEM_UNAME))) PLATFORM = windows @@ -318,6 +322,11 @@ ifneq (,$(findstring CYGWIN,$(SYSTEM_UNAME))) export CYGWIN_HOME endif endif +ifneq (,$(findstring MINGW,$(SYSTEM_UNAME))) + PLATFORM = windows + USING_MSYS = true + export USING_MSYS +endif # Platform settings specific to Windows ifeq ($(PLATFORM), windows) @@ -395,11 +404,12 @@ ifeq ($(PLATFORM), windows) endif ARCH_FAMILY = $(ARCH) # Where is unwanted output to be delivered? - # MKS uses the special file "NUL", cygwin uses the customary unix file. - ifeq ($(USING_CYGWIN),true) - DEV_NULL = /dev/null - else + # MKS uses the special file "NUL"; Cygwin and MinGW/MSYS use the + # customary unix file. + ifeq ($(USING_MKS),true) DEV_NULL = NUL + else + DEV_NULL = /dev/null endif export DEV_NULL # Classpath separator @@ -440,28 +450,11 @@ ifeq ($(PLATFORM), windows) _MB_OF_MEMORY := \ $(shell free -m | grep Mem: | awk '{print $$2;}' ) else - # Windows 2000 has the mem utility, but two memory areas - # extended memory is what is beyond 1024M - _B_OF_EXT_MEMORY := \ - $(shell mem 2> $(DEV_NULL) | \ - grep 'total contiguous extended memory' | awk '{print $$1;}') - ifeq ($(_B_OF_EXT_MEMORY),) - _B_OF_MEMORY := \ - $(shell mem 2> $(DEV_NULL) | \ - grep 'total conventional memory' | awk '{print $$1;}') - else - _B_OF_MEMORY := \ - $(shell expr 1048576 '+' $(_B_OF_EXT_MEMORY) 2> $(DEV_NULL)) - endif - ifeq ($(_B_OF_MEMORY),) - # Windows 2003 has the systeminfo utility use it if mem doesn't work - _MB_OF_MEMORY := \ - $(shell systeminfo 2> $(DEV_NULL) | \ - grep 'Total Physical Memory:' | \ - awk '{print $$4;}' | sed -e 's@,@@') - else - _MB_OF_MEMORY := $(shell expr $(_B_OF_MEMORY) '/' 1024 2> $(DEV_NULL)) - endif + # Windows XP and higher has the systeminfo utility + _MB_OF_MEMORY := \ + $(shell systeminfo 2> $(DEV_NULL) | \ + grep 'Total Physical Memory:' | \ + awk '{print $$4;}' | sed -e 's@,@@') endif ifeq ($(shell expr $(_MB_OF_MEMORY) '+' 0 2> $(DEV_NULL)), $(_MB_OF_MEMORY)) MB_OF_MEMORY := $(_MB_OF_MEMORY) diff --git a/jdk/make/common/shared/Sanity-Settings.gmk b/jdk/make/common/shared/Sanity-Settings.gmk index e571b068f82..b6b0fdcf19d 100644 --- a/jdk/make/common/shared/Sanity-Settings.gmk +++ b/jdk/make/common/shared/Sanity-Settings.gmk @@ -182,8 +182,13 @@ ifeq ($(PLATFORM),windows) ALL_SETTINGS+=$(call addRequiredVersionSetting,CYGWIN_VER) ALL_SETTINGS+=$(call addRequiredSetting,CYGPATH_CMD) else - ALL_SETTINGS+=$(call addRequiredVersionSetting,MKS_VER) - ALL_SETTINGS+=$(call addOptionalSetting,DOSNAME_CMD) + ifdef USING_MSYS + ALL_SETTINGS+=$(call addRequiredSetting,USING_MSYS) + ALL_SETTINGS+=$(call addRequiredSetting,DOSPATH_CMD) + else + ALL_SETTINGS+=$(call addRequiredVersionSetting,MKS_VER) + ALL_SETTINGS+=$(call addOptionalSetting,DOSNAME_CMD) + endif endif endif ifeq ($(PLATFORM),linux) diff --git a/jdk/make/common/shared/Sanity.gmk b/jdk/make/common/shared/Sanity.gmk index b6c340cfe91..845418bcecc 100644 --- a/jdk/make/common/shared/Sanity.gmk +++ b/jdk/make/common/shared/Sanity.gmk @@ -395,7 +395,7 @@ endif ifeq ($(PLATFORM), windows) MKS_CHECK :=$(call CheckVersions,$(MKS_VER),$(REQUIRED_MKS_VER)) sane-mks: - ifndef USING_CYGWIN + ifdef USING_MKS ifeq ($(MKS_CHECK),missing) @$(call OfficialErrorMessage,MKS version,$(MKS_VER),$(REQUIRED_MKS_VER)) endif @@ -905,14 +905,25 @@ sane-unixcommand_path: "" >> $(ERROR_FILE) ; \ fi ifeq ($(PLATFORM), windows) - @for utility in cpio ar file m4 ; do \ +ifeq ($(USING_MSYS), true) + @for utility in $(AR) $(FILE) $(M4) ; do \ if [ ! -r "`$(WHICH) $${utility}`" ]; then \ $(ECHO) "WARNING: You do not have the utility $${utility} in the \n" \ " directory $(UNIXCOMMAND_PATH). \n" \ - " The utilities cpio, ar, file, and m4 are required. \n" \ + " The utilities ar, file and m4 are required. \n" \ "" >> $(WARNING_FILE) ; \ fi; \ done +else + @for utility in $(AR) $(CPIO) $(FILE) $(M4) ; do \ + if [ ! -r "`$(WHICH) $${utility}`" ]; then \ + $(ECHO) "WARNING: You do not have the utility $${utility} in the \n" \ + " directory $(UNIXCOMMAND_PATH). \n" \ + " The utilities ar, cpio, file and m4 are required. \n" \ + "" >> $(WARNING_FILE) ; \ + fi; \ + done +endif endif ###################################################### @@ -999,7 +1010,8 @@ ifeq ($(PLATFORM), windows) " This is normally obtained from the WINDOWSSDKDIR." \ "" >> $(ERROR_FILE) endif - ifeq ($(wildcard $(DUMPBIN)),) + # MinGW/MSYS make 3.81 will not tolerate a path with a quoted substring + ifeq ($(wildcard $(subst ",,$(DUMPBIN))),) @$(ECHO) "ERROR: Cannot find the DUMPBIN utility from path: $(DUMPBIN)\n" \ " This is normally obtained from the COMPILER_PATH." \ "" >> $(ERROR_FILE) diff --git a/jdk/make/java/java/Makefile b/jdk/make/java/java/Makefile index 6693a8224b7..b2d1c5ab091 100644 --- a/jdk/make/java/java/Makefile +++ b/jdk/make/java/java/Makefile @@ -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 @@ -64,13 +64,11 @@ include FILES_java.gmk include Exportedfiles.gmk ifeq ($(PLATFORM),windows) -FILES_java += java/io/Win32FileSystem.java \ - java/io/WinNTFileSystem.java \ +FILES_java += java/io/WinNTFileSystem.java \ java/util/prefs/WindowsPreferences.java \ java/util/prefs/WindowsPreferencesFactory.java FILES_c += ProcessImpl_md.c \ - Win32FileSystem_md.c \ WinNTFileSystem_md.c \ canonicalize_md.c \ dirent_md.c \ diff --git a/jdk/make/jdk/Makefile b/jdk/make/jdk/Makefile new file mode 100644 index 00000000000..b8ac7422749 --- /dev/null +++ b/jdk/make/jdk/Makefile @@ -0,0 +1,38 @@ +# +# 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 +# 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. +# + +# +# Makefile for building all of java +# + +BUILDDIR = .. +PRODUCT = jdk +include $(BUILDDIR)/common/Defs.gmk + +SUBDIRS = asm +include $(BUILDDIR)/common/Subdirs.gmk + +all build clean clobber:: + $(SUBDIRS-loop) diff --git a/jdk/make/jdk/asm/Makefile b/jdk/make/jdk/asm/Makefile new file mode 100644 index 00000000000..48b8f609644 --- /dev/null +++ b/jdk/make/jdk/asm/Makefile @@ -0,0 +1,40 @@ +# +# Copyright (c) 1995, 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. +# + +BUILDDIR = ../.. +PACKAGE = jdk.internal.org.objectweb.asm +PRODUCT = jdk +JAVAC_LINT_OPTIONS=-Xlint:all +include $(BUILDDIR)/common/Defs.gmk + +# +# Files to compile +# +AUTO_FILES_JAVA_DIRS = jdk/internal/org/objectweb/asm + +# +# Rules +# +include $(BUILDDIR)/common/Classes.gmk diff --git a/jdk/make/jdk_generic_profile.sh b/jdk/make/jdk_generic_profile.sh index 93aa1cd4d25..6836d8bd0b8 100644 --- a/jdk/make/jdk_generic_profile.sh +++ b/jdk/make/jdk_generic_profile.sh @@ -176,17 +176,38 @@ else else windows_arch=i586 fi + + repo=`hg root | sed -e 's@\\\\@/@g'` # We need to check if we are running a CYGWIN shell - if [ "$(uname -a | fgrep Cygwin)" != "" -a -f /bin/cygpath ] ; then + if [ "$(echo ${osname} | fgrep Cygwin)" != "" -a -f /bin/cygpath ] ; then # For CYGWIN, uname will have "Cygwin" in it, and /bin/cygpath should exist # Utility to convert to short pathnames without spaces cygpath="/usr/bin/cygpath -a -m -s" + cygpathp="/usr/bin/cygpath -p" # Most unix utilities are in the /usr/bin unixcommand_path="/usr/bin" # Make the prompt tell you CYGWIN export PS1="CYGWIN:${COMPUTERNAME}:${USERNAME}[\!] " + elif [ "$(echo ${osname} | fgrep MINGW)" != "" ] ; then + # Utility to convert to short pathnames without spaces + cygpath="${repo}/make/tools/msys_build_scripts/dospath.sh" + if [ ! -f ${cygpath} ] ; then + echo "ERROR: Cannot find cygpath or equivalent on this machine" + exit 1 + fi + # Utility to fix a path to MinGW/MSYS format - the equivalent of 'cygpath -p' + for tfile in "${repo}/make/scripts/fixpath.pl" "${repo}/../make/scripts/fixpath.pl"; do + if [ -f ${tfile} ] ; then + cygpathp="/bin/perl ${tfile} -m" + fi + done; + if [ -z "${cygpathp}" ] ; then + echo "ERROR: Cannot find make/scripts/fixpath.pl on this machine" + exit 1 + fi + unixcommand_path="/usr/bin" else - echo "ERROR: Cannot find CYGWIN on this machine" + echo "ERROR: Cannot find CYGWIN or MinGW/MSYS on this machine" exit 1 fi if [ "${ALT_UNIXCOMMAND_PATH}" != "" ] ; then @@ -204,17 +225,18 @@ else else sys_root=$(${cygpath} "C:/WINNT") fi - path4sdk="${unixcommand_path};${sys_root}/system32;${sys_root};${sys_root}/System32/Wbem" if [ ! -d "${sys_root}" ] ; then echo "WARNING: No system root found at: ${sys_root}" fi + # Build a : separated path making sure each segment is acceptable to ${osname} + path4sdk="${unixcommand_path}:"`${cygpathp} "${sys_root}/system32;${sys_root};${sys_root}/System32/Wbem"` + # Compiler setup (nasty part) # NOTE: You can use vcvars32.bat to set PATH, LIB, and INCLUDE. # NOTE: CYGWIN has a link.exe too, make sure the compilers are first # Use supplied vsvars.sh - repo=`hg root` if [ -f "${repo}/make/scripts/vsvars.sh" ] ; then eval `sh ${repo}/make/scripts/vsvars.sh -v10` elif [ -f "${repo}/../make/scripts/vsvars.sh" ] ; then diff --git a/jdk/make/jprt.properties b/jdk/make/jprt.properties index f41a227d30e..2c1eb2c9ee8 100644 --- a/jdk/make/jprt.properties +++ b/jdk/make/jprt.properties @@ -77,20 +77,18 @@ jprt.make.rule.core.test.targets= \ ${jprt.my.test.target.set:TESTNAME=jdk_util}, \ ${jprt.my.test.target.set:TESTNAME=jdk_io}, \ ${jprt.my.test.target.set:TESTNAME=jdk_net}, \ - ${jprt.my.test.target.set:TESTNAME=jdk_nio1}, \ - ${jprt.my.test.target.set:TESTNAME=jdk_nio2}, \ - ${jprt.my.test.target.set:TESTNAME=jdk_nio3}, \ + ${jprt.my.test.target.set:TESTNAME=jdk_nio}, \ ${jprt.my.test.target.set:TESTNAME=jdk_security1}, \ ${jprt.my.test.target.set:TESTNAME=jdk_security2}, \ ${jprt.my.test.target.set:TESTNAME=jdk_security3}, \ ${jprt.my.test.target.set:TESTNAME=jdk_rmi}, \ - ${jprt.my.test.target.set:TESTNAME=jdk_management1}, \ - ${jprt.my.test.target.set:TESTNAME=jdk_management2}, \ + ${jprt.my.test.target.set:TESTNAME=jdk_management}, \ + ${jprt.my.test.target.set:TESTNAME=jdk_jmx}, \ ${jprt.my.test.target.set:TESTNAME=jdk_text}, \ - ${jprt.my.test.target.set:TESTNAME=jdk_tools1}, \ - ${jprt.my.test.target.set:TESTNAME=jdk_tools2}, \ + ${jprt.my.test.target.set:TESTNAME=jdk_tools}, \ + ${jprt.my.test.target.set:TESTNAME=jdk_jdi}, \ ${jprt.my.test.target.set:TESTNAME=jdk_jfr}, \ - ${jprt.my.test.target.set:TESTNAME=jdk_misc} + ${jprt.my.test.target.set:TESTNAME=jdk_other} # All vm test targets (testset=all) jprt.vm.all.test.targets= \ diff --git a/jdk/make/launchers/Makefile b/jdk/make/launchers/Makefile index 9979d973b39..3d9511408b0 100644 --- a/jdk/make/launchers/Makefile +++ b/jdk/make/launchers/Makefile @@ -58,7 +58,7 @@ $(make-appletviewer) $(call make-launcher, extcheck, com.sun.tools.extcheck.Main, , ) $(call make-launcher, idlj, com.sun.tools.corba.se.idl.toJavaPortable.Compile, , ) $(call make-launcher, jar, sun.tools.jar.Main, , ) -$(call make-launcher, jarsigner, sun.security.tools.JarSigner, , ) +$(call make-launcher, jarsigner, sun.security.tools.jarsigner.Main, , ) $(call make-launcher, javac, com.sun.tools.javac.Main, , ) $(call make-launcher, javadoc, com.sun.tools.javadoc.Main, , ) $(call make-launcher, javah, com.sun.tools.javah.Main, , ) diff --git a/jdk/make/sun/net/FILES_java.gmk b/jdk/make/sun/net/FILES_java.gmk index 6c140abc68b..9c5feb4457e 100644 --- a/jdk/make/sun/net/FILES_java.gmk +++ b/jdk/make/sun/net/FILES_java.gmk @@ -128,8 +128,6 @@ FILES_java = \ sun/net/www/content/audio/x_wav.java \ sun/net/www/protocol/ftp/Handler.java \ sun/net/www/protocol/ftp/FtpURLConnection.java \ - sun/net/www/protocol/gopher/GopherClient.java \ - sun/net/www/protocol/gopher/Handler.java \ sun/net/www/protocol/mailto/Handler.java \ sun/net/www/protocol/mailto/MailToURLConnection.java \ sun/net/idn/Punycode.java \ diff --git a/jdk/make/sun/security/tools/Makefile b/jdk/make/sun/security/tools/Makefile index f46070d07ca..a03f85d0849 100644 --- a/jdk/make/sun/security/tools/Makefile +++ b/jdk/make/sun/security/tools/Makefile @@ -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 @@ -37,7 +37,7 @@ AUTO_FILES_JAVA_DIRS = sun/security/tools # Resources # LOCALE_SET_DEFINITION = jdk -RESOURCE_BUNDLES_JAVA = sun/security/tools/JarSignerResources.java +RESOURCE_BUNDLES_JAVA = sun/security/tools/jarsigner/Resources.java # # Rules @@ -45,7 +45,7 @@ RESOURCE_BUNDLES_JAVA = sun/security/tools/JarSignerResources.java include $(BUILDDIR)/common/Classes.gmk build: - $(call make-launcher, keytool, sun.security.tools.KeyTool, , ) + $(call make-launcher, keytool, sun.security.tools.keytool.Main, , ) ifndef BUILD_HEADLESS_ONLY $(call make-launcher, policytool, sun.security.tools.policytool.PolicyTool, , ) endif diff --git a/jdk/make/tools/freetypecheck/Makefile b/jdk/make/tools/freetypecheck/Makefile index 0b18de0c17c..5bed801916a 100644 --- a/jdk/make/tools/freetypecheck/Makefile +++ b/jdk/make/tools/freetypecheck/Makefile @@ -37,11 +37,11 @@ ifeq ($(OPENJDK),true) # Start with CFLAGS (which gets us the required -xarch setting on solaris) ifeq ($(PLATFORM), windows) - FT_OPTIONS = /nologo /c + FT_OPTIONS = -nologo -c FREETYPE_DLL = $(FREETYPE_LIB_PATH)/freetype.dll FT_LD_OPTIONS = $(FREETYPE_LIB_PATH)/freetype.lib ifdef MT - FT_LD_OPTIONS += /manifest + FT_LD_OPTIONS += -manifest endif else FT_OPTIONS = $(CFLAGS) @@ -72,11 +72,11 @@ $(FT_TEST): freetypecheck.c $(prep-target) ifeq ($(PLATFORM), windows) $(CC) $(FT_OPTIONS) $(CC_OBJECT_OUTPUT_FLAG)$(FT_OBJ) $< - $(LINK) $(FT_LD_OPTIONS) /OUT:$(FT_TEST) $(FT_OBJ) + $(LINK) $(FT_LD_OPTIONS) -OUT:$(FT_TEST) $(FT_OBJ) $(CP) $(FREETYPE_DLL) $(@D)/ ifdef MT $(CP) $(MSVCRNN_DLL_PATH)/$(MSVCRNN_DLL) $(@D)/ - $(MT) /manifest $(FT_TEST).manifest /outputresource:$(FT_TEST);#1 + $(MT) -manifest $(FT_TEST).manifest -outputresource:$(FT_TEST);#1 endif else @$(CC) $(FT_OPTIONS) -o $@ $< $(FT_LD_OPTIONS) diff --git a/jdk/make/tools/msys_build_scripts/dospath.sh b/jdk/make/tools/msys_build_scripts/dospath.sh new file mode 100644 index 00000000000..d674aba29ec --- /dev/null +++ b/jdk/make/tools/msys_build_scripts/dospath.sh @@ -0,0 +1,42 @@ +# +# 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. +# + +# A shell script which converts its first argument, which must be an existing +# path name, into a DOS (aka 8.3) path name. If the path is a file, only the +# directory part of the whole path will be converted. +# This shell script executes the Visual Basic helper script 'dospath.vbs' +# which must be located in the same directory as this script itself. +# The Visual Basic script will be invoked trough the "Windows Script Host" +# which is available by default on Windows since Windows 98. + +pushd `dirname "$0"` > /dev/null +ABS_PATH=`pwd` +popd > /dev/null +if [ -d "$1" ]; then + echo `cd "$1" && cscript.exe -nologo $ABS_PATH/dospath.vbs`; +elif [ -f "$1" ]; then + DIR=`dirname "$1"`; + echo `cd "$DIR" && cscript.exe -nologo $ABS_PATH/dospath.vbs`\\`basename "$1"`; +fi diff --git a/jdk/make/tools/msys_build_scripts/dospath.vbs b/jdk/make/tools/msys_build_scripts/dospath.vbs new file mode 100644 index 00000000000..55ff34bcabe --- /dev/null +++ b/jdk/make/tools/msys_build_scripts/dospath.vbs @@ -0,0 +1,34 @@ +' +' 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. +' + +' +' Visual Basic Script which returns the DOS (aka 8.3) filename of the current +' directory. +' Only called from 'dospath.sh' during a Windows build under MinGW/MSYS. +' + +Set fso=CreateObject("Scripting.FileSystemObject") +Set path = fso.GetFolder(".") +WScript.Echo path.ShortPath diff --git a/jdk/makefiles/CompileLaunchers.gmk b/jdk/makefiles/CompileLaunchers.gmk index ce651675bad..1be6d7b1ec0 100644 --- a/jdk/makefiles/CompileLaunchers.gmk +++ b/jdk/makefiles/CompileLaunchers.gmk @@ -232,7 +232,7 @@ $(eval $(call SetupLauncher,jar,\ -DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "sun.tools.jar.Main"$(COMMA) }')) $(eval $(call SetupLauncher,jarsigner,\ - -DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "sun.security.tools.JarSigner"$(COMMA) }')) + -DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "sun.security.tools.jarsigner.Main"$(COMMA) }')) $(eval $(call SetupLauncher,javac,\ -DEXPAND_CLASSPATH_WILDCARDS \ @@ -310,7 +310,7 @@ $(eval $(call SetupLauncher,jstatd,\ -DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "sun.tools.jstatd.Jstatd"$(COMMA) }')) $(eval $(call SetupLauncher,keytool,\ - -DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "sun.security.tools.KeyTool"$(COMMA) }')) + -DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "sun.security.tools.keytool.Main"$(COMMA) }')) $(eval $(call SetupLauncher,native2ascii,\ -DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "sun.tools.native2ascii.Main"$(COMMA) }')) diff --git a/jdk/makefiles/CompileNativeLibraries.gmk b/jdk/makefiles/CompileNativeLibraries.gmk index 5a3be46cb22..4962b40a2f1 100644 --- a/jdk/makefiles/CompileNativeLibraries.gmk +++ b/jdk/makefiles/CompileNativeLibraries.gmk @@ -209,7 +209,6 @@ ifeq ($(OPENJDK_TARGET_OS),windows) else LIBJAVA_EXCLUDE_FILES += \ ProcessImpl_md.c \ - Win32FileSystem_md.c \ WinNTFileSystem_md.c \ dirent_md.c \ WindowsPreferences.c \ diff --git a/jdk/makefiles/CreateJars.gmk b/jdk/makefiles/CreateJars.gmk index 27ac93f321d..ebd34b3a236 100644 --- a/jdk/makefiles/CreateJars.gmk +++ b/jdk/makefiles/CreateJars.gmk @@ -131,15 +131,15 @@ RT_JAR_EXCLUDES := \ sun/tools/serialver \ sun/tools/tree \ sun/tools/util \ - sun/security/tools/JarBASE64Encoder.class \ - sun/security/tools/JarSigner.class \ - sun/security/tools/JarSignerParameters.class \ - sun/security/tools/JarSignerResources.class \ - sun/security/tools/JarSignerResources_ja.class \ - sun/security/tools/JarSignerResources_zh_CN.class \ - sun/security/tools/SignatureFile\$$$$Block.class \ - sun/security/tools/SignatureFile.class \ - sun/security/tools/TimestampedSigner.class \ + sun/security/tools/jarsigner/JarBASE64Encoder.class \ + sun/security/tools/jarsigner/Main.class \ + sun/security/tools/jarsigner/JarSignerParameters.class \ + sun/security/tools/jarsigner/Resources.class \ + sun/security/tools/jarsigner/Resources_ja.class \ + sun/security/tools/jarsigner/Resources_zh_CN.class \ + sun/security/tools/jarsigner/SignatureFile\$$$$Block.class \ + sun/security/tools/jarsigner/SignatureFile.class \ + sun/security/tools/jarsigner/TimestampedSigner.class \ sun/security/provider/Sun.class \ sun/security/rsa/SunRsaSign.class \ sun/security/ssl \ diff --git a/jdk/src/macosx/classes/com/apple/laf/AquaFileChooserUI.java b/jdk/src/macosx/classes/com/apple/laf/AquaFileChooserUI.java index f5dba5bd1c5..b7598f99d6d 100644 --- a/jdk/src/macosx/classes/com/apple/laf/AquaFileChooserUI.java +++ b/jdk/src/macosx/classes/com/apple/laf/AquaFileChooserUI.java @@ -379,6 +379,19 @@ public class AquaFileChooserUI extends FileChooserUI { } } updateButtonState(getFileChooser()); + } else if (prop.equals(JFileChooser.SELECTED_FILES_CHANGED_PROPERTY)) { + JFileChooser fileChooser = getFileChooser(); + if (!fileChooser.isDirectorySelectionEnabled()) { + final File[] files = (File[]) e.getNewValue(); + if (files != null) { + for (int selectedRow : fFileList.getSelectedRows()) { + File file = (File) fFileList.getValueAt(selectedRow, 0); + if (fileChooser.isTraversable(file)) { + fFileList.removeSelectedIndex(selectedRow); + } + } + } + } } else if (prop.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) { fFileList.clearSelection(); final File currentDirectory = getFileChooser().getCurrentDirectory(); diff --git a/jdk/src/macosx/classes/java/util/prefs/MacOSXPreferences.java b/jdk/src/macosx/classes/java/util/prefs/MacOSXPreferences.java index 42c61009d11..05943eddd44 100644 --- a/jdk/src/macosx/classes/java/util/prefs/MacOSXPreferences.java +++ b/jdk/src/macosx/classes/java/util/prefs/MacOSXPreferences.java @@ -100,7 +100,7 @@ class MacOSXPreferences extends AbstractPreferences { else this.isUser = isUserNode(); path = isRoot ? absolutePath() : absolutePath() + "/"; - file = cfFileForNode(isUser); + file = cfFileForNode(this.isUser); if (isNew) newNode = isNew; else diff --git a/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java b/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java index 431a1e000d4..2b884538839 100644 --- a/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java +++ b/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java @@ -33,9 +33,7 @@ import java.awt.DisplayMode; import sun.java2d.opengl.CGLGraphicsConfig; -import sun.awt.FullScreenCapable; - -public class CGraphicsDevice extends GraphicsDevice { +public final class CGraphicsDevice extends GraphicsDevice { // CoreGraphics display ID private final int displayID; @@ -108,11 +106,6 @@ public class CGraphicsDevice extends GraphicsDevice { return nativeGetYResolution(displayID); } - public int getScreenResolution() { - // TODO: report non-72 value when HiDPI is turned on - return 72; - } - private static native double nativeGetXResolution(int displayID); private static native double nativeGetYResolution(int displayID); @@ -194,6 +187,9 @@ public class CGraphicsDevice extends GraphicsDevice { @Override public void setDisplayMode(DisplayMode dm) { + if (dm == null) { + throw new IllegalArgumentException("Invalid display mode"); + } nativeSetDisplayMode(displayID, dm.getWidth(), dm.getHeight(), dm.getBitDepth(), dm.getRefreshRate()); if (isFullScreenSupported() && getFullScreenWindow() != null) { getFullScreenWindow().setSize(dm.getWidth(), dm.getHeight()); diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java index 15502d1f8d7..6146ca25576 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java @@ -65,7 +65,7 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo private static native void nativeDispose(long nsWindowPtr); private static native CPlatformWindow nativeGetTopmostPlatformWindowUnderMouse(); - private static native int nativeGetNSWindowDisplayID_AppKitThread(long nsWindowPtr); + private static native int nativeGetNSWindowDisplayID(long nsWindowPtr); // Loger to report issues happened during execution but that do not affect functionality private static final PlatformLogger logger = PlatformLogger.getLogger("sun.lwawt.macosx.CPlatformWindow"); @@ -444,7 +444,7 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo public GraphicsDevice getGraphicsDevice() { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); CGraphicsEnvironment cge = (CGraphicsEnvironment)ge; - int displayID = nativeGetNSWindowDisplayID_AppKitThread(getNSWindowPtr()); + int displayID = nativeGetNSWindowDisplayID(getNSWindowPtr()); GraphicsDevice gd = cge.getScreenDevice(displayID); if (gd == null) { // this could possibly happen during device removal diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CTrayIcon.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CTrayIcon.java index fac844e4229..4a19e5a064d 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CTrayIcon.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CTrayIcon.java @@ -26,6 +26,7 @@ package sun.lwawt.macosx; import sun.awt.SunToolkit; +import sun.lwawt.macosx.event.NSEvent; import javax.swing.*; import java.awt.*; @@ -42,6 +43,16 @@ public class CTrayIcon extends CFRetainedResource implements TrayIconPeer { private JDialog messageDialog; private DialogEventHandler handler; + // In order to construct MouseEvent object, we need to specify a + // Component target. Because TrayIcon isn't Component's subclass, + // we use this dummy frame instead + private final Frame dummyFrame; + + // A bitmask that indicates what mouse buttons produce MOUSE_CLICKED events + // on MOUSE_RELEASE. Click events are only generated if there were no drag + // events between MOUSE_PRESSED and MOUSE_RELEASED for particular button + private static int mouseClickButtons = 0; + CTrayIcon(TrayIcon target) { super(0, true); @@ -49,6 +60,7 @@ public class CTrayIcon extends CFRetainedResource implements TrayIconPeer { this.handler = null; this.target = target; this.popup = target.getPopupMenu(); + this.dummyFrame = new Frame(); setPtr(createModel()); //if no one else is creating the peer. @@ -119,6 +131,8 @@ public class CTrayIcon extends CFRetainedResource implements TrayIconPeer { disposeMessageDialog(); } + dummyFrame.dispose(); + LWCToolkit.targetDisposedPeer(target, this); target = null; @@ -161,17 +175,78 @@ public class CTrayIcon extends CFRetainedResource implements TrayIconPeer { private native void setNativeImage(final long model, final long nsimage, final boolean autosize); - //invocation from the AWTTrayIcon.m - public void performAction() { + private void postEvent(final AWTEvent event) { SunToolkit.executeOnEventHandlerThread(target, new Runnable() { public void run() { - final String cmd = target.getActionCommand(); - final ActionEvent event = new ActionEvent(target, ActionEvent.ACTION_PERFORMED, cmd); SunToolkit.postEvent(SunToolkit.targetToAppContext(target), event); } }); } + //invocation from the AWTTrayIcon.m + private void handleMouseEvent(NSEvent nsEvent) { + int buttonNumber = nsEvent.getButtonNumber(); + final SunToolkit tk = (SunToolkit)Toolkit.getDefaultToolkit(); + if ((buttonNumber > 2 && !tk.areExtraMouseButtonsEnabled()) + || buttonNumber > tk.getNumberOfButtons() - 1) { + return; + } + + int jeventType = NSEvent.nsToJavaEventType(nsEvent.getType()); + + int jbuttonNumber = MouseEvent.NOBUTTON; + int jclickCount = 0; + if (jeventType != MouseEvent.MOUSE_MOVED) { + jbuttonNumber = NSEvent.nsToJavaButton(buttonNumber); + jclickCount = nsEvent.getClickCount(); + } + + int jmodifiers = NSEvent.nsToJavaMouseModifiers(buttonNumber, + nsEvent.getModifierFlags()); + boolean isPopupTrigger = NSEvent.isPopupTrigger(jmodifiers); + + int eventButtonMask = (jbuttonNumber > 0)? + MouseEvent.getMaskForButton(jbuttonNumber) : 0; + long when = System.currentTimeMillis(); + + if (jeventType == MouseEvent.MOUSE_PRESSED) { + mouseClickButtons |= eventButtonMask; + } else if (jeventType == MouseEvent.MOUSE_DRAGGED) { + mouseClickButtons = 0; + } + + // The MouseEvent's coordinates are relative to screen + int absX = nsEvent.getAbsX(); + int absY = nsEvent.getAbsY(); + + MouseEvent mouseEvent = new MouseEvent(dummyFrame, jeventType, when, + jmodifiers, absX, absY, absX, absY, jclickCount, isPopupTrigger, + jbuttonNumber); + mouseEvent.setSource(target); + postEvent(mouseEvent); + + // fire ACTION event + if (jeventType == MouseEvent.MOUSE_PRESSED && isPopupTrigger) { + final String cmd = target.getActionCommand(); + final ActionEvent event = new ActionEvent(target, + ActionEvent.ACTION_PERFORMED, cmd); + postEvent(event); + } + + // synthesize CLICKED event + if (jeventType == MouseEvent.MOUSE_RELEASED) { + if ((mouseClickButtons & eventButtonMask) != 0) { + MouseEvent clickEvent = new MouseEvent(dummyFrame, + MouseEvent.MOUSE_CLICKED, when, jmodifiers, absX, absY, + absX, absY, jclickCount, isPopupTrigger, jbuttonNumber); + clickEvent.setSource(target); + postEvent(clickEvent); + } + + mouseClickButtons &= ~eventButtonMask; + } + } + private native Point2D nativeGetIconLocation(long trayIconModel); public void displayMessageOnEDT(String caption, String text, @@ -256,6 +331,9 @@ public class CTrayIcon extends CFRetainedResource implements TrayIconPeer { dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); dialog.setModal(false); + dialog.setModalExclusionType(Dialog.ModalExclusionType.TOOLKIT_EXCLUDE); + dialog.setAlwaysOnTop(true); + dialog.setAutoRequestFocus(false); dialog.setResizable(false); dialog.setContentPane(op); diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java b/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java index 23df4fbf9eb..32a980898c0 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java @@ -53,7 +53,7 @@ class NamedCursor extends Cursor { /** * Mac OS X Cocoa-based AWT Toolkit. */ -public class LWCToolkit extends LWToolkit { +public final class LWCToolkit extends LWToolkit { // While it is possible to enumerate all mouse devices // and query them for the number of buttons, the code // that does it is rather complex. Instead, we opt for @@ -278,7 +278,6 @@ public class LWCToolkit extends LWToolkit { return new CMouseInfoPeer(); } - @Override protected int getScreenHeight() { return GraphicsEnvironment.getLocalGraphicsEnvironment() @@ -333,8 +332,9 @@ public class LWCToolkit extends LWToolkit { @Override public int getScreenResolution() throws HeadlessException { - return ((CGraphicsDevice) GraphicsEnvironment - .getLocalGraphicsEnvironment().getDefaultScreenDevice()).getScreenResolution(); + return (int) ((CGraphicsDevice) GraphicsEnvironment + .getLocalGraphicsEnvironment().getDefaultScreenDevice()) + .getXResolution(); } @Override diff --git a/jdk/src/macosx/native/sun/awt/AWTWindow.m b/jdk/src/macosx/native/sun/awt/AWTWindow.m index 2e2b854f35b..f2958e38894 100644 --- a/jdk/src/macosx/native/sun/awt/AWTWindow.m +++ b/jdk/src/macosx/native/sun/awt/AWTWindow.m @@ -324,6 +324,13 @@ AWT_ASSERT_APPKIT_THREAD; } } ++ (NSNumber *) getNSWindowDisplayID_AppKitThread:(NSWindow *)window { + AWT_ASSERT_APPKIT_THREAD; + NSScreen *screen = [window screen]; + NSDictionary *deviceDescription = [screen deviceDescription]; + return [deviceDescription objectForKey:@"NSScreenNumber"]; +} + - (void) dealloc { AWT_ASSERT_APPKIT_THREAD; @@ -1113,19 +1120,22 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSynthesizeMou * Signature: (J)I */ JNIEXPORT jint JNICALL -Java_sun_lwawt_macosx_CPlatformWindow_nativeGetNSWindowDisplayID_1AppKitThread +Java_sun_lwawt_macosx_CPlatformWindow_nativeGetNSWindowDisplayID (JNIEnv *env, jclass clazz, jlong windowPtr) { - jint ret; // CGDirectDisplayID + __block jint ret; // CGDirectDisplayID JNF_COCOA_ENTER(env); -AWT_ASSERT_APPKIT_THREAD; NSWindow *window = OBJC(windowPtr); - NSScreen *screen = [window screen]; - NSDictionary *deviceDescription = [screen deviceDescription]; - NSNumber *displayID = [deviceDescription objectForKey:@"NSScreenNumber"]; - ret = (jint)[displayID intValue]; + + if ([NSThread isMainThread]) { + ret = (jint)[[AWTWindow getNSWindowDisplayID_AppKitThread: window] intValue]; + } else { + [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + ret = (jint)[[AWTWindow getNSWindowDisplayID_AppKitThread: window] intValue]; + }]; + } JNF_COCOA_EXIT(env); diff --git a/jdk/src/macosx/native/sun/awt/CTrayIcon.h b/jdk/src/macosx/native/sun/awt/CTrayIcon.h index c5ceebf3414..9501e7ddde4 100644 --- a/jdk/src/macosx/native/sun/awt/CTrayIcon.h +++ b/jdk/src/macosx/native/sun/awt/CTrayIcon.h @@ -53,6 +53,7 @@ extern "C" { - (jobject) peer; - (void) setImage:(NSImage *) imagePtr sizing:(BOOL)autosize; - (NSPoint) getLocationOnScreen; +- (void) deliverJavaMouseEvent:(NSEvent*) event; @end //AWTTrayIcon @@ -68,6 +69,7 @@ extern "C" { -(id)initWithTrayIcon:(AWTTrayIcon *)theTrayIcon; -(void)setHighlighted:(BOOL)aFlag; -(void)setImage:(NSImage*)anImage; +-(void)setTrayIcon:(AWTTrayIcon*)theTrayIcon; @end //AWTTrayIconView diff --git a/jdk/src/macosx/native/sun/awt/CTrayIcon.m b/jdk/src/macosx/native/sun/awt/CTrayIcon.m index b9c2942f1b7..a69995f84aa 100644 --- a/jdk/src/macosx/native/sun/awt/CTrayIcon.m +++ b/jdk/src/macosx/native/sun/awt/CTrayIcon.m @@ -29,6 +29,7 @@ #import "CTrayIcon.h" #import "ThreadUtilities.h" #include "GeomUtilities.h" +#import "LWCToolkit.h" #define kImageInset 4.0 @@ -76,8 +77,9 @@ static NSSize ScaledImageSizeForStatusBar(NSSize imageSize) { // Its a bad idea to force the item to release our view by setting // the item's view to nil: it can lead to a crash in some scenarios. // The item will release the view later on, so just set the view's image - // to nil since we are done with it. + // and tray icon to nil since we are done with it. [view setImage: nil]; + [view setTrayIcon: nil]; [view release]; [theItem release]; @@ -115,6 +117,45 @@ static NSSize ScaledImageSizeForStatusBar(NSSize imageSize) { return [[view window] convertBaseToScreen: NSZeroPoint]; } +-(void) deliverJavaMouseEvent: (NSEvent *) event { + [AWTToolkit eventCountPlusPlus]; + + JNIEnv *env = [ThreadUtilities getJNIEnv]; + + NSPoint eventLocation = [event locationInWindow]; + NSPoint localPoint = [view convertPoint: eventLocation fromView: nil]; + localPoint.y = [view bounds].size.height - localPoint.y; + + NSPoint absP = [NSEvent mouseLocation]; + NSEventType type = [event type]; + + NSRect screenRect = [[NSScreen mainScreen] frame]; + absP.y = screenRect.size.height - absP.y; + jint clickCount; + + clickCount = [event clickCount]; + + static JNF_CLASS_CACHE(jc_NSEvent, "sun/lwawt/macosx/event/NSEvent"); + static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IIIIIIIIDD)V"); + jobject jEvent = JNFNewObject(env, jctor_NSEvent, + [event type], + [event modifierFlags], + clickCount, + [event buttonNumber], + (jint)localPoint.x, (jint)localPoint.y, + (jint)absP.x, (jint)absP.y, + [event deltaY], + [event deltaX]); + if (jEvent == nil) { + // Unable to create event by some reason. + return; + } + + static JNF_CLASS_CACHE(jc_TrayIcon, "sun/lwawt/macosx/CTrayIcon"); + static JNF_MEMBER_CACHE(jm_handleMouseEvent, jc_TrayIcon, "handleMouseEvent", "(Lsun/lwawt/macosx/event/NSEvent;)V"); + JNFCallVoidMethod(env, peer, jm_handleMouseEvent, jEvent); +} + @end //AWTTrayIcon //================================================ @@ -123,7 +164,7 @@ static NSSize ScaledImageSizeForStatusBar(NSSize imageSize) { -(id)initWithTrayIcon:(AWTTrayIcon *)theTrayIcon { self = [super initWithFrame:NSMakeRect(0, 0, 1, 1)]; - trayIcon = theTrayIcon; + [self setTrayIcon: theTrayIcon]; isHighlighted = NO; image = nil; @@ -153,6 +194,10 @@ static NSSize ScaledImageSizeForStatusBar(NSSize imageSize) { } } +-(void)setTrayIcon:(AWTTrayIcon*)theTrayIcon { + trayIcon = theTrayIcon; +} + - (void)menuWillOpen:(NSMenu *)menu { [self setHighlighted:YES]; @@ -191,30 +236,57 @@ static NSSize ScaledImageSizeForStatusBar(NSSize imageSize) { ]; } -- (void) mouseDown:(NSEvent *)e { - //find CTrayIcon.getPopupMenuModel method and call it to get popup menu ptr. - JNIEnv *env = [ThreadUtilities getJNIEnv]; - static JNF_CLASS_CACHE(jc_CTrayIcon, "sun/lwawt/macosx/CTrayIcon"); - static JNF_MEMBER_CACHE(jm_getPopupMenuModel, jc_CTrayIcon, "getPopupMenuModel", "()J"); - static JNF_MEMBER_CACHE(jm_performAction, jc_CTrayIcon, "performAction", "()V"); - jlong res = JNFCallLongMethod(env, trayIcon.peer, jm_getPopupMenuModel); - if (res != 0) { - CPopupMenu *cmenu = jlong_to_ptr(res); - NSMenu* menu = [cmenu menu]; - [menu setDelegate:self]; - [trayIcon.theItem popUpStatusItemMenu:menu]; - [self setNeedsDisplay:YES]; - } else { - JNFCallVoidMethod(env, trayIcon.peer, jm_performAction); +- (void)mouseDown:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; + + // don't show the menu on ctrl+click: it triggers ACTION event, like right click + if (([event modifierFlags] & NSControlKeyMask) == 0) { + //find CTrayIcon.getPopupMenuModel method and call it to get popup menu ptr. + JNIEnv *env = [ThreadUtilities getJNIEnv]; + static JNF_CLASS_CACHE(jc_CTrayIcon, "sun/lwawt/macosx/CTrayIcon"); + static JNF_MEMBER_CACHE(jm_getPopupMenuModel, jc_CTrayIcon, "getPopupMenuModel", "()J"); + jlong res = JNFCallLongMethod(env, trayIcon.peer, jm_getPopupMenuModel); + + if (res != 0) { + CPopupMenu *cmenu = jlong_to_ptr(res); + NSMenu* menu = [cmenu menu]; + [menu setDelegate:self]; + [trayIcon.theItem popUpStatusItemMenu:menu]; + [self setNeedsDisplay:YES]; + } } } -- (void) rightMouseDown:(NSEvent *)e { - // Call CTrayIcon.performAction() method on right mouse press - JNIEnv *env = [ThreadUtilities getJNIEnv]; - static JNF_CLASS_CACHE(jc_CTrayIcon, "sun/lwawt/macosx/CTrayIcon"); - static JNF_MEMBER_CACHE(jm_performAction, jc_CTrayIcon, "performAction", "()V"); - JNFCallVoidMethod(env, trayIcon.peer, jm_performAction); +- (void) mouseUp:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; +} + +- (void) mouseDragged:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; +} + +- (void) rightMouseDown:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; +} + +- (void) rightMouseUp:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; +} + +- (void) rightMouseDragged:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; +} + +- (void) otherMouseDown:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; +} + +- (void) otherMouseUp:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; +} + +- (void) otherMouseDragged:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; } diff --git a/jdk/src/share/classes/com/sun/beans/decoder/DocumentHandler.java b/jdk/src/share/classes/com/sun/beans/decoder/DocumentHandler.java index f454006ab7e..4bbb8f4a201 100644 --- a/jdk/src/share/classes/com/sun/beans/decoder/DocumentHandler.java +++ b/jdk/src/share/classes/com/sun/beans/decoder/DocumentHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -37,6 +37,9 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; @@ -46,6 +49,8 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; +import sun.misc.SharedSecrets; + /** * The main class to parse JavaBeans XML archive. * @@ -56,11 +61,10 @@ import org.xml.sax.helpers.DefaultHandler; * @see ElementHandler */ public final class DocumentHandler extends DefaultHandler { - private final Map> handlers = new HashMap>(); - - private final Map environment = new HashMap(); - - private final List objects = new ArrayList(); + private final AccessControlContext acc = AccessController.getContext(); + private final Map> handlers = new HashMap<>(); + private final Map environment = new HashMap<>(); + private final List objects = new ArrayList<>(); private Reference loader; private ExceptionListener listener; @@ -351,23 +355,32 @@ public final class DocumentHandler extends DefaultHandler { * * @param input the input source to parse */ - public void parse(InputSource input) { - try { - SAXParserFactory.newInstance().newSAXParser().parse(input, this); + public void parse(final InputSource input) { + if ((this.acc == null) && (null != System.getSecurityManager())) { + throw new SecurityException("AccessControlContext is not set"); } - catch (ParserConfigurationException exception) { - handleException(exception); - } - catch (SAXException wrapper) { - Exception exception = wrapper.getException(); - if (exception == null) { - exception = wrapper; + AccessControlContext stack = AccessController.getContext(); + SharedSecrets.getJavaSecurityAccess().doIntersectionPrivilege(new PrivilegedAction() { + public Void run() { + try { + SAXParserFactory.newInstance().newSAXParser().parse(input, DocumentHandler.this); + } + catch (ParserConfigurationException exception) { + handleException(exception); + } + catch (SAXException wrapper) { + Exception exception = wrapper.getException(); + if (exception == null) { + exception = wrapper; + } + handleException(exception); + } + catch (IOException exception) { + handleException(exception); + } + return null; } - handleException(exception); - } - catch (IOException exception) { - handleException(exception); - } + }, stack, this.acc); } /** diff --git a/jdk/src/share/classes/com/sun/beans/decoder/PropertyElementHandler.java b/jdk/src/share/classes/com/sun/beans/decoder/PropertyElementHandler.java index f20829385d4..8f4c40cac93 100644 --- a/jdk/src/share/classes/com/sun/beans/decoder/PropertyElementHandler.java +++ b/jdk/src/share/classes/com/sun/beans/decoder/PropertyElementHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -35,6 +35,8 @@ import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import sun.reflect.misc.MethodUtil; + /** * This class is intended to handle <property> element. * This element simplifies access to the properties. @@ -168,11 +170,11 @@ final class PropertyElementHandler extends AccessorElementHandler { private static Object getPropertyValue(Object bean, String name, Integer index) throws IllegalAccessException, IntrospectionException, InvocationTargetException, NoSuchMethodException { Class type = bean.getClass(); if (index == null) { - return findGetter(type, name).invoke(bean); + return MethodUtil.invoke(findGetter(type, name), bean, new Object[] {}); } else if (type.isArray() && (name == null)) { return Array.get(bean, index); } else { - return findGetter(type, name, int.class).invoke(bean, index); + return MethodUtil.invoke(findGetter(type, name, int.class), bean, new Object[] {index}); } } @@ -197,11 +199,11 @@ final class PropertyElementHandler extends AccessorElementHandler { : null; if (index == null) { - findSetter(type, name, param).invoke(bean, value); + MethodUtil.invoke(findSetter(type, name, param), bean, new Object[] {value}); } else if (type.isArray() && (name == null)) { Array.set(bean, index, value); } else { - findSetter(type, name, int.class, param).invoke(bean, index, value); + MethodUtil.invoke(findSetter(type, name, int.class, param), bean, new Object[] {index, value}); } } diff --git a/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java b/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java index ba071411608..58ccfb45280 100644 --- a/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java +++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java @@ -68,9 +68,9 @@ public class ServerNotifForwarder { this.notifBuffer = notifBuffer; this.connectionId = connectionId; connectionTimeout = EnvHelp.getServerConnectionTimeout(env); - checkNotificationEmission = EnvHelp.computeBooleanFromString( - env, - "jmx.remote.x.check.notification.emission",false); + + String stringBoolean = (String) env.get("jmx.remote.x.check.notification.emission"); + checkNotificationEmission = EnvHelp.computeBooleanFromString( stringBoolean ); notificationAccessController = EnvHelp.getNotificationAccessController(env); } diff --git a/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java b/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java index e61d9d09d60..b8bf9d37a0f 100644 --- a/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java +++ b/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java @@ -665,97 +665,57 @@ public class EnvHelp { * Computes a boolean value from a string value retrieved from a * property in the given map. * - * @param env the environment map. - * @param prop the name of the property in the environment map whose - * returned string value must be converted into a boolean value. - * @param systemProperty if true, consult a system property of the - * same name if there is no entry in the environment map. + * @param stringBoolean the string value that must be converted + * into a boolean value. * * @return *
      - *
    • {@code false} if {@code env.get(prop)} is {@code null}
    • + *
    • {@code false} if {@code stringBoolean} is {@code null}
    • *
    • {@code false} if - * {@code ((String)env.get(prop)).equalsIgnoreCase("false")} + * {@code stringBoolean.equalsIgnoreCase("false")} * is {@code true}
    • *
    • {@code true} if - * {@code ((String)env.get(prop)).equalsIgnoreCase("true")} + * {@code stringBoolean.equalsIgnoreCase("true")} * is {@code true}
    • *
    * - * @throws IllegalArgumentException if {@code env} is {@code null} or - * {@code env.get(prop)} is not {@code null} and + * @throws IllegalArgumentException if * {@code ((String)env.get(prop)).equalsIgnoreCase("false")} and * {@code ((String)env.get(prop)).equalsIgnoreCase("true")} are * {@code false}. - * @throws ClassCastException if {@code env.get(prop)} cannot be cast - * to {@code String}. */ - public static boolean computeBooleanFromString( - Map env, String prop, boolean systemProperty) { - - if (env == null) - throw new IllegalArgumentException("env map cannot be null"); - + public static boolean computeBooleanFromString(String stringBoolean) { // returns a default value of 'false' if no property is found... - return computeBooleanFromString(env,prop,systemProperty,false); + return computeBooleanFromString(stringBoolean,false); } /** * Computes a boolean value from a string value retrieved from a * property in the given map. * - * @param env the environment map. - * @param prop the name of the property in the environment map whose - * returned string value must be converted into a boolean value. - * @param systemProperty if true, consult a system property of the - * same name if there is no entry in the environment map. + * @param stringBoolean the string value that must be converted + * into a boolean value. * @param defaultValue a default value to return in case no property * was defined. * * @return *
      - *
    • {@code defaultValue} if {@code env.get(prop)} is {@code null} - * and {@code systemProperty} is {@code false}
    • - *
    • {@code defaultValue} if {@code env.get(prop)} is {@code null} - * and {@code systemProperty} is {@code true} and - * {@code System.getProperty(prop)} is {@code null}
    • - *
    • {@code false} if {@code env.get(prop)} is {@code null} - * and {@code systemProperty} is {@code true} and - * {@code System.getProperty(prop).equalsIgnoreCase("false")} - * is {@code true}
    • - *
    • {@code true} if {@code env.get(prop)} is {@code null} - * and {@code systemProperty} is {@code true} and - * {@code System.getProperty(prop).equalsIgnoreCase("true")} - * is {@code true}
    • + *
    • {@code defaultValue} if {@code stringBoolean} + * is {@code null}
    • *
    • {@code false} if - * {@code ((String)env.get(prop)).equalsIgnoreCase("false")} + * {@code stringBoolean.equalsIgnoreCase("false")} * is {@code true}
    • *
    • {@code true} if - * {@code ((String)env.get(prop)).equalsIgnoreCase("true")} + * {@code stringBoolean.equalsIgnoreCase("true")} * is {@code true}
    • *
    * - * @throws IllegalArgumentException if {@code env} is {@code null} or - * {@code env.get(prop)} is not {@code null} and + * @throws IllegalArgumentException if * {@code ((String)env.get(prop)).equalsIgnoreCase("false")} and * {@code ((String)env.get(prop)).equalsIgnoreCase("true")} are * {@code false}. - * @throws ClassCastException if {@code env.get(prop)} cannot be cast - * to {@code String}. */ - public static boolean computeBooleanFromString( - Map env, String prop, - boolean systemProperty, boolean defaultValue) { - - if (env == null) - throw new IllegalArgumentException("env map cannot be null"); - - String stringBoolean = (String) env.get(prop); - if (stringBoolean == null && systemProperty) { - stringBoolean = - AccessController.doPrivileged(new GetPropertyAction(prop)); - } - + public static boolean computeBooleanFromString( String stringBoolean, boolean defaultValue) { if (stringBoolean == null) return defaultValue; else if (stringBoolean.equalsIgnoreCase("true")) @@ -763,8 +723,8 @@ public class EnvHelp { else if (stringBoolean.equalsIgnoreCase("false")) return false; else - throw new IllegalArgumentException(prop + - " must be \"true\" or \"false\" instead of \"" + + throw new IllegalArgumentException( + "Property value must be \"true\" or \"false\" instead of \"" + stringBoolean + "\""); } diff --git a/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java b/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java index 2b8b410f4cb..0d96af74a9c 100644 --- a/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java +++ b/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java @@ -157,7 +157,8 @@ public final class Connection implements Runnable { volatile IOException closureReason = null; volatile boolean useable = true; // is Connection still useable - private int readTimeout; + int readTimeout; + int connectTimeout; // true means v3; false means v2 // Called in LdapClient.authenticate() (which is synchronized) @@ -187,6 +188,7 @@ public final class Connection implements Runnable { this.port = port; this.parent = parent; this.readTimeout = readTimeout; + this.connectTimeout = connectTimeout; if (trace != null) { traceFile = trace; diff --git a/jdk/src/share/classes/com/sun/jndi/ldap/LdapClient.java b/jdk/src/share/classes/com/sun/jndi/ldap/LdapClient.java index 788152929b2..e0d0454dfa1 100644 --- a/jdk/src/share/classes/com/sun/jndi/ldap/LdapClient.java +++ b/jdk/src/share/classes/com/sun/jndi/ldap/LdapClient.java @@ -150,149 +150,155 @@ public final class LdapClient implements PooledConnection { String authMechanism, Control[] ctls, Hashtable env) throws NamingException { - authenticateCalled = true; - - try { - ensureOpen(); - } catch (IOException e) { - NamingException ne = new CommunicationException(); - ne.setRootCause(e); - throw ne; - } - - switch (version) { - case LDAP_VERSION3_VERSION2: - case LDAP_VERSION3: - isLdapv3 = true; - break; - case LDAP_VERSION2: - isLdapv3 = false; - break; - default: - throw new CommunicationException("Protocol version " + version + - " not supported"); - } - + int readTimeout = conn.readTimeout; + conn.readTimeout = conn.connectTimeout; LdapResult res = null; - if (authMechanism.equalsIgnoreCase("none") || - authMechanism.equalsIgnoreCase("anonymous")) { + try { + authenticateCalled = true; - // Perform LDAP bind if we are reauthenticating, using LDAPv2, - // supporting failover to LDAPv2, or controls have been supplied. - if (!initial || - (version == LDAP_VERSION2) || - (version == LDAP_VERSION3_VERSION2) || - ((ctls != null) && (ctls.length > 0))) { + try { + ensureOpen(); + } catch (IOException e) { + NamingException ne = new CommunicationException(); + ne.setRootCause(e); + throw ne; + } + + switch (version) { + case LDAP_VERSION3_VERSION2: + case LDAP_VERSION3: + isLdapv3 = true; + break; + case LDAP_VERSION2: + isLdapv3 = false; + break; + default: + throw new CommunicationException("Protocol version " + version + + " not supported"); + } + + if (authMechanism.equalsIgnoreCase("none") || + authMechanism.equalsIgnoreCase("anonymous")) { + + // Perform LDAP bind if we are reauthenticating, using LDAPv2, + // supporting failover to LDAPv2, or controls have been supplied. + if (!initial || + (version == LDAP_VERSION2) || + (version == LDAP_VERSION3_VERSION2) || + ((ctls != null) && (ctls.length > 0))) { + try { + // anonymous bind; update name/pw for LDAPv2 retry + res = ldapBind(name=null, (byte[])(pw=null), ctls, null, + false); + if (res.status == LdapClient.LDAP_SUCCESS) { + conn.setBound(); + } + } catch (IOException e) { + NamingException ne = + new CommunicationException("anonymous bind failed: " + + conn.host + ":" + conn.port); + ne.setRootCause(e); + throw ne; + } + } else { + // Skip LDAP bind for LDAPv3 anonymous bind + res = new LdapResult(); + res.status = LdapClient.LDAP_SUCCESS; + } + } else if (authMechanism.equalsIgnoreCase("simple")) { + // simple authentication + byte[] encodedPw = null; try { - // anonymous bind; update name/pw for LDAPv2 retry - res = ldapBind(name=null, (byte[])(pw=null), ctls, null, - false); + encodedPw = encodePassword(pw, isLdapv3); + res = ldapBind(name, encodedPw, ctls, null, false); if (res.status == LdapClient.LDAP_SUCCESS) { conn.setBound(); } } catch (IOException e) { NamingException ne = - new CommunicationException("anonymous bind failed: " + + new CommunicationException("simple bind failed: " + + conn.host + ":" + conn.port); + ne.setRootCause(e); + throw ne; + } finally { + // If pw was copied to a new array, clear that array as + // a security precaution. + if (encodedPw != pw && encodedPw != null) { + for (int i = 0; i < encodedPw.length; i++) { + encodedPw[i] = 0; + } + } + } + } else if (isLdapv3) { + // SASL authentication + try { + res = LdapSasl.saslBind(this, conn, conn.host, name, pw, + authMechanism, env, ctls); + if (res.status == LdapClient.LDAP_SUCCESS) { + conn.setBound(); + } + } catch (IOException e) { + NamingException ne = + new CommunicationException("SASL bind failed: " + conn.host + ":" + conn.port); ne.setRootCause(e); throw ne; } } else { - // Skip LDAP bind for LDAPv3 anonymous bind - res = new LdapResult(); - res.status = LdapClient.LDAP_SUCCESS; + throw new AuthenticationNotSupportedException(authMechanism); } - } else if (authMechanism.equalsIgnoreCase("simple")) { - // simple authentication - byte[] encodedPw = null; - try { - encodedPw = encodePassword(pw, isLdapv3); - res = ldapBind(name, encodedPw, ctls, null, false); - if (res.status == LdapClient.LDAP_SUCCESS) { - conn.setBound(); - } - } catch (IOException e) { - NamingException ne = - new CommunicationException("simple bind failed: " + - conn.host + ":" + conn.port); - ne.setRootCause(e); - throw ne; - } finally { - // If pw was copied to a new array, clear that array as - // a security precaution. - if (encodedPw != pw && encodedPw != null) { - for (int i = 0; i < encodedPw.length; i++) { - encodedPw[i] = 0; + + // + // re-try login using v2 if failing over + // + if (initial && + (res.status == LdapClient.LDAP_PROTOCOL_ERROR) && + (version == LdapClient.LDAP_VERSION3_VERSION2) && + (authMechanism.equalsIgnoreCase("none") || + authMechanism.equalsIgnoreCase("anonymous") || + authMechanism.equalsIgnoreCase("simple"))) { + + byte[] encodedPw = null; + try { + isLdapv3 = false; + encodedPw = encodePassword(pw, false); + res = ldapBind(name, encodedPw, ctls, null, false); + if (res.status == LdapClient.LDAP_SUCCESS) { + conn.setBound(); + } + } catch (IOException e) { + NamingException ne = + new CommunicationException(authMechanism + ":" + + conn.host + ":" + conn.port); + ne.setRootCause(e); + throw ne; + } finally { + // If pw was copied to a new array, clear that array as + // a security precaution. + if (encodedPw != pw && encodedPw != null) { + for (int i = 0; i < encodedPw.length; i++) { + encodedPw[i] = 0; + } } } } - } else if (isLdapv3) { - // SASL authentication - try { - res = LdapSasl.saslBind(this, conn, conn.host, name, pw, - authMechanism, env, ctls); - if (res.status == LdapClient.LDAP_SUCCESS) { - conn.setBound(); - } - } catch (IOException e) { - NamingException ne = - new CommunicationException("SASL bind failed: " + - conn.host + ":" + conn.port); - ne.setRootCause(e); - throw ne; + + // principal name not found + // (map NameNotFoundException to AuthenticationException) + // %%% This is a workaround for Netscape servers returning + // %%% no such object when the principal name is not found + // %%% Note that when this workaround is applied, it does not allow + // %%% response controls to be recorded by the calling context + if (res.status == LdapClient.LDAP_NO_SUCH_OBJECT) { + throw new AuthenticationException( + getErrorMessage(res.status, res.errorMessage)); } - } else { - throw new AuthenticationNotSupportedException(authMechanism); + conn.setV3(isLdapv3); + return res; + } finally { + conn.readTimeout = readTimeout; } - - // - // re-try login using v2 if failing over - // - if (initial && - (res.status == LdapClient.LDAP_PROTOCOL_ERROR) && - (version == LdapClient.LDAP_VERSION3_VERSION2) && - (authMechanism.equalsIgnoreCase("none") || - authMechanism.equalsIgnoreCase("anonymous") || - authMechanism.equalsIgnoreCase("simple"))) { - - byte[] encodedPw = null; - try { - isLdapv3 = false; - encodedPw = encodePassword(pw, false); - res = ldapBind(name, encodedPw, ctls, null, false); - if (res.status == LdapClient.LDAP_SUCCESS) { - conn.setBound(); - } - } catch (IOException e) { - NamingException ne = - new CommunicationException(authMechanism + ":" + - conn.host + ":" + conn.port); - ne.setRootCause(e); - throw ne; - } finally { - // If pw was copied to a new array, clear that array as - // a security precaution. - if (encodedPw != pw && encodedPw != null) { - for (int i = 0; i < encodedPw.length; i++) { - encodedPw[i] = 0; - } - } - } - } - - // principal name not found - // (map NameNotFoundException to AuthenticationException) - // %%% This is a workaround for Netscape servers returning - // %%% no such object when the principal name is not found - // %%% Note that when this workaround is applied, it does not allow - // %%% response controls to be recorded by the calling context - if (res.status == LdapClient.LDAP_NO_SUCH_OBJECT) { - throw new AuthenticationException( - getErrorMessage(res.status, res.errorMessage)); - } - conn.setV3(isLdapv3); - return res; } /** diff --git a/jdk/src/share/classes/com/sun/rowset/CachedRowSetImpl.java b/jdk/src/share/classes/com/sun/rowset/CachedRowSetImpl.java index df6cbd0773b..af0c988b5d1 100644 --- a/jdk/src/share/classes/com/sun/rowset/CachedRowSetImpl.java +++ b/jdk/src/share/classes/com/sun/rowset/CachedRowSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -1746,12 +1746,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern // convert to a Double and compare to zero try { - Double d = new Double(value.toString()); - if (d.compareTo(new Double((double)0)) == 0) { - return false; - } else { - return true; - } + return Double.compare(Double.parseDouble(value.toString()), 0) != 0; } catch (NumberFormatException ex) { throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.boolfail").toString(), new Object[] {value.toString().trim(), columnIndex})); @@ -2039,6 +2034,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern * the cursor is not on a valid row, or this method fails * @deprecated */ + @Deprecated public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { Object value; BigDecimal bDecimal, retVal; @@ -2374,6 +2370,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern * @throws SQLException if an error occurs * @deprecated */ + @Deprecated public java.io.InputStream getUnicodeStream(int columnIndex) throws SQLException { // always free an old stream unicodeStream = null; @@ -2643,6 +2640,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern * @deprecated Use the getBigDecimal(String columnName) * method instead */ + @Deprecated public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException { return getBigDecimal(getColIdxByName(columnName), scale); } @@ -2774,6 +2772,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern * this rowset's rows or its insert row * @deprecated use the method getCharacterStream instead */ + @Deprecated public java.io.InputStream getUnicodeStream(String columnName) throws SQLException { return getUnicodeStream(getColIdxByName(columnName)); } @@ -4428,7 +4427,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern // make sure the cursor is on a valid row checkCursor(); - Object obj = convertNumeric(new Float(x), + Object obj = convertNumeric(Float.valueOf(x), java.sql.Types.REAL, RowSetMD.getColumnType(columnIndex)); @@ -4463,7 +4462,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern checkIndex(columnIndex); // make sure the cursor is on a valid row checkCursor(); - Object obj = convertNumeric(new Double(x), + Object obj = convertNumeric(Double.valueOf(x), java.sql.Types.DOUBLE, RowSetMD.getColumnType(columnIndex)); diff --git a/jdk/src/share/classes/com/sun/rowset/FilteredRowSetImpl.java b/jdk/src/share/classes/com/sun/rowset/FilteredRowSetImpl.java index 20c2743ee4b..eeda4b7e326 100644 --- a/jdk/src/share/classes/com/sun/rowset/FilteredRowSetImpl.java +++ b/jdk/src/share/classes/com/sun/rowset/FilteredRowSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -839,7 +839,7 @@ public class FilteredRowSetImpl extends WebRowSetImpl implements Serializable, C if(onInsertRow) { if(p != null) { - bool = p.evaluate(new Float(x) , columnIndex); + bool = p.evaluate(Float.valueOf(x), columnIndex); if(!bool) { throw new SQLException(resBundle.handleGetObject("filteredrowsetimpl.notallowed").toString()); @@ -906,7 +906,7 @@ public class FilteredRowSetImpl extends WebRowSetImpl implements Serializable, C if(onInsertRow) { if(p != null) { - bool = p.evaluate(new Double(x) , columnIndex); + bool = p.evaluate(Double.valueOf(x) , columnIndex); if(!bool) { throw new SQLException(resBundle.handleGetObject("filteredrowsetimpl.notallowed").toString()); diff --git a/jdk/src/share/classes/com/sun/rowset/JdbcRowSetImpl.java b/jdk/src/share/classes/com/sun/rowset/JdbcRowSetImpl.java index 36612ad8080..8302c2922c0 100644 --- a/jdk/src/share/classes/com/sun/rowset/JdbcRowSetImpl.java +++ b/jdk/src/share/classes/com/sun/rowset/JdbcRowSetImpl.java @@ -1016,6 +1016,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * prepared statement, and result set * @deprecated */ + @Deprecated public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { checkState(); @@ -1154,6 +1155,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * @deprecated use getCharacterStream in place of * getUnicodeStream */ + @Deprecated public java.io.InputStream getUnicodeStream(int columnIndex) throws SQLException { checkState(); @@ -1336,6 +1338,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * prepared statement, and result set * @deprecated */ + @Deprecated public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException { return getBigDecimal(findColumn(columnName), scale); } @@ -1461,6 +1464,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * prepared statement, and result set * @deprecated */ + @Deprecated public java.io.InputStream getUnicodeStream(String columnName) throws SQLException { return getUnicodeStream(findColumn(columnName)); } diff --git a/jdk/src/share/classes/com/sun/rowset/JoinRowSetImpl.java b/jdk/src/share/classes/com/sun/rowset/JoinRowSetImpl.java index 0f712f9946c..4593794d9d3 100644 --- a/jdk/src/share/classes/com/sun/rowset/JoinRowSetImpl.java +++ b/jdk/src/share/classes/com/sun/rowset/JoinRowSetImpl.java @@ -1153,6 +1153,7 @@ public class JoinRowSetImpl extends WebRowSetImpl implements JoinRowSet { * the cursor is not on a valid row, or this method fails * @deprecated */ + @Deprecated public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { return crsInternal.getBigDecimal(columnIndex); } @@ -1264,6 +1265,7 @@ public class JoinRowSetImpl extends WebRowSetImpl implements JoinRowSet { * @throws SQLException if an error occurs * @deprecated */ + @Deprecated public java.io.InputStream getUnicodeStream(int columnIndex) throws SQLException { return crsInternal.getUnicodeStream(columnIndex); } @@ -1436,6 +1438,7 @@ public class JoinRowSetImpl extends WebRowSetImpl implements JoinRowSet { * @deprecated use the method getBigDecimal(String columnName) * instead */ + @Deprecated public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException { return crsInternal.getBigDecimal(columnName); } @@ -1552,6 +1555,7 @@ public class JoinRowSetImpl extends WebRowSetImpl implements JoinRowSet { * this rowset's rows or its insert row * @deprecated use the method getCharacterStream instead */ + @Deprecated public java.io.InputStream getUnicodeStream(String columnName) throws SQLException { return crsInternal.getUnicodeStream(columnName); } diff --git a/jdk/src/share/classes/com/sun/rowset/internal/SyncResolverImpl.java b/jdk/src/share/classes/com/sun/rowset/internal/SyncResolverImpl.java index 911b1d17152..51654a8c83b 100644 --- a/jdk/src/share/classes/com/sun/rowset/internal/SyncResolverImpl.java +++ b/jdk/src/share/classes/com/sun/rowset/internal/SyncResolverImpl.java @@ -1288,6 +1288,7 @@ public class SyncResolverImpl extends CachedRowSetImpl implements SyncResolver { * the cursor is not on a valid row, or this method fails * @deprecated */ + @Deprecated public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { throw new UnsupportedOperationException(); } @@ -1424,6 +1425,7 @@ public class SyncResolverImpl extends CachedRowSetImpl implements SyncResolver { * @throws SQLException if an error occurs * @deprecated */ + @Deprecated public java.io.InputStream getUnicodeStream(int columnIndex) throws SQLException { throw new UnsupportedOperationException(); } @@ -1653,6 +1655,7 @@ public class SyncResolverImpl extends CachedRowSetImpl implements SyncResolver { * @deprecated Use the getBigDecimal(String columnName) * method instead */ + @Deprecated public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException { throw new UnsupportedOperationException(); } @@ -1784,6 +1787,7 @@ public class SyncResolverImpl extends CachedRowSetImpl implements SyncResolver { * this rowset's rows or its insert row * @deprecated use the method getCharacterStream instead */ + @Deprecated public java.io.InputStream getUnicodeStream(String columnName) throws SQLException { throw new UnsupportedOperationException(); } diff --git a/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java b/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java index 2f2a4944173..aaab5a9da11 100644 --- a/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java +++ b/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java @@ -802,7 +802,7 @@ public class Krb5LoginModule implements LoginModule { if (doNotPrompt) { throw new LoginException - ("Unable to obtain Princpal Name for authentication "); + ("Unable to obtain Principal Name for authentication "); } else { if (callbackHandler == null) throw new LoginException("No CallbackHandler " diff --git a/jdk/src/share/classes/java/beans/XMLDecoder.java b/jdk/src/share/classes/java/beans/XMLDecoder.java index accef1199c9..2fb2fd0ef4d 100644 --- a/jdk/src/share/classes/java/beans/XMLDecoder.java +++ b/jdk/src/share/classes/java/beans/XMLDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, 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,6 +29,9 @@ import com.sun.beans.decoder.DocumentHandler; import java.io.Closeable; import java.io.InputStream; import java.io.IOException; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; import org.xml.sax.InputSource; import org.xml.sax.helpers.DefaultHandler; @@ -61,6 +64,7 @@ import org.xml.sax.helpers.DefaultHandler; * @author Philip Milne */ public class XMLDecoder implements AutoCloseable { + private final AccessControlContext acc = AccessController.getContext(); private final DocumentHandler handler = new DocumentHandler(); private final InputSource input; private Object owner; @@ -189,7 +193,15 @@ public class XMLDecoder implements AutoCloseable { return false; } if (this.array == null) { - this.handler.parse(this.input); + if ((this.acc == null) && (null != System.getSecurityManager())) { + throw new SecurityException("AccessControlContext is not set"); + } + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + XMLDecoder.this.handler.parse(XMLDecoder.this.input); + return null; + } + }, this.acc); this.array = this.handler.getObjects(); } return true; diff --git a/jdk/src/share/classes/java/io/FilePermission.java b/jdk/src/share/classes/java/io/FilePermission.java index 97ca19597ad..e70d292e0c8 100644 --- a/jdk/src/share/classes/java/io/FilePermission.java +++ b/jdk/src/share/classes/java/io/FilePermission.java @@ -407,7 +407,7 @@ public final class FilePermission extends Permission implements Serializable { * @return a hash code value for this object. */ public int hashCode() { - return this.cpath.hashCode(); + return 0; } /** diff --git a/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java b/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java index 4071305abc5..dfc6e9d41fe 100644 --- a/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java +++ b/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java @@ -79,7 +79,7 @@ import com.sun.xml.internal.ws.org.objectweb.asm.Type; default : throw new InternalError("unexpected xtype: " + xtype); } } catch (Throwable t) { - throw new InternalError(t); + throw newInternalError(t); } } @@ -97,7 +97,7 @@ import com.sun.xml.internal.ws.org.objectweb.asm.Type; case 'D': return cloneExtendD(type, form, (double) x); } } catch (Throwable t) { - throw new InternalError(t); + throw newInternalError(t); } throw new InternalError("unexpected type: " + xtype); } @@ -115,7 +115,7 @@ import com.sun.xml.internal.ws.org.objectweb.asm.Type; try { return clone(srcType, form); } catch (Throwable t) { - throw new InternalError(t); + throw newInternalError(t); } } @@ -124,7 +124,7 @@ import com.sun.xml.internal.ws.org.objectweb.asm.Type; try { return clone(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList()))); } catch (Throwable t) { - throw new InternalError(t); + throw newInternalError(t); } } @@ -166,7 +166,7 @@ import com.sun.xml.internal.ws.org.objectweb.asm.Type; case 'J': return argJ(i); } } catch (Throwable ex) { - throw new InternalError(ex); + throw newInternalError(ex); } throw new InternalError("unexpected type: " + speciesData().types+"."+i); } @@ -192,7 +192,7 @@ import com.sun.xml.internal.ws.org.objectweb.asm.Type; try { return (MethodHandle) argL(0); } catch (Throwable ex) { - throw new InternalError(ex); + throw newInternalError(ex); } } @@ -464,7 +464,7 @@ import com.sun.xml.internal.ws.org.objectweb.asm.Type; } } } catch (Throwable e) { - throw new InternalError(e); + throw newInternalError(e); } for (SpeciesData d : CACHE.values()) { @@ -748,7 +748,7 @@ import com.sun.xml.internal.ws.org.objectweb.asm.Type; try { return LOOKUP.findGetter(cbmhClass, fieldName, fieldType); } catch (NoSuchFieldException | IllegalAccessException e) { - throw new InternalError(e); + throw newInternalError(e); } } @@ -776,7 +776,7 @@ import com.sun.xml.internal.ws.org.objectweb.asm.Type; Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA"); return (SpeciesData) F_SPECIES_DATA.get(null); } catch (ReflectiveOperationException ex) { - throw new InternalError(ex); + throw newInternalError(ex); } } @@ -802,7 +802,7 @@ import com.sun.xml.internal.ws.org.objectweb.asm.Type; try { return linkConstructor(LOOKUP.findConstructor(cbmh, MethodType.fromMethodDescriptorString(makeSignature(types, true), null))); } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) { - throw new InternalError(e); + throw newInternalError(e); } } @@ -833,7 +833,7 @@ import com.sun.xml.internal.ws.org.objectweb.asm.Type; linkerMN = MemberName.getFactory().resolveOrFail(REF_invokeStatic, linkerMN, null, NoSuchMethodException.class); assert(linkerMN.isStatic()); } catch (ReflectiveOperationException ex) { - throw new InternalError(ex); + throw newInternalError(ex); } // extend arguments array Object[] newArgs = Arrays.copyOf(initName.arguments, initName.arguments.length + 1); diff --git a/jdk/src/share/classes/java/lang/invoke/CallSite.java b/jdk/src/share/classes/java/lang/invoke/CallSite.java index 7beb101b755..5d637b96d4f 100644 --- a/jdk/src/share/classes/java/lang/invoke/CallSite.java +++ b/jdk/src/share/classes/java/lang/invoke/CallSite.java @@ -222,7 +222,7 @@ public class CallSite { GET_TARGET = IMPL_LOOKUP. findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class)); } catch (ReflectiveOperationException e) { - throw new InternalError(e); + throw newInternalError(e); } } diff --git a/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java b/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java index b1c7f82da9a..2adc8e82bd8 100644 --- a/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java +++ b/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java @@ -218,7 +218,7 @@ class DirectMethodHandle extends MethodHandle { try { linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class); } catch (ReflectiveOperationException ex) { - throw new InternalError(ex); + throw newInternalError(ex); } final int DMH_THIS = 0; final int ARG_BASE = 1; @@ -554,7 +554,7 @@ class DirectMethodHandle extends MethodHandle { try { linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, NoSuchMethodException.class); } catch (ReflectiveOperationException ex) { - throw new InternalError(ex); + throw newInternalError(ex); } // What is the external type of the lambda form? @@ -653,7 +653,7 @@ class DirectMethodHandle extends MethodHandle { nf.resolve(); } } catch (ReflectiveOperationException ex) { - throw new InternalError(ex); + throw newInternalError(ex); } } } diff --git a/jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index 48f88adeecc..0def847d38c 100644 --- a/jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -138,7 +138,7 @@ class InvokerBytecodeGenerator { DUMP_CLASS_FILES_DIR = dumpDir; System.out.println("Dumping class files to "+DUMP_CLASS_FILES_DIR+"/..."); } catch (Exception e) { - throw new InternalError(e); + throw newInternalError(e); } } else { DUMP_CLASS_FILES_COUNTERS = null; @@ -162,7 +162,7 @@ class InvokerBytecodeGenerator { file.close(); return null; } catch (IOException ex) { - throw new InternalError(ex); + throw newInternalError(ex); } } }); @@ -279,7 +279,7 @@ class InvokerBytecodeGenerator { try { member = MEMBERNAME_FACTORY.resolveOrFail(REF_invokeStatic, member, HOST_CLASS, ReflectiveOperationException.class); } catch (ReflectiveOperationException e) { - throw new InternalError(e); + throw newInternalError(e); } //System.out.println("resolveInvokerMember => "+member); return member; diff --git a/jdk/src/share/classes/java/lang/invoke/Invokers.java b/jdk/src/share/classes/java/lang/invoke/Invokers.java index 0e3dcf64bc7..0e40396a96f 100644 --- a/jdk/src/share/classes/java/lang/invoke/Invokers.java +++ b/jdk/src/share/classes/java/lang/invoke/Invokers.java @@ -27,6 +27,7 @@ package java.lang.invoke; import java.util.Arrays; import sun.invoke.empty.Empty; +import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; import static java.lang.invoke.LambdaForm.*; @@ -128,9 +129,8 @@ class Invokers { try { //Lookup.findVirtual(MethodHandle.class, name, type); return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, name, type); - } catch (ReflectiveOperationException ex) { - throw new InternalError("JVM cannot find invoker for "+type, ex); + throw newInternalError("JVM cannot find invoker for "+type, ex); } } @@ -176,7 +176,7 @@ class Invokers { .findVirtual(MethodHandle.class, "asSpreader", MethodType.methodType(MethodHandle.class, Class.class, int.class)); } catch (ReflectiveOperationException ex) { - throw new InternalError(ex); + throw newInternalError(ex); } makeSpreader = MethodHandles.insertArguments(makeSpreader, 1, Object[].class, spreadArgCount); vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader); @@ -215,7 +215,7 @@ class Invokers { .findStatic(CallSite.class, "uninitializedCallSite", MethodType.methodType(Empty.class)); } catch (ReflectiveOperationException ex) { - throw new InternalError(ex); + throw newInternalError(ex); } } invoker = MethodHandles.explicitCastArguments(invoker, MethodType.methodType(targetType.returnType())); @@ -389,7 +389,7 @@ class Invokers { form.genericInvoker = gamh; return gamh; } catch (Exception ex) { - throw new InternalError("Exception while resolving inexact invoke", ex); + throw newInternalError("Exception while resolving inexact invoke", ex); } } @@ -456,7 +456,7 @@ class Invokers { NF_getCallSiteTarget.resolve(); // bound } catch (ReflectiveOperationException ex) { - throw new InternalError(ex); + throw newInternalError(ex); } } diff --git a/jdk/src/share/classes/java/lang/invoke/LambdaForm.java b/jdk/src/share/classes/java/lang/invoke/LambdaForm.java index e39896afecb..f1da24379c0 100644 --- a/jdk/src/share/classes/java/lang/invoke/LambdaForm.java +++ b/jdk/src/share/classes/java/lang/invoke/LambdaForm.java @@ -457,7 +457,7 @@ class LambdaForm { isCompiled = true; return vmentry; } catch (Error | Exception ex) { - throw new InternalError(this.toString(), ex); + throw newInternalError(this.toString(), ex); } } @@ -1547,7 +1547,7 @@ class LambdaForm { try { zmem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zmem, null, NoSuchMethodException.class); } catch (IllegalAccessException|NoSuchMethodException ex) { - throw new InternalError(ex); + throw newInternalError(ex); } NamedFunction zcon = new NamedFunction(zmem); Name n = new Name(zcon).newIndex(0); diff --git a/jdk/src/share/classes/java/lang/invoke/MemberName.java b/jdk/src/share/classes/java/lang/invoke/MemberName.java index 595b1145fe1..e2bd9b068d4 100644 --- a/jdk/src/share/classes/java/lang/invoke/MemberName.java +++ b/jdk/src/share/classes/java/lang/invoke/MemberName.java @@ -558,7 +558,7 @@ import java.util.Objects; try { return (MemberName) super.clone(); } catch (CloneNotSupportedException ex) { - throw new InternalError(ex); + throw newInternalError(ex); } } diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandle.java b/jdk/src/share/classes/java/lang/invoke/MethodHandle.java index a5e4e584d18..2a6b8c1b789 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandle.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandle.java @@ -1372,7 +1372,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); NF_reinvokerTarget = new LambdaForm.NamedFunction(MethodHandle.class .getDeclaredMethod("reinvokerTarget")); } catch (ReflectiveOperationException ex) { - throw new InternalError(ex); + throw newInternalError(ex); } } @@ -1397,7 +1397,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); try { FORM_OFFSET = UNSAFE.objectFieldOffset(MethodHandle.class.getDeclaredField("form")); } catch (ReflectiveOperationException ex) { - throw new InternalError(ex); + throw newInternalError(ex); } } } diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java index d9822bd7189..3f58e6182eb 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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,13 +25,14 @@ package java.lang.invoke; -import sun.invoke.util.VerifyType; - +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import sun.invoke.empty.Empty; import sun.invoke.util.ValueConversions; +import sun.invoke.util.VerifyType; import sun.invoke.util.Wrapper; import static java.lang.invoke.LambdaForm.*; import static java.lang.invoke.MethodHandleStatics.*; @@ -478,7 +479,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; .getDeclaredMethod("checkSpreadArgument", Object.class, int.class)); NF_checkSpreadArgument.resolve(); } catch (ReflectiveOperationException ex) { - throw new InternalError(ex); + throw newInternalError(ex); } } @@ -781,4 +782,168 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; return mh; } + /** + * Create an alias for the method handle which, when called, + * appears to be called from the same class loader and protection domain + * as hostClass. + * This is an expensive no-op unless the method which is called + * is sensitive to its caller. A small number of system methods + * are in this category, including Class.forName and Method.invoke. + */ + static + MethodHandle bindCaller(MethodHandle mh, Class hostClass) { + return BindCaller.bindCaller(mh, hostClass); + } + + // Put the whole mess into its own nested class. + // That way we can lazily load the code and set up the constants. + private static class BindCaller { + static + MethodHandle bindCaller(MethodHandle mh, Class hostClass) { + // Do not use this function to inject calls into system classes. + if (hostClass == null) { + hostClass = C_Trampoline; + } else if (hostClass.isArray() || + hostClass.isPrimitive() || + hostClass.getName().startsWith("java.") || + hostClass.getName().startsWith("sun.")) { + throw new InternalError(); // does not happen, and should not anyway + } + // For simplicity, convert mh to a varargs-like method. + MethodHandle vamh = prepareForInvoker(mh); + // Cache the result of makeInjectedInvoker once per argument class. + MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass); + return restoreToType(bccInvoker.bindTo(vamh), mh.type()); + } + + // This class ("Trampoline") is known to be inside a dead-end class loader. + // Inject all doubtful calls into this class. + private static Class C_Trampoline; + static { + Class tramp = null; + try { + final int FRAME_COUNT_ARG = 1; // [0] Reflection [1] Trampoline + java.lang.reflect.Method gcc = sun.reflect.Reflection.class.getMethod("getCallerClass", int.class); + tramp = (Class) sun.reflect.misc.MethodUtil.invoke(gcc, null, new Object[]{ FRAME_COUNT_ARG }); + if (tramp.getClassLoader() == BindCaller.class.getClassLoader()) + throw new RuntimeException(tramp.getName()+" class loader"); + } catch (Throwable ex) { + throw new InternalError(ex); + } + C_Trampoline = tramp; + } + + private static MethodHandle makeInjectedInvoker(Class hostClass) { + Class bcc = UNSAFE.defineAnonymousClass(hostClass, T_BYTES, null); + if (hostClass.getClassLoader() != bcc.getClassLoader()) + throw new InternalError(hostClass.getName()+" (CL)"); + try { + if (hostClass.getProtectionDomain() != bcc.getProtectionDomain()) + throw new InternalError(hostClass.getName()+" (PD)"); + } catch (SecurityException ex) { + // Self-check was blocked by security manager. This is OK. + // In fact the whole try body could be turned into an assertion. + } + try { + MethodHandle init = IMPL_LOOKUP.findStatic(bcc, "init", MethodType.methodType(void.class)); + init.invokeExact(); // force initialization of the class + } catch (Throwable ex) { + throw uncaughtException(ex); + } + MethodHandle bccInvoker; + try { + MethodType invokerMT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class); + bccInvoker = IMPL_LOOKUP.findStatic(bcc, "invoke_V", invokerMT); + } catch (ReflectiveOperationException ex) { + throw uncaughtException(ex); + } + // Test the invoker, to ensure that it really injects into the right place. + try { + MethodHandle vamh = prepareForInvoker(MH_checkCallerClass); + Object ok = bccInvoker.invokeExact(vamh, new Object[]{hostClass, bcc}); + } catch (Throwable ex) { + throw new InternalError(ex); + } + return bccInvoker; + } + private static ClassValue CV_makeInjectedInvoker = new ClassValue() { + @Override protected MethodHandle computeValue(Class hostClass) { + return makeInjectedInvoker(hostClass); + } + }; + + // Adapt mh so that it can be called directly from an injected invoker: + private static MethodHandle prepareForInvoker(MethodHandle mh) { + mh = mh.asFixedArity(); + MethodType mt = mh.type(); + int arity = mt.parameterCount(); + MethodHandle vamh = mh.asType(mt.generic()); + vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames + vamh = vamh.asSpreader(Object[].class, arity); + vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames + return vamh; + } + + // Undo the adapter effect of prepareForInvoker: + private static MethodHandle restoreToType(MethodHandle vamh, MethodType type) { + return vamh.asCollector(Object[].class, type.parameterCount()).asType(type); + } + + private static final MethodHandle MH_checkCallerClass; + static { + final Class THIS_CLASS = BindCaller.class; + assert(checkCallerClass(THIS_CLASS, THIS_CLASS)); + try { + MH_checkCallerClass = IMPL_LOOKUP + .findStatic(THIS_CLASS, "checkCallerClass", + MethodType.methodType(boolean.class, Class.class, Class.class)); + assert((boolean) MH_checkCallerClass.invokeExact(THIS_CLASS, THIS_CLASS)); + } catch (Throwable ex) { + throw new InternalError(ex); + } + } + + private static boolean checkCallerClass(Class expected, Class expected2) { + final int FRAME_COUNT_ARG = 2; // [0] Reflection [1] BindCaller [2] Expected + Class actual = sun.reflect.Reflection.getCallerClass(FRAME_COUNT_ARG); + if (actual != expected && actual != expected2) + throw new InternalError("found "+actual.getName()+", expected "+expected.getName() + +(expected == expected2 ? "" : ", or else "+expected2.getName())); + return true; + } + + private static final byte[] T_BYTES; + static { + final Object[] values = {null}; + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + try { + Class tClass = T.class; + String tName = tClass.getName(); + String tResource = tName.substring(tName.lastIndexOf('.')+1)+".class"; + java.net.URLConnection uconn = tClass.getResource(tResource).openConnection(); + int len = uconn.getContentLength(); + byte[] bytes = new byte[len]; + try (java.io.InputStream str = uconn.getInputStream()) { + int nr = str.read(bytes); + if (nr != len) throw new java.io.IOException(tResource); + } + values[0] = bytes; + } catch (java.io.IOException ex) { + throw new InternalError(ex); + } + return null; + } + }); + T_BYTES = (byte[]) values[0]; + } + + // The following class is used as a template for Unsafe.defineAnonymousClass: + private static class T { + static void init() { } // side effect: initializes this class + static Object invoke_V(MethodHandle vamh, Object[] args) throws Throwable { + return vamh.invokeExact(args); + } + } + } } diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java index d27256fb337..06a9ba20e69 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java @@ -385,4 +385,101 @@ class MethodHandleNatives { throw err; } } + + /** + * Is this method a caller-sensitive method? + * I.e., does it call Reflection.getCallerClass or a similer method + * to ask about the identity of its caller? + */ + // FIXME: Replace this pattern match by an annotation @sun.reflect.CallerSensitive. + static boolean isCallerSensitive(MemberName mem) { + assert(mem.isInvocable()); + Class defc = mem.getDeclaringClass(); + switch (mem.getName()) { + case "doPrivileged": + return defc == java.security.AccessController.class; + case "getUnsafe": + return defc == sun.misc.Unsafe.class; + case "lookup": + return defc == java.lang.invoke.MethodHandles.class; + case "invoke": + return defc == java.lang.reflect.Method.class; + case "get": + case "getBoolean": + case "getByte": + case "getChar": + case "getShort": + case "getInt": + case "getLong": + case "getFloat": + case "getDouble": + case "set": + case "setBoolean": + case "setByte": + case "setChar": + case "setShort": + case "setInt": + case "setLong": + case "setFloat": + case "setDouble": + return defc == java.lang.reflect.Field.class; + case "newInstance": + if (defc == java.lang.reflect.Constructor.class) return true; + if (defc == java.lang.Class.class) return true; + break; + case "forName": + case "getClassLoader": + case "getClasses": + case "getFields": + case "getMethods": + case "getConstructors": + case "getDeclaredClasses": + case "getDeclaredFields": + case "getDeclaredMethods": + case "getDeclaredConstructors": + case "getField": + case "getMethod": + case "getConstructor": + case "getDeclaredField": + case "getDeclaredMethod": + case "getDeclaredConstructor": + return defc == java.lang.Class.class; + case "getConnection": + case "getDriver": + case "getDrivers": + case "deregisterDriver": + return defc == java.sql.DriverManager.class; + case "newUpdater": + if (defc == java.util.concurrent.atomic.AtomicIntegerFieldUpdater.class) return true; + if (defc == java.util.concurrent.atomic.AtomicLongFieldUpdater.class) return true; + if (defc == java.util.concurrent.atomic.AtomicReferenceFieldUpdater.class) return true; + break; + case "getContextClassLoader": + return defc == java.lang.Thread.class; + case "getPackage": + case "getPackages": + return defc == java.lang.Package.class; + case "getParent": + case "getSystemClassLoader": + return defc == java.lang.ClassLoader.class; + case "load": + case "loadLibrary": + if (defc == java.lang.Runtime.class) return true; + if (defc == java.lang.System.class) return true; + break; + case "getCallerClass": + if (defc == sun.reflect.Reflection.class) return true; + if (defc == java.lang.System.class) return true; + break; + case "getCallerClassLoader": + return defc == java.lang.ClassLoader.class; + case "getProxyClass": + case "newProxyInstance": + return defc == java.lang.reflect.Proxy.class; + case "getBundle": + case "clearCache": + return defc == java.util.ResourceBundle.class; + } + return false; + } } diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java index 3db5712fdeb..8a8eedfe1bf 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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,12 @@ import sun.misc.Unsafe; } // handy shared exception makers (they simplify the common case code) + /*non-public*/ static InternalError newInternalError(String message, Throwable cause) { + return new InternalError(message, cause); + } + /*non-public*/ static InternalError newInternalError(Throwable cause) { + return new InternalError(cause); + } /*non-public*/ static RuntimeException newIllegalStateException(String message) { return new IllegalStateException(message); } @@ -108,8 +114,8 @@ import sun.misc.Unsafe; /*non-public*/ static RuntimeException newIllegalArgumentException(String message, Object obj, Object obj2) { return new IllegalArgumentException(message(message, obj, obj2)); } - /*non-public*/ static Error uncaughtException(Exception ex) { - throw new InternalError("uncaught exception", ex); + /*non-public*/ static Error uncaughtException(Throwable ex) { + throw newInternalError("uncaught exception", ex); } static Error NYI() { throw new AssertionError("NYI"); diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java index 5c55f202353..e7007dd2b89 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -329,6 +329,7 @@ public class MethodHandles { * where {@code defcPkg} is the package of {@code defc}. * */ + // FIXME in MR1: clarify that the bytecode behavior of a caller-ID method (like Class.forName) is relative to the lookupClass used to create the method handle, not the dynamic caller of the method handle public static final class Lookup { /** The class on behalf of whom the lookup is being performed. */ @@ -1209,6 +1210,7 @@ return mh1; if (method.isMethodHandleInvoke()) return fakeMethodHandleInvoke(method); MethodHandle mh = DirectMethodHandle.make(refc, method); + mh = maybeBindCaller(method, mh); mh = mh.setVarargs(method); if (doRestrict) mh = restrictReceiver(method, mh, lookupClass()); @@ -1217,6 +1219,16 @@ return mh1; private MethodHandle fakeMethodHandleInvoke(MemberName method) { return throwException(method.getReturnType(), UnsupportedOperationException.class); } + private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh) throws IllegalAccessException { + if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method)) + return mh; + Class hostClass = lookupClass; + if ((allowedModes & PRIVATE) == 0) // caller must use full-power lookup + hostClass = null; + MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, hostClass); + // Note: caller will apply varargs after this step happens. + return cbmh; + } private MethodHandle getDirectField(byte refKind, Class refc, MemberName field) throws IllegalAccessException { checkField(refKind, refc, field); MethodHandle mh = DirectMethodHandle.make(refc, field); @@ -1229,6 +1241,7 @@ return mh1; private MethodHandle getDirectConstructor(Class refc, MemberName ctor) throws IllegalAccessException { assert(ctor.isConstructor()); checkAccess(REF_newInvokeSpecial, refc, ctor); + assert(!MethodHandleNatives.isCallerSensitive(ctor)); // maybeBindCaller not relevant here return DirectMethodHandle.make(ctor).setVarargs(ctor); } diff --git a/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java b/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java index 7495805947f..ce3647925a7 100644 --- a/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java +++ b/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java @@ -52,6 +52,7 @@ abstract class AbstractPlainSocketImpl extends SocketImpl private boolean shut_wr = false; private SocketInputStream socketInputStream = null; + private SocketOutputStream socketOutputStream = null; /* number of threads using the FileDescriptor */ protected int fdUseCount = 0; @@ -436,7 +437,10 @@ abstract class AbstractPlainSocketImpl extends SocketImpl if (shut_wr) { throw new IOException("Socket output is shutdown"); } - return new SocketOutputStream(this); + if (socketOutputStream == null) { + socketOutputStream = new SocketOutputStream(this); + } + return socketOutputStream; } void setFileDescriptor(FileDescriptor fd) { diff --git a/jdk/src/share/classes/java/net/ProxySelector.java b/jdk/src/share/classes/java/net/ProxySelector.java index 88f24a210ae..97d19a14269 100644 --- a/jdk/src/share/classes/java/net/ProxySelector.java +++ b/jdk/src/share/classes/java/net/ProxySelector.java @@ -127,7 +127,6 @@ public abstract class ProxySelector { *
      *
    • http URI for http connections
    • *
    • https URI for https connections - *
    • ftp URI for ftp connections
    • *
    • socket://host:port
      * for tcp client sockets connections
    • *
    diff --git a/jdk/src/share/classes/java/net/URL.java b/jdk/src/share/classes/java/net/URL.java index e7e9ddacc4c..5cb3f6d6324 100644 --- a/jdk/src/share/classes/java/net/URL.java +++ b/jdk/src/share/classes/java/net/URL.java @@ -274,7 +274,7 @@ public final class URL implements java.io.Serializable { *

    Protocol handlers for the following protocols are guaranteed * to exist on the search path :- *

    -     *     http, https, ftp, file, and jar
    +     *     http, https, file, and jar
          * 
    * Protocol handlers for additional protocols may also be * available. diff --git a/jdk/src/share/classes/java/net/URLStreamHandler.java b/jdk/src/share/classes/java/net/URLStreamHandler.java index c98588a0e65..ba7fa263cec 100644 --- a/jdk/src/share/classes/java/net/URLStreamHandler.java +++ b/jdk/src/share/classes/java/net/URLStreamHandler.java @@ -37,8 +37,7 @@ import sun.net.www.ParseUtil; * The abstract class URLStreamHandler is the common * superclass for all stream protocol handlers. A stream protocol * handler knows how to make a connection for a particular protocol - * type, such as http, ftp, or - * gopher. + * type, such as http or https. *

    * In most cases, an instance of a URLStreamHandler * subclass is not created directly by an application. Rather, the diff --git a/jdk/src/share/classes/java/net/package.html b/jdk/src/share/classes/java/net/package.html index b5bd261be9f..2cd8a249414 100644 --- a/jdk/src/share/classes/java/net/package.html +++ b/jdk/src/share/classes/java/net/package.html @@ -72,7 +72,7 @@ Provides the classes for implementing networking applications.

    • {@link java.net.URI} is the class representing a Universal Resource Identifier, as specified in RFC 2396. As the name indicates, this is just an Identifier and doesn't provide directly the means to access the resource.
    • {@link java.net.URL} is the class representing a Universal Resource Locator, which is both an older concept for URIs and a means to access the resources.
    • -
    • {@link java.net.URLConnection} is created from a URL and is the communication link used to access the resource pointed by the URL. This abstract class will delegate most of the work to the underlying protocol handlers like http or ftp.
    • +
    • {@link java.net.URLConnection} is created from a URL and is the communication link used to access the resource pointed by the URL. This abstract class will delegate most of the work to the underlying protocol handlers like http or https.
    • {@link java.net.HttpURLConnection} is a subclass of URLConnection and provides some additional functionalities specific to the HTTP protocol.

    The recommended usage is to use {@link java.net.URI} to identify resources, then convert it into a {@link java.net.URL} when it is time to access the resource. From that URL, you can either get the {@link java.net.URLConnection} for fine control, or get directly the InputStream.

    diff --git a/jdk/src/share/classes/java/security/AccessController.java b/jdk/src/share/classes/java/security/AccessController.java index 97383f54a46..4e790ffc8da 100644 --- a/jdk/src/share/classes/java/security/AccessController.java +++ b/jdk/src/share/classes/java/security/AccessController.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 @@ -290,11 +290,11 @@ public final class AccessController { */ public static T doPrivilegedWithCombiner(PrivilegedAction action) { - DomainCombiner dc = null; AccessControlContext acc = getStackAccessControlContext(); - if (acc == null || (dc = acc.getAssignedCombiner()) == null) { + if (acc == null) { return AccessController.doPrivileged(action); } + DomainCombiner dc = acc.getAssignedCombiner(); return AccessController.doPrivileged(action, preserveCombiner(dc)); } @@ -386,11 +386,11 @@ public final class AccessController { public static T doPrivilegedWithCombiner (PrivilegedExceptionAction action) throws PrivilegedActionException { - DomainCombiner dc = null; AccessControlContext acc = getStackAccessControlContext(); - if (acc == null || (dc = acc.getAssignedCombiner()) == null) { + if (acc == null) { return AccessController.doPrivileged(action); } + DomainCombiner dc = acc.getAssignedCombiner(); return AccessController.doPrivileged(action, preserveCombiner(dc)); } @@ -417,7 +417,12 @@ public final class AccessController { // perform 'combine' on the caller of doPrivileged, // even if the caller is from the bootclasspath ProtectionDomain[] pds = new ProtectionDomain[] {callerPd}; - return new AccessControlContext(combiner.combine(pds, null), combiner); + if (combiner == null) { + return new AccessControlContext(pds); + } else { + return new AccessControlContext(combiner.combine(pds, null), + combiner); + } } diff --git a/jdk/src/share/classes/java/sql/CallableStatement.java b/jdk/src/share/classes/java/sql/CallableStatement.java index 460b0285894..2813b6cc27e 100644 --- a/jdk/src/share/classes/java/sql/CallableStatement.java +++ b/jdk/src/share/classes/java/sql/CallableStatement.java @@ -295,6 +295,7 @@ public interface CallableStatement extends PreparedStatement { * or getBigDecimal(String parameterName) * @see #setBigDecimal */ + @Deprecated BigDecimal getBigDecimal(int parameterIndex, int scale) throws SQLException; diff --git a/jdk/src/share/classes/java/sql/Date.java b/jdk/src/share/classes/java/sql/Date.java index de39d148502..5d6cd6baf11 100644 --- a/jdk/src/share/classes/java/sql/Date.java +++ b/jdk/src/share/classes/java/sql/Date.java @@ -51,6 +51,7 @@ public class Date extends java.util.Date { * @param day 1 to 31 * @deprecated instead use the constructor Date(long date) */ + @Deprecated public Date(int year, int month, int day) { super(year, month, day); } @@ -179,6 +180,7 @@ public class Date extends java.util.Date { * @exception java.lang.IllegalArgumentException if this method is invoked * @see #setHours */ + @Deprecated public int getHours() { throw new java.lang.IllegalArgumentException(); } @@ -191,6 +193,7 @@ public class Date extends java.util.Date { * @exception java.lang.IllegalArgumentException if this method is invoked * @see #setMinutes */ + @Deprecated public int getMinutes() { throw new java.lang.IllegalArgumentException(); } @@ -203,6 +206,7 @@ public class Date extends java.util.Date { * @exception java.lang.IllegalArgumentException if this method is invoked * @see #setSeconds */ + @Deprecated public int getSeconds() { throw new java.lang.IllegalArgumentException(); } @@ -215,6 +219,7 @@ public class Date extends java.util.Date { * @exception java.lang.IllegalArgumentException if this method is invoked * @see #getHours */ + @Deprecated public void setHours(int i) { throw new java.lang.IllegalArgumentException(); } @@ -227,6 +232,7 @@ public class Date extends java.util.Date { * @exception java.lang.IllegalArgumentException if this method is invoked * @see #getMinutes */ + @Deprecated public void setMinutes(int i) { throw new java.lang.IllegalArgumentException(); } @@ -239,6 +245,7 @@ public class Date extends java.util.Date { * @exception java.lang.IllegalArgumentException if this method is invoked * @see #getSeconds */ + @Deprecated public void setSeconds(int i) { throw new java.lang.IllegalArgumentException(); } diff --git a/jdk/src/share/classes/java/sql/DriverManager.java b/jdk/src/share/classes/java/sql/DriverManager.java index 819544a1558..4021fa24435 100644 --- a/jdk/src/share/classes/java/sql/DriverManager.java +++ b/jdk/src/share/classes/java/sql/DriverManager.java @@ -412,13 +412,14 @@ public class DriverManager { * method throws a java.lang.SecurityException. * * @param out the new logging/tracing PrintStream; to disable, set to null - * @deprecated + * @deprecated Use {@code setLogWriter} * @throws SecurityException if a security manager exists and its * checkPermission method denies setting the log stream * * @see SecurityManager#checkPermission * @see #getLogStream */ + @Deprecated public static void setLogStream(java.io.PrintStream out) { SecurityManager sec = System.getSecurityManager(); @@ -438,9 +439,10 @@ public class DriverManager { * and all drivers. * * @return the logging/tracing PrintStream; if disabled, is null - * @deprecated + * @deprecated Use {@code getLogWriter} * @see #setLogStream */ + @Deprecated public static java.io.PrintStream getLogStream() { return logStream; } diff --git a/jdk/src/share/classes/java/sql/PreparedStatement.java b/jdk/src/share/classes/java/sql/PreparedStatement.java index 8d6ca60360c..d67505f4f94 100644 --- a/jdk/src/share/classes/java/sql/PreparedStatement.java +++ b/jdk/src/share/classes/java/sql/PreparedStatement.java @@ -342,8 +342,9 @@ public interface PreparedStatement extends Statement { * this method is called on a closed PreparedStatement * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @deprecated + * @deprecated Use {@code setCharacterStream} */ + @Deprecated void setUnicodeStream(int parameterIndex, java.io.InputStream x, int length) throws SQLException; diff --git a/jdk/src/share/classes/java/sql/ResultSet.java b/jdk/src/share/classes/java/sql/ResultSet.java index fc4dbf6b476..3904a2ed607 100644 --- a/jdk/src/share/classes/java/sql/ResultSet.java +++ b/jdk/src/share/classes/java/sql/ResultSet.java @@ -356,8 +356,10 @@ public interface ResultSet extends Wrapper, AutoCloseable { * called on a closed result set * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @deprecated + * @deprecated Use {@code getBigDecimal(int columnIndex)} + * or {@code getBigDecimal(String columnLabel)} */ + @Deprecated BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException; /** @@ -477,6 +479,7 @@ public interface ResultSet extends Wrapper, AutoCloseable { * @deprecated use getCharacterStream in place of * getUnicodeStream */ + @Deprecated java.io.InputStream getUnicodeStream(int columnIndex) throws SQLException; /** @@ -641,8 +644,10 @@ public interface ResultSet extends Wrapper, AutoCloseable { * called on a closed result set * @exception SQLFeatureNotSupportedException if the JDBC driver does not support * this method - * @deprecated + * @deprecated Use {@code getBigDecimal(int columnIndex)} + * or {@code getBigDecimal(String columnLabel)} */ + @Deprecated BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException; /** @@ -760,6 +765,7 @@ public interface ResultSet extends Wrapper, AutoCloseable { * this method * @deprecated use getCharacterStream instead */ + @Deprecated java.io.InputStream getUnicodeStream(String columnLabel) throws SQLException; /** diff --git a/jdk/src/share/classes/java/text/DateFormatSymbols.java b/jdk/src/share/classes/java/text/DateFormatSymbols.java index 3e701b13799..ee688abd9b6 100644 --- a/jdk/src/share/classes/java/text/DateFormatSymbols.java +++ b/jdk/src/share/classes/java/text/DateFormatSymbols.java @@ -45,6 +45,7 @@ import java.lang.ref.SoftReference; import java.text.spi.DateFormatSymbolsProvider; import java.util.Arrays; import java.util.Locale; +import java.util.Objects; import java.util.ResourceBundle; import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; @@ -366,6 +367,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { */ public void setEras(String[] newEras) { eras = Arrays.copyOf(newEras, newEras.length); + cachedHashCode = 0; } /** @@ -393,6 +395,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { */ public void setMonths(String[] newMonths) { months = Arrays.copyOf(newMonths, newMonths.length); + cachedHashCode = 0; } /** @@ -420,6 +423,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { */ public void setShortMonths(String[] newShortMonths) { shortMonths = Arrays.copyOf(newShortMonths, newShortMonths.length); + cachedHashCode = 0; } /** @@ -439,6 +443,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { */ public void setWeekdays(String[] newWeekdays) { weekdays = Arrays.copyOf(newWeekdays, newWeekdays.length); + cachedHashCode = 0; } /** @@ -458,6 +463,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { */ public void setShortWeekdays(String[] newShortWeekdays) { shortWeekdays = Arrays.copyOf(newShortWeekdays, newShortWeekdays.length); + cachedHashCode = 0; } /** @@ -474,6 +480,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { */ public void setAmPmStrings(String[] newAmpms) { ampms = Arrays.copyOf(newAmpms, newAmpms.length); + cachedHashCode = 0; } /** @@ -558,6 +565,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { } zoneStrings = aCopy; isZoneStringsSet = true; + cachedHashCode = 0; } /** @@ -576,6 +584,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { public void setLocalPatternChars(String newLocalPatternChars) { // Call toString() to throw an NPE in case the argument is null localPatternChars = newLocalPatternChars.toString(); + cachedHashCode = 0; } /** @@ -597,12 +606,23 @@ public class DateFormatSymbols implements Serializable, Cloneable { * Override hashCode. * Generates a hash code for the DateFormatSymbols object. */ + @Override public int hashCode() { - int hashcode = 0; - String[][] zoneStrings = getZoneStringsWrapper(); - for (int index = 0; index < zoneStrings[0].length; ++index) - hashcode ^= zoneStrings[0][index].hashCode(); - return hashcode; + int hashCode = cachedHashCode; + if (hashCode == 0) { + hashCode = 5; + hashCode = 11 * hashCode + Arrays.hashCode(eras); + hashCode = 11 * hashCode + Arrays.hashCode(months); + hashCode = 11 * hashCode + Arrays.hashCode(shortMonths); + hashCode = 11 * hashCode + Arrays.hashCode(weekdays); + hashCode = 11 * hashCode + Arrays.hashCode(shortWeekdays); + hashCode = 11 * hashCode + Arrays.hashCode(ampms); + hashCode = 11 * hashCode + Arrays.deepHashCode(getZoneStringsWrapper()); + hashCode = 11 * hashCode + Objects.hashCode(localPatternChars); + cachedHashCode = hashCode; + } + + return hashCode; } /** @@ -641,6 +661,11 @@ public class DateFormatSymbols implements Serializable, Cloneable { private transient int lastZoneIndex = 0; + /** + * Cached hash code + */ + transient volatile int cachedHashCode = 0; + private void initializeData(Locale desiredLocale) { locale = desiredLocale; @@ -782,6 +807,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { dst.zoneStrings = null; } dst.localPatternChars = src.localPatternChars; + dst.cachedHashCode = 0; } /** diff --git a/jdk/src/share/classes/java/util/Hashtable.java b/jdk/src/share/classes/java/util/Hashtable.java index f82c300838e..785b2668aa3 100644 --- a/jdk/src/share/classes/java/util/Hashtable.java +++ b/jdk/src/share/classes/java/util/Hashtable.java @@ -1059,7 +1059,7 @@ public class Hashtable } public int hashCode() { - return hash ^ (value==null ? 0 : value.hashCode()); + return (Objects.hashCode(key) ^ Objects.hashCode(value)); } public String toString() { diff --git a/jdk/src/share/classes/java/util/Properties.java b/jdk/src/share/classes/java/util/Properties.java index c8bdab7c273..e084479c6d9 100644 --- a/jdk/src/share/classes/java/util/Properties.java +++ b/jdk/src/share/classes/java/util/Properties.java @@ -81,8 +81,9 @@ import sun.util.spi.XmlPropertiesProvider; *

    The {@link #loadFromXML(InputStream)} and {@link * #storeToXML(OutputStream, String, String)} methods load and store properties * in a simple XML format. By default the UTF-8 character encoding is used, - * however a specific encoding may be specified if required. An XML properties - * document has the following DOCTYPE declaration: + * however a specific encoding may be specified if required. Implementations + * are required to support UTF-8 and UTF-16 and may support other encodings. + * An XML properties document has the following DOCTYPE declaration: * *

      * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
    @@ -853,23 +854,30 @@ class Properties extends Hashtable {
          * Furthermore, the document must satisfy the properties DTD described
          * above.
          *
    +     * 

    An implementation is required to read XML documents that use the + * "{@code UTF-8}" or "{@code UTF-16}" encoding. An implementation may + * support additional encodings. + * *

    The specified stream is closed after this method returns. * * @param in the input stream from which to read the XML document. * @throws IOException if reading from the specified input stream * results in an IOException. + * @throws java.io.UnsupportedEncodingException if the document's encoding + * declaration can be read and it specifies an encoding that is not + * supported * @throws InvalidPropertiesFormatException Data on input stream does not * constitute a valid XML document with the mandated document type. * @throws NullPointerException if {@code in} is null. * @see #storeToXML(OutputStream, String, String) + * @see Character + * Encoding in Entities * @since 1.5 */ public synchronized void loadFromXML(InputStream in) throws IOException, InvalidPropertiesFormatException { - if (in == null) - throw new NullPointerException(); - XmlSupport.load(this, in); + XmlSupport.load(this, Objects.requireNonNull(in)); in.close(); } @@ -896,8 +904,6 @@ class Properties extends Hashtable { public void storeToXML(OutputStream os, String comment) throws IOException { - if (os == null) - throw new NullPointerException(); storeToXML(os, comment, "UTF-8"); } @@ -910,9 +916,13 @@ class Properties extends Hashtable { * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> *

    * - *

    If the specified comment is {@code null} then no comment + *

    If the specified comment is {@code null} then no comment * will be stored in the document. * + *

    An implementation is required to support writing of XML documents + * that use the "{@code UTF-8}" or "{@code UTF-16}" encoding. An + * implementation may support additional encodings. + * *

    The specified stream remains open after this method returns. * * @param os the output stream on which to emit the XML document. @@ -924,20 +934,23 @@ class Properties extends Hashtable { * * @throws IOException if writing to the specified output stream * results in an IOException. + * @throws java.io.UnsupportedEncodingException if the encoding is not + * supported by the implementation. * @throws NullPointerException if {@code os} is {@code null}, * or if {@code encoding} is {@code null}. * @throws ClassCastException if this {@code Properties} object * contains any keys or values that are not * {@code Strings}. * @see #loadFromXML(InputStream) + * @see Character + * Encoding in Entities * @since 1.5 */ public void storeToXML(OutputStream os, String comment, String encoding) throws IOException { - if (os == null) - throw new NullPointerException(); - XmlSupport.save(this, os, comment, encoding); + XmlSupport.save(this, Objects.requireNonNull(os), comment, + Objects.requireNonNull(encoding)); } /** diff --git a/jdk/src/share/classes/java/util/ServiceLoader.java b/jdk/src/share/classes/java/util/ServiceLoader.java index 067537a213d..01a5f440feb 100644 --- a/jdk/src/share/classes/java/util/ServiceLoader.java +++ b/jdk/src/share/classes/java/util/ServiceLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -214,7 +214,7 @@ public final class ServiceLoader private ServiceLoader(Class svc, ClassLoader cl) { service = Objects.requireNonNull(svc, "Service interface cannot be null"); - loader = cl; + loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl; reload(); } @@ -358,14 +358,21 @@ public final class ServiceLoader } String cn = nextName; nextName = null; + Class c = null; try { - S p = service.cast(Class.forName(cn, true, loader) - .newInstance()); - providers.put(cn, p); - return p; + c = Class.forName(cn, false, loader); } catch (ClassNotFoundException x) { fail(service, "Provider " + cn + " not found"); + } + if (!service.isAssignableFrom(c)) { + fail(service, + "Provider " + cn + " not a subtype"); + } + try { + S p = service.cast(c.newInstance()); + providers.put(cn, p); + return p; } catch (Throwable x) { fail(service, "Provider " + cn + " could not be instantiated: " + x, diff --git a/jdk/src/share/classes/java/util/TimeZone.java b/jdk/src/share/classes/java/util/TimeZone.java index 648191a471a..13ede9c2a12 100644 --- a/jdk/src/share/classes/java/util/TimeZone.java +++ b/jdk/src/share/classes/java/util/TimeZone.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -719,15 +719,16 @@ abstract public class TimeZone implements Serializable, Cloneable { * Returns the default TimeZone in an AppContext if any AppContext * has ever used. null is returned if any AppContext hasn't been * used or if the AppContext doesn't have the default TimeZone. + * + * Note that javaAWTAccess may be null if sun.awt.AppContext class hasn't + * been loaded. If so, it implies that AWTSecurityManager is not our + * SecurityManager and we can use a local static variable. + * This works around a build time issue. */ - private synchronized static TimeZone getDefaultInAppContext() { + private static TimeZone getDefaultInAppContext() { // JavaAWTAccess provides access implementation-private methods without using reflection. JavaAWTAccess javaAWTAccess = SharedSecrets.getJavaAWTAccess(); - // Note that javaAWTAccess may be null if sun.awt.AppContext class hasn't - // been loaded. If so, it implies that AWTSecurityManager is not our - // SecurityManager and we can use a local static variable. - // This works around a build time issue. if (javaAWTAccess == null) { return mainAppContextDefault; } else { @@ -749,15 +750,16 @@ abstract public class TimeZone implements Serializable, Cloneable { * tz. null is handled special: do nothing if any AppContext * hasn't been used, remove the default TimeZone in the * AppContext otherwise. + * + * Note that javaAWTAccess may be null if sun.awt.AppContext class hasn't + * been loaded. If so, it implies that AWTSecurityManager is not our + * SecurityManager and we can use a local static variable. + * This works around a build time issue. */ - private synchronized static void setDefaultInAppContext(TimeZone tz) { + private static void setDefaultInAppContext(TimeZone tz) { // JavaAWTAccess provides access implementation-private methods without using reflection. JavaAWTAccess javaAWTAccess = SharedSecrets.getJavaAWTAccess(); - // Note that javaAWTAccess may be null if sun.awt.AppContext class hasn't - // been loaded. If so, it implies that AWTSecurityManager is not our - // SecurityManager and we can use a local static variable. - // This works around a build time issue. if (javaAWTAccess == null) { mainAppContextDefault = tz; } else { @@ -822,7 +824,7 @@ abstract public class TimeZone implements Serializable, Cloneable { private static final int GMT_ID_LENGTH = 3; // a static TimeZone we can reference if no AppContext is in place - private static TimeZone mainAppContextDefault; + private static volatile TimeZone mainAppContextDefault; /** * Parses a custom time zone identifier and returns a corresponding zone. diff --git a/jdk/src/share/classes/java/util/concurrent/Executors.java b/jdk/src/share/classes/java/util/concurrent/Executors.java index 4ff71418422..78708f8d773 100644 --- a/jdk/src/share/classes/java/util/concurrent/Executors.java +++ b/jdk/src/share/classes/java/util/concurrent/Executors.java @@ -530,18 +530,17 @@ public class Executors { return AccessController.doPrivileged( new PrivilegedExceptionAction() { public T run() throws Exception { - ClassLoader savedcl = null; Thread t = Thread.currentThread(); - try { - ClassLoader cl = t.getContextClassLoader(); - if (ccl != cl) { - t.setContextClassLoader(ccl); - savedcl = cl; - } + ClassLoader cl = t.getContextClassLoader(); + if (ccl == cl) { return task.call(); - } finally { - if (savedcl != null) - t.setContextClassLoader(savedcl); + } else { + t.setContextClassLoader(ccl); + try { + return task.call(); + } finally { + t.setContextClassLoader(cl); + } } } }, acc); diff --git a/jdk/src/share/classes/java/util/jar/Pack200.java b/jdk/src/share/classes/java/util/jar/Pack200.java index 0f28a14b527..6f244f37725 100644 --- a/jdk/src/share/classes/java/util/jar/Pack200.java +++ b/jdk/src/share/classes/java/util/jar/Pack200.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003,2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -456,12 +456,12 @@ public abstract class Pack200 { * The unpacker's progress as a percentage, as periodically * updated by the unpacker. * Values of 0 - 100 are normal, and -1 indicates a stall. - * Observe this property with a {@link PropertyChangeListener}. + * Progress can be monitored by polling the value of this + * property. *

    * At a minimum, the unpacker must set progress to 0 * at the beginning of a packing operation, and to 100 * at the end. - * @see #addPropertyChangeListener */ String PROGRESS = "pack.progress"; @@ -577,7 +577,15 @@ public abstract class Pack200 { * @see #properties * @see #PROGRESS * @param listener An object to be invoked when a property is changed. + * @deprecated The dependency on {@code PropertyChangeListener} creates + * a significant impediment to future modularization of the + * Java platform. This method will be removed in a future + * release. + * Applications that need to monitor progress of the packer + * can poll the value of the {@link #PROGRESS PROGRESS} + * property instead. */ + @Deprecated void addPropertyChangeListener(PropertyChangeListener listener) ; /** @@ -586,7 +594,12 @@ public abstract class Pack200 { * * @see #addPropertyChangeListener * @param listener The PropertyChange listener to be removed. + * @deprecated The dependency on {@code PropertyChangeListener} creates + * a significant impediment to future modularization of the + * Java platform. This method will be removed in a future + * release. */ + @Deprecated void removePropertyChangeListener(PropertyChangeListener listener); } @@ -640,12 +653,12 @@ public abstract class Pack200 { * The unpacker's progress as a percentage, as periodically * updated by the unpacker. * Values of 0 - 100 are normal, and -1 indicates a stall. - * Observe this property with a {@link PropertyChangeListener}. + * Progress can be monitored by polling the value of this + * property. *

    * At a minimum, the unpacker must set progress to 0 * at the beginning of a packing operation, and to 100 * at the end. - * @see #addPropertyChangeListener */ String PROGRESS = "unpack.progress"; @@ -708,7 +721,15 @@ public abstract class Pack200 { * @see #properties * @see #PROGRESS * @param listener An object to be invoked when a property is changed. + * @deprecated The dependency on {@code PropertyChangeListener} creates + * a significant impediment to future modularization of the + * Java platform. This method will be removed in a future + * release. + * Applications that need to monitor progress of the + * unpacker can poll the value of the {@link #PROGRESS + * PROGRESS} property instead. */ + @Deprecated void addPropertyChangeListener(PropertyChangeListener listener) ; /** @@ -717,7 +738,12 @@ public abstract class Pack200 { * * @see #addPropertyChangeListener * @param listener The PropertyChange listener to be removed. + * @deprecated The dependency on {@code PropertyChangeListener} creates + * a significant impediment to future modularization of the + * Java platform. This method will be removed in a future + * release. */ + @Deprecated void removePropertyChangeListener(PropertyChangeListener listener); } diff --git a/jdk/src/share/classes/java/util/logging/FileHandler.java b/jdk/src/share/classes/java/util/logging/FileHandler.java index fb3b67c4d92..b9a5d73c341 100644 --- a/jdk/src/share/classes/java/util/logging/FileHandler.java +++ b/jdk/src/share/classes/java/util/logging/FileHandler.java @@ -220,7 +220,7 @@ public class FileHandler extends StreamHandler { * @exception NullPointerException if pattern property is an empty String. */ public FileHandler() throws IOException, SecurityException { - checkAccess(); + checkPermission(); configure(); openFiles(); } @@ -246,7 +246,7 @@ public class FileHandler extends StreamHandler { if (pattern.length() < 1 ) { throw new IllegalArgumentException(); } - checkAccess(); + checkPermission(); configure(); this.pattern = pattern; this.limit = 0; @@ -278,7 +278,7 @@ public class FileHandler extends StreamHandler { if (pattern.length() < 1 ) { throw new IllegalArgumentException(); } - checkAccess(); + checkPermission(); configure(); this.pattern = pattern; this.limit = 0; @@ -315,7 +315,7 @@ public class FileHandler extends StreamHandler { if (limit < 0 || count < 1 || pattern.length() < 1) { throw new IllegalArgumentException(); } - checkAccess(); + checkPermission(); configure(); this.pattern = pattern; this.limit = limit; @@ -354,7 +354,7 @@ public class FileHandler extends StreamHandler { if (limit < 0 || count < 1 || pattern.length() < 1) { throw new IllegalArgumentException(); } - checkAccess(); + checkPermission(); configure(); this.pattern = pattern; this.limit = limit; @@ -367,7 +367,7 @@ public class FileHandler extends StreamHandler { // configured instance variables. private void openFiles() throws IOException { LogManager manager = LogManager.getLogManager(); - manager.checkAccess(); + manager.checkPermission(); if (count < 1) { throw new IllegalArgumentException("file count = " + count); } diff --git a/jdk/src/share/classes/java/util/logging/Handler.java b/jdk/src/share/classes/java/util/logging/Handler.java index 1317b572d92..fd04c2cb496 100644 --- a/jdk/src/share/classes/java/util/logging/Handler.java +++ b/jdk/src/share/classes/java/util/logging/Handler.java @@ -111,7 +111,7 @@ public abstract class Handler { * the caller does not have LoggingPermission("control"). */ public void setFormatter(Formatter newFormatter) throws SecurityException { - checkAccess(); + checkPermission(); // Check for a null pointer: newFormatter.getClass(); formatter = newFormatter; @@ -140,7 +140,7 @@ public abstract class Handler { */ public void setEncoding(String encoding) throws SecurityException, java.io.UnsupportedEncodingException { - checkAccess(); + checkPermission(); if (encoding != null) { try { if(!java.nio.charset.Charset.isSupported(encoding)) { @@ -175,7 +175,7 @@ public abstract class Handler { * the caller does not have LoggingPermission("control"). */ public void setFilter(Filter newFilter) throws SecurityException { - checkAccess(); + checkPermission(); filter = newFilter; } @@ -199,7 +199,7 @@ public abstract class Handler { * the caller does not have LoggingPermission("control"). */ public void setErrorManager(ErrorManager em) { - checkAccess(); + checkPermission(); if (em == null) { throw new NullPointerException(); } @@ -213,7 +213,7 @@ public abstract class Handler { * the caller does not have LoggingPermission("control"). */ public ErrorManager getErrorManager() { - checkAccess(); + checkPermission(); return errorManager; } @@ -253,7 +253,7 @@ public abstract class Handler { if (newLevel == null) { throw new NullPointerException(); } - checkAccess(); + checkPermission(); logLevel = newLevel; } @@ -296,9 +296,9 @@ public abstract class Handler { // If "sealed" is true, we check that the caller has // appropriate security privileges to update Handler // state and if not throw a SecurityException. - void checkAccess() throws SecurityException { + void checkPermission() throws SecurityException { if (sealed) { - manager.checkAccess(); + manager.checkPermission(); } } } diff --git a/jdk/src/share/classes/java/util/logging/LogManager.java b/jdk/src/share/classes/java/util/logging/LogManager.java index 24f61b46f74..a100eb9d989 100644 --- a/jdk/src/share/classes/java/util/logging/LogManager.java +++ b/jdk/src/share/classes/java/util/logging/LogManager.java @@ -311,10 +311,17 @@ public class LogManager { * @exception SecurityException if a security manager exists and if * the caller does not have LoggingPermission("control"). * @exception NullPointerException if the PropertyChangeListener is null. + * @deprecated The dependency on {@code PropertyChangeListener} creates a + * significant impediment to future modularization of the Java + * platform. This method will be removed in a future release. + * The global {@code LogManager} can detect changes to the + * logging configuration by overridding the {@link + * #readConfiguration readConfiguration} method. */ + @Deprecated public void addPropertyChangeListener(PropertyChangeListener l) throws SecurityException { PropertyChangeListener listener = Objects.requireNonNull(l); - checkAccess(); + checkPermission(); synchronized (listenerMap) { // increment the registration count if already registered Integer value = listenerMap.get(listener); @@ -336,9 +343,16 @@ public class LogManager { * @param l event listener (can be null) * @exception SecurityException if a security manager exists and if * the caller does not have LoggingPermission("control"). + * @deprecated The dependency on {@code PropertyChangeListener} creates a + * significant impediment to future modularization of the Java + * platform. This method will be removed in a future release. + * The global {@code LogManager} can detect changes to the + * logging configuration by overridding the {@link + * #readConfiguration readConfiguration} method. */ + @Deprecated public void removePropertyChangeListener(PropertyChangeListener l) throws SecurityException { - checkAccess(); + checkPermission(); if (l != null) { PropertyChangeListener listener = l; synchronized (listenerMap) { @@ -793,7 +807,7 @@ public class LogManager { * @exception IOException if there are IO problems reading the configuration. */ public void readConfiguration() throws IOException, SecurityException { - checkAccess(); + checkPermission(); // if a configuration class is specified, load it and use it. String cname = System.getProperty("java.util.logging.config.class"); @@ -851,7 +865,7 @@ public class LogManager { */ public void reset() throws SecurityException { - checkAccess(); + checkPermission(); synchronized (this) { props = new Properties(); // Since we are doing a reset we no longer want to initialize @@ -936,7 +950,7 @@ public class LogManager { * @exception IOException if there are problems reading from the stream. */ public void readConfiguration(InputStream ins) throws IOException, SecurityException { - checkAccess(); + checkPermission(); reset(); // Load the properties @@ -1113,8 +1127,13 @@ public class LogManager { loadLoggerHandlers(rootLogger, null, "handlers"); } + private final Permission controlPermission = new LoggingPermission("control", null); - private Permission ourPermission = new LoggingPermission("control", null); + void checkPermission() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(controlPermission); + } /** * Check that the current context is trusted to modify the logging @@ -1127,11 +1146,7 @@ public class LogManager { * the caller does not have LoggingPermission("control"). */ public void checkAccess() throws SecurityException { - SecurityManager sm = System.getSecurityManager(); - if (sm == null) { - return; - } - sm.checkPermission(ourPermission); + checkPermission(); } // Nested class to represent a node in our tree of named loggers. diff --git a/jdk/src/share/classes/java/util/logging/Logger.java b/jdk/src/share/classes/java/util/logging/Logger.java index aebf63ed5e8..f1d6f729b91 100644 --- a/jdk/src/share/classes/java/util/logging/Logger.java +++ b/jdk/src/share/classes/java/util/logging/Logger.java @@ -276,13 +276,13 @@ public class Logger { this.manager = manager; } - private void checkAccess() throws SecurityException { + private void checkPermission() throws SecurityException { if (!anonymous) { if (manager == null) { // Complete initialization of the global Logger. manager = LogManager.getLogManager(); } - manager.checkAccess(); + manager.checkPermission(); } } @@ -482,7 +482,7 @@ public class Logger { * the caller does not have LoggingPermission("control"). */ public void setFilter(Filter newFilter) throws SecurityException { - checkAccess(); + checkPermission(); filter = newFilter; } @@ -1168,7 +1168,7 @@ public class Logger { * the caller does not have LoggingPermission("control"). */ public void setLevel(Level newLevel) throws SecurityException { - checkAccess(); + checkPermission(); synchronized (treeLock) { levelObject = newLevel; updateEffectiveLevel(); @@ -1223,7 +1223,7 @@ public class Logger { public void addHandler(Handler handler) throws SecurityException { // Check for null handler handler.getClass(); - checkAccess(); + checkPermission(); handlers.add(handler); } @@ -1237,7 +1237,7 @@ public class Logger { * the caller does not have LoggingPermission("control"). */ public void removeHandler(Handler handler) throws SecurityException { - checkAccess(); + checkPermission(); if (handler == null) { return; } @@ -1265,7 +1265,7 @@ public class Logger { * the caller does not have LoggingPermission("control"). */ public void setUseParentHandlers(boolean useParentHandlers) { - checkAccess(); + checkPermission(); this.useParentHandlers = useParentHandlers; } @@ -1420,7 +1420,7 @@ public class Logger { if (parent == null) { throw new NullPointerException(); } - manager.checkAccess(); + manager.checkPermission(); doSetParent(parent); } diff --git a/jdk/src/share/classes/java/util/logging/MemoryHandler.java b/jdk/src/share/classes/java/util/logging/MemoryHandler.java index 2c297301d92..06c0930ed5c 100644 --- a/jdk/src/share/classes/java/util/logging/MemoryHandler.java +++ b/jdk/src/share/classes/java/util/logging/MemoryHandler.java @@ -238,7 +238,7 @@ public class MemoryHandler extends Handler { throw new NullPointerException(); } LogManager manager = LogManager.getLogManager(); - checkAccess(); + checkPermission(); pushLevel = newLevel; } diff --git a/jdk/src/share/classes/java/util/logging/StreamHandler.java b/jdk/src/share/classes/java/util/logging/StreamHandler.java index 9ed9e57b768..f6407ec2bfd 100644 --- a/jdk/src/share/classes/java/util/logging/StreamHandler.java +++ b/jdk/src/share/classes/java/util/logging/StreamHandler.java @@ -249,7 +249,7 @@ public class StreamHandler extends Handler { } private synchronized void flushAndClose() throws SecurityException { - checkAccess(); + checkPermission(); if (writer != null) { try { if (!doneHeader) { diff --git a/jdk/src/share/classes/javax/management/modelmbean/DescriptorSupport.java b/jdk/src/share/classes/javax/management/modelmbean/DescriptorSupport.java index 57b4b46365e..068047967ea 100644 --- a/jdk/src/share/classes/javax/management/modelmbean/DescriptorSupport.java +++ b/jdk/src/share/classes/javax/management/modelmbean/DescriptorSupport.java @@ -1245,13 +1245,12 @@ public class DescriptorSupport return s.substring(1, s.length() - 1); } final String className = s.substring(1, slash); + final Constructor constr; try { + ReflectUtil.checkPackageAccess(className); final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - if (contextClassLoader == null) { - ReflectUtil.checkPackageAccess(className); - } final Class c = Class.forName(className, false, contextClassLoader); constr = c.getConstructor(new Class[] {String.class}); diff --git a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java index f322af0f2bc..3f880d0a8f9 100644 --- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java +++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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,6 +25,30 @@ package javax.management.remote.rmi; +import java.io.IOException; +import java.rmi.MarshalledObject; +import java.rmi.UnmarshalException; +import java.rmi.server.Unreferenced; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Permissions; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.ProtectionDomain; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import javax.management.*; +import javax.management.remote.JMXServerErrorException; +import javax.management.remote.NotificationResult; +import javax.management.remote.TargetedNotification; +import javax.security.auth.Subject; + import static com.sun.jmx.mbeanserver.Util.cast; import com.sun.jmx.remote.internal.ServerCommunicatorAdmin; import com.sun.jmx.remote.internal.ServerNotifForwarder; @@ -35,44 +59,6 @@ import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; import com.sun.jmx.remote.util.OrderClassLoaders; -import java.io.IOException; -import java.rmi.MarshalledObject; -import java.rmi.UnmarshalException; -import java.rmi.server.Unreferenced; -import java.security.AccessControlContext; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.Arrays; -import java.util.Collections; -import java.util.Map; -import java.util.Set; - -import javax.management.Attribute; -import javax.management.AttributeList; -import javax.management.AttributeNotFoundException; -import javax.management.InstanceAlreadyExistsException; -import javax.management.InstanceNotFoundException; -import javax.management.IntrospectionException; -import javax.management.InvalidAttributeValueException; -import javax.management.ListenerNotFoundException; -import javax.management.MBeanException; -import javax.management.MBeanInfo; -import javax.management.MBeanRegistrationException; -import javax.management.MBeanServer; -import javax.management.NotCompliantMBeanException; -import javax.management.NotificationFilter; -import javax.management.ObjectInstance; -import javax.management.ObjectName; -import javax.management.QueryExp; -import javax.management.ReflectionException; -import javax.management.RuntimeOperationsException; -import javax.management.remote.JMXServerErrorException; -import javax.management.remote.NotificationResult; -import javax.management.remote.TargetedNotification; -import javax.security.auth.Subject; - /** *

    Implementation of the {@link RMIConnection} interface. User * code will not usually reference this class.

    @@ -143,6 +129,7 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { this.mbeanServer = rmiServer.getMBeanServer(); final ClassLoader dcl = defaultClassLoader; + this.classLoaderWithRepository = AccessController.doPrivileged( new PrivilegedAction() { @@ -151,13 +138,40 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { mbeanServer.getClassLoaderRepository(), dcl); } + }, + + withPermissions( new MBeanPermission("*", "getClassLoaderRepository"), + new RuntimePermission("createClassLoader")) + ); + + + this.defaultContextClassLoader = + AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public ClassLoader run() { + return new CombinedClassLoader(Thread.currentThread().getContextClassLoader(), + dcl); + } }); + serverCommunicatorAdmin = new RMIServerCommunicatorAdmin(EnvHelp.getServerConnectionTimeout(env)); this.env = env; } + private static AccessControlContext withPermissions(Permission ... perms){ + Permissions col = new Permissions(); + + for (Permission thePerm : perms ) { + col.add(thePerm); + } + + final ProtectionDomain pd = new ProtectionDomain(null, col); + return new AccessControlContext( new ProtectionDomain[] { pd }); + } + private synchronized ServerNotifForwarder getServerNotifFwd() { // Lazily created when first use. Mainly when // addNotificationListener is first called. @@ -507,7 +521,7 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { "connectionId=" + connectionId +" unwrapping query with defaultClassLoader."); - queryValue = unwrap(query, defaultClassLoader, QueryExp.class); + queryValue = unwrap(query, defaultContextClassLoader, QueryExp.class); try { final Object params[] = new Object[] { name, queryValue }; @@ -542,7 +556,7 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { "connectionId=" + connectionId +" unwrapping query with defaultClassLoader."); - queryValue = unwrap(query, defaultClassLoader, QueryExp.class); + queryValue = unwrap(query, defaultContextClassLoader, QueryExp.class); try { final Object params[] = new Object[] { name, queryValue }; @@ -1330,7 +1344,9 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { public ClassLoader run() throws InstanceNotFoundException { return mbeanServer.getClassLoader(name); } - }); + }, + withPermissions(new MBeanPermission("*", "getClassLoader")) + ); } catch (PrivilegedActionException pe) { throw (InstanceNotFoundException) extractException(pe); } @@ -1345,7 +1361,9 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { public Object run() throws InstanceNotFoundException { return mbeanServer.getClassLoaderFor(name); } - }); + }, + withPermissions(new MBeanPermission("*", "getClassLoaderFor")) + ); } catch (PrivilegedActionException pe) { throw (InstanceNotFoundException) extractException(pe); } @@ -1572,7 +1590,8 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { ClassLoader orderCL = AccessController.doPrivileged( new PrivilegedExceptionAction() { public ClassLoader run() throws Exception { - return new OrderClassLoaders(cl1, cl2); + return new CombinedClassLoader(Thread.currentThread().getContextClassLoader(), + new OrderClassLoaders(cl1, cl2)); } } ); @@ -1664,6 +1683,8 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { private final ClassLoader defaultClassLoader; + private final ClassLoader defaultContextClassLoader; + private final ClassLoaderWithRepository classLoaderWithRepository; private boolean terminated = false; @@ -1746,4 +1767,43 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { private static final ClassLogger logger = new ClassLogger("javax.management.remote.rmi", "RMIConnectionImpl"); + + private static final class CombinedClassLoader extends ClassLoader { + + private final static class ClassLoaderWrapper extends ClassLoader { + ClassLoaderWrapper(ClassLoader cl) { + super(cl); + } + + @Override + protected Class loadClass(String name, boolean resolve) + throws ClassNotFoundException { + return super.loadClass(name, resolve); + } + }; + + final ClassLoaderWrapper defaultCL; + + private CombinedClassLoader(ClassLoader parent, ClassLoader defaultCL) { + super(parent); + this.defaultCL = new ClassLoaderWrapper(defaultCL); + } + + @Override + protected Class loadClass(String name, boolean resolve) + throws ClassNotFoundException { + try { + super.loadClass(name, resolve); + } catch(Exception e) { + for(Throwable t = e; t != null; t = t.getCause()) { + if(t instanceof SecurityException) { + throw t==e?(SecurityException)t:new SecurityException(t.getMessage(), e); + } + } + } + final Class cl = defaultCL.loadClass(name, resolve); + return cl; + } + + } } diff --git a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java index f5359f9b12c..f6d17d6cc08 100644 --- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java +++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java @@ -277,9 +277,9 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable // Check for secure RMIServer stub if the corresponding // client-side environment property is set to "true". // - boolean checkStub = EnvHelp.computeBooleanFromString( - usemap, - "jmx.remote.x.check.stub",false); + String stringBoolean = (String) usemap.get("jmx.remote.x.check.stub"); + boolean checkStub = EnvHelp.computeBooleanFromString(stringBoolean); + if (checkStub) checkStub(stub, rmiServerImplStubClass); // Connect IIOP Stub if needed. diff --git a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java index 909b9cb0d47..da92f49f70b 100644 --- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java +++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java @@ -412,9 +412,8 @@ public class RMIConnectorServer extends JMXConnectorServer { if (tracing) logger.trace("start", "Using external directory: " + jndiUrl); - final boolean rebind = EnvHelp.computeBooleanFromString( - attributes, - JNDI_REBIND_ATTRIBUTE,false); + String stringBoolean = (String) attributes.get(JNDI_REBIND_ATTRIBUTE); + final boolean rebind = EnvHelp.computeBooleanFromString( stringBoolean ); if (tracing) logger.trace("start", JNDI_REBIND_ATTRIBUTE + "=" + rebind); diff --git a/jdk/src/share/classes/javax/management/timer/Timer.java b/jdk/src/share/classes/javax/management/timer/Timer.java index 2516de5259e..aafd0ab35eb 100644 --- a/jdk/src/share/classes/javax/management/timer/Timer.java +++ b/jdk/src/share/classes/javax/management/timer/Timer.java @@ -28,8 +28,7 @@ package javax.management.timer; import static com.sun.jmx.defaults.JmxProperties.TIMER_LOGGER; import java.util.ArrayList; import java.util.Date; -import java.util.Hashtable; -import java.util.Iterator; +import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.TreeSet; @@ -128,8 +127,8 @@ public class Timer extends NotificationBroadcasterSupport * Table containing all the timer notifications of this timer, * with the associated date, period and number of occurrences. */ - private Map timerTable = - new Hashtable(); + final private Map timerTable = + new HashMap<>(); /** * Past notifications sending on/off flag value. @@ -163,7 +162,7 @@ public class Timer extends NotificationBroadcasterSupport * The notification counter ID. * Used to keep the max key value inserted into the timer table. */ - private int counterID = 0; + volatile private int counterID = 0; private java.util.Timer timer; @@ -776,7 +775,7 @@ public class Timer extends NotificationBroadcasterSupport * * @return The number of timer notifications. */ - public int getNbNotifications() { + public synchronized int getNbNotifications() { return timerTable.size(); } @@ -824,7 +823,7 @@ public class Timer extends NotificationBroadcasterSupport * @return The timer notification type or null if the identifier is not mapped to any * timer notification registered for this timer MBean. */ - public String getNotificationType(Integer id) { + public synchronized String getNotificationType(Integer id) { Object[] obj = timerTable.get(id); if (obj != null) { @@ -841,7 +840,7 @@ public class Timer extends NotificationBroadcasterSupport * @return The timer notification detailed message or null if the identifier is not mapped to any * timer notification registered for this timer MBean. */ - public String getNotificationMessage(Integer id) { + public synchronized String getNotificationMessage(Integer id) { Object[] obj = timerTable.get(id); if (obj != null) { @@ -862,7 +861,7 @@ public class Timer extends NotificationBroadcasterSupport //public Serializable getNotificationUserData(Integer id) { // end of NPCTE fix for bugId 4464388 - public Object getNotificationUserData(Integer id) { + public synchronized Object getNotificationUserData(Integer id) { Object[] obj = timerTable.get(id); if (obj != null) { return ( ((TimerNotification)obj[TIMER_NOTIF_INDEX]).getUserData() ); @@ -878,7 +877,7 @@ public class Timer extends NotificationBroadcasterSupport * @return A copy of the date or null if the identifier is not mapped to any * timer notification registered for this timer MBean. */ - public Date getDate(Integer id) { + public synchronized Date getDate(Integer id) { Object[] obj = timerTable.get(id); if (obj != null) { @@ -896,7 +895,7 @@ public class Timer extends NotificationBroadcasterSupport * @return A copy of the period or null if the identifier is not mapped to any * timer notification registered for this timer MBean. */ - public Long getPeriod(Integer id) { + public synchronized Long getPeriod(Integer id) { Object[] obj = timerTable.get(id); if (obj != null) { @@ -913,7 +912,7 @@ public class Timer extends NotificationBroadcasterSupport * @return A copy of the remaining number of occurrences or null if the identifier is not mapped to any * timer notification registered for this timer MBean. */ - public Long getNbOccurences(Integer id) { + public synchronized Long getNbOccurences(Integer id) { Object[] obj = timerTable.get(id); if (obj != null) { @@ -931,7 +930,7 @@ public class Timer extends NotificationBroadcasterSupport * @return A copy of the flag indicating whether a periodic notification is * executed at fixed-delay or at fixed-rate. */ - public Boolean getFixedRate(Integer id) { + public synchronized Boolean getFixedRate(Integer id) { Object[] obj = timerTable.get(id); if (obj != null) { @@ -982,7 +981,7 @@ public class Timer extends NotificationBroadcasterSupport * * @return true if the list of timer notifications is empty, false otherwise. */ - public boolean isEmpty() { + public synchronized boolean isEmpty() { return (timerTable.isEmpty()); } @@ -1184,11 +1183,13 @@ public class Timer extends NotificationBroadcasterSupport // TimerAlarmClock alarmClock = (TimerAlarmClock)notification.getSource(); - for (Object[] obj : timerTable.values()) { - if (obj[ALARM_CLOCK_INDEX] == alarmClock) { - timerNotification = (TimerNotification)obj[TIMER_NOTIF_INDEX]; - timerDate = (Date)obj[TIMER_DATE_INDEX]; - break; + synchronized(Timer.this) { + for (Object[] obj : timerTable.values()) { + if (obj[ALARM_CLOCK_INDEX] == alarmClock) { + timerNotification = (TimerNotification)obj[TIMER_NOTIF_INDEX]; + timerDate = (Date)obj[TIMER_DATE_INDEX]; + break; + } } } diff --git a/jdk/src/share/classes/javax/net/ssl/ExtendedSSLSession.java b/jdk/src/share/classes/javax/net/ssl/ExtendedSSLSession.java index 8afd963458d..70f98ce221d 100644 --- a/jdk/src/share/classes/javax/net/ssl/ExtendedSSLSession.java +++ b/jdk/src/share/classes/javax/net/ssl/ExtendedSSLSession.java @@ -25,6 +25,8 @@ package javax.net.ssl; +import java.util.List; + /** * Extends the SSLSession interface to support additional * session attributes. @@ -83,4 +85,34 @@ public abstract class ExtendedSSLSession implements SSLSession { * @see X509ExtendedKeyManager */ public abstract String[] getPeerSupportedSignatureAlgorithms(); + + /** + * Obtains a {@link List} containing all {@link SNIServerName}s + * of the requested Server Name Indication (SNI) extension. + *

    + * In server mode, unless the return {@link List} is empty, + * the server should use the requested server names to guide its + * selection of an appropriate authentication certificate, and/or + * other aspects of security policy. + *

    + * In client mode, unless the return {@link List} is empty, + * the client should use the requested server names to guide its + * endpoint identification of the peer's identity, and/or + * other aspects of security policy. + * + * @return a non-null immutable list of {@link SNIServerName}s of the + * requested server name indications. The returned list may be + * empty if no server name indications were requested. + * @throws UnsupportedOperationException if the underlying provider + * does not implement the operation + * + * @see SNIServerName + * @see X509ExtendedTrustManager + * @see X509ExtendedKeyManager + * + * @since 1.8 + */ + public List getRequestedServerNames() { + throw new UnsupportedOperationException(); + } } diff --git a/jdk/src/share/classes/javax/net/ssl/HandshakeCompletedEvent.java b/jdk/src/share/classes/javax/net/ssl/HandshakeCompletedEvent.java index b9fe920f265..39e802c4d86 100644 --- a/jdk/src/share/classes/javax/net/ssl/HandshakeCompletedEvent.java +++ b/jdk/src/share/classes/javax/net/ssl/HandshakeCompletedEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2003, 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 @@ -186,8 +186,7 @@ public class HandshakeCompletedEvent extends EventObject // if the provider does not support it, fallback to peer certs. // return the X500Principal of the end-entity cert. Certificate[] certs = getPeerCertificates(); - principal = (X500Principal) - ((X509Certificate)certs[0]).getSubjectX500Principal(); + principal = ((X509Certificate)certs[0]).getSubjectX500Principal(); } return principal; } @@ -216,7 +215,7 @@ public class HandshakeCompletedEvent extends EventObject // return the X500Principal of the end-entity cert. Certificate[] certs = getLocalCertificates(); if (certs != null) { - principal = (X500Principal) + principal = ((X509Certificate)certs[0]).getSubjectX500Principal(); } } diff --git a/jdk/src/share/classes/javax/net/ssl/SNIHostName.java b/jdk/src/share/classes/javax/net/ssl/SNIHostName.java new file mode 100644 index 00000000000..6f2092c662f --- /dev/null +++ b/jdk/src/share/classes/javax/net/ssl/SNIHostName.java @@ -0,0 +1,394 @@ +/* + * 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 javax.net.ssl; + +import java.net.IDN; +import java.nio.ByteBuffer; +import java.nio.charset.CodingErrorAction; +import java.nio.charset.StandardCharsets; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharacterCodingException; +import java.util.Locale; +import java.util.Objects; +import java.util.regex.Pattern; + +/** + * Instances of this class represent a server name of type + * {@link StandardConstants#SNI_HOST_NAME host_name} in a Server Name + * Indication (SNI) extension. + *

    + * As described in section 3, "Server Name Indication", of + * TLS Extensions (RFC 6066), + * "HostName" contains the fully qualified DNS hostname of the server, as + * understood by the client. The encoded server name value of a hostname is + * represented as a byte string using ASCII encoding without a trailing dot. + * This allows the support of Internationalized Domain Names (IDN) through + * the use of A-labels (the ASCII-Compatible Encoding (ACE) form of a valid + * string of Internationalized Domain Names for Applications (IDNA)) defined + * in RFC 5890. + *

    + * Note that {@code SNIHostName} objects are immutable. + * + * @see SNIServerName + * @see StandardConstants#SNI_HOST_NAME + * + * @since 1.8 + */ +public final class SNIHostName extends SNIServerName { + + // the decoded string value of the server name + private final String hostname; + + /** + * Creates an {@code SNIHostName} using the specified hostname. + *

    + * Note that per RFC 6066, + * the encoded server name value of a hostname is + * {@link StandardCharsets#US_ASCII}-compliant. In this method, + * {@code hostname} can be a user-friendly Internationalized Domain Name + * (IDN). {@link IDN#toASCII(String, int)} is used to enforce the + * restrictions on ASCII characters in hostnames (see + * RFC 3490, + * RFC 1122, + * RFC 1123) and + * translate the {@code hostname} into ASCII Compatible Encoding (ACE), as: + *

    +     *     IDN.toASCII(hostname, IDN.USE_STD3_ASCII_RULES);
    +     * 
    + *

    + * The {@code hostname} argument is illegal if it: + *

      + *
    • {@code hostname} is empty,
    • + *
    • {@code hostname} ends with a trailing dot,
    • + *
    • {@code hostname} is not a valid Internationalized + * Domain Name (IDN) compliant with the RFC 3490 specification.
    • + *
    + * @param hostname + * the hostname of this server name + * + * @throws NullPointerException if {@code hostname} is {@code null} + * @throws IllegalArgumentException if {@code hostname} is illegal + */ + public SNIHostName(String hostname) { + // IllegalArgumentException will be thrown if {@code hostname} is + // not a valid IDN. + super(StandardConstants.SNI_HOST_NAME, + (hostname = IDN.toASCII( + Objects.requireNonNull(hostname, + "Server name value of host_name cannot be null"), + IDN.USE_STD3_ASCII_RULES)) + .getBytes(StandardCharsets.US_ASCII)); + + this.hostname = hostname; + + // check the validity of the string hostname + checkHostName(); + } + + /** + * Creates an {@code SNIHostName} using the specified encoded value. + *

    + * This method is normally used to parse the encoded name value in a + * requested SNI extension. + *

    + * Per RFC 6066, + * the encoded name value of a hostname is + * {@link StandardCharsets#US_ASCII}-compliant. However, in the previous + * version of the SNI extension ( + * RFC 4366), + * the encoded hostname is represented as a byte string using UTF-8 + * encoding. For the purpose of version tolerance, this method allows + * that the charset of {@code encoded} argument can be + * {@link StandardCharsets#UTF_8}, as well as + * {@link StandardCharsets#US_ASCII}. {@link IDN#toASCII(String)} is used + * to translate the {@code encoded} argument into ASCII Compatible + * Encoding (ACE) hostname. + *

    + * It is strongly recommended that this constructor is only used to parse + * the encoded name value in a requested SNI extension. Otherwise, to + * comply with RFC 6066, + * please always use {@link StandardCharsets#US_ASCII}-compliant charset + * and enforce the restrictions on ASCII characters in hostnames (see + * RFC 3490, + * RFC 1122, + * RFC 1123) + * for {@code encoded} argument, or use {@link SNIHostName(String)} instead. + *

    + * The {@code encoded} argument is illegal if it: + *

      + *
    • {@code encoded} is empty,
    • + *
    • {@code encoded} ends with a trailing dot,
    • + *
    • {@code encoded} is not encoded in + * {@link StandardCharsets#US_ASCII} or + * {@link StandardCharsets#UTF_8}-compliant charset,
    • + *
    • {@code encoded} is not a valid Internationalized + * Domain Name (IDN) compliant with the RFC 3490 specification.
    • + *
    + * + *

    + * Note that the {@code encoded} byte array is cloned + * to protect against subsequent modification. + * + * @param encoded + * the encoded hostname of this server name + * + * @throws NullPointerException if {@code encoded} is {@code null} + * @throws IllegalArgumentException if {@code encoded} is illegal + */ + public SNIHostName(byte[] encoded) { + // NullPointerException will be thrown if {@code encoded} is null + super(StandardConstants.SNI_HOST_NAME, encoded); + + // Compliance: RFC 4366 requires that the hostname is represented + // as a byte string using UTF_8 encoding [UTF8] + try { + // Please don't use {@link String} constructors because they + // do not report coding errors. + CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder() + .onMalformedInput(CodingErrorAction.REPORT) + .onUnmappableCharacter(CodingErrorAction.REPORT); + + this.hostname = IDN.toASCII( + decoder.decode(ByteBuffer.wrap(encoded)).toString()); + } catch (RuntimeException | CharacterCodingException e) { + throw new IllegalArgumentException( + "The encoded server name value is invalid", e); + } + + // check the validity of the string hostname + checkHostName(); + } + + /** + * Returns the {@link StandardCharsets#US_ASCII}-compliant hostname of + * this {@code SNIHostName} object. + *

    + * Note that, per + * RFC 6066, the + * returned hostname may be an internationalized domain name that + * contains A-labels. See + * RFC 5890 + * for more information about the detailed A-label specification. + * + * @return the {@link StandardCharsets#US_ASCII}-compliant hostname + * of this {@code SNIHostName} object + */ + public String getAsciiName() { + return hostname; + } + + /** + * Compares this server name to the specified object. + *

    + * Per RFC 6066, DNS + * hostnames are case-insensitive. Two server hostnames are equal if, + * and only if, they have the same name type, and the hostnames are + * equal in a case-independent comparison. + * + * @param other + * the other server name object to compare with. + * @return true if, and only if, the {@code other} is considered + * equal to this instance + */ + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (other instanceof SNIHostName) { + return hostname.equalsIgnoreCase(((SNIHostName)other).hostname); + } + + return false; + } + + /** + * Returns a hash code value for this {@code SNIHostName}. + *

    + * The hash code value is generated using the case-insensitive hostname + * of this {@code SNIHostName}. + * + * @return a hash code value for this {@code SNIHostName}. + */ + @Override + public int hashCode() { + int result = 17; // 17/31: prime number to decrease collisions + result = 31 * result + hostname.toUpperCase(Locale.ENGLISH).hashCode(); + + return result; + } + + /** + * Returns a string representation of the object, including the DNS + * hostname in this {@code SNIHostName} object. + *

    + * The exact details of the representation are unspecified and subject + * to change, but the following may be regarded as typical: + *

    +     *     "type=host_name (0), value={@literal }"
    +     * 
    + * The "{@literal }" is an ASCII representation of the hostname, + * which may contains A-labels. For example, a returned value of an pseudo + * hostname may look like: + *
    +     *     "type=host_name (0), value=www.example.com"
    +     * 
    + * or + *
    +     *     "type=host_name (0), value=xn--fsqu00a.xn--0zwm56d"
    +     * 
    + *

    + * Please NOTE that the exact details of the representation are unspecified + * and subject to change. + * + * @return a string representation of the object. + */ + @Override + public String toString() { + return "type=host_name (0), value=" + hostname; + } + + /** + * Creates an {@link SNIMatcher} object for {@code SNIHostName}s. + *

    + * This method can be used by a server to verify the acceptable + * {@code SNIHostName}s. For example, + *

    +     *     SNIMatcher matcher =
    +     *         SNIHostName.createSNIMatcher("www\\.example\\.com");
    +     * 
    + * will accept the hostname "www.example.com". + *
    +     *     SNIMatcher matcher =
    +     *         SNIHostName.createSNIMatcher("www\\.example\\.(com|org)");
    +     * 
    + * will accept hostnames "www.example.com" and "www.example.org". + * + * @param regex + * the + * regular expression pattern + * representing the hostname(s) to match + * @throws NullPointerException if {@code regex} is + * {@code null} + * @throws PatternSyntaxException if the regular expression's syntax + * is invalid + */ + public static SNIMatcher createSNIMatcher(String regex) { + if (regex == null) { + throw new NullPointerException( + "The regular expression cannot be null"); + } + + return new SNIHostNameMatcher(regex); + } + + // check the validity of the string hostname + private void checkHostName() { + if (hostname.isEmpty()) { + throw new IllegalArgumentException( + "Server name value of host_name cannot be empty"); + } + + if (hostname.endsWith(".")) { + throw new IllegalArgumentException( + "Server name value of host_name cannot have the trailing dot"); + } + } + + private final static class SNIHostNameMatcher extends SNIMatcher { + + // the compiled representation of a regular expression. + private final Pattern pattern; + + /** + * Creates an SNIHostNameMatcher object. + * + * @param regex + * the + * regular expression pattern + * representing the hostname(s) to match + * @throws NullPointerException if {@code regex} is + * {@code null} + * @throws PatternSyntaxException if the regular expression's syntax + * is invalid + */ + SNIHostNameMatcher(String regex) { + super(StandardConstants.SNI_HOST_NAME); + pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); + } + + /** + * Attempts to match the given {@link SNIServerName}. + * + * @param serverName + * the {@link SNIServerName} instance on which this matcher + * performs match operations + * + * @return {@code true} if, and only if, the matcher matches the + * given {@code serverName} + * + * @throws NullPointerException if {@code serverName} is {@code null} + * @throws IllegalArgumentException if {@code serverName} is + * not of {@code StandardConstants#SNI_HOST_NAME} type + * + * @see SNIServerName + */ + @Override + public boolean matches(SNIServerName serverName) { + if (serverName == null) { + throw new NullPointerException( + "The SNIServerName argument cannot be null"); + } + + SNIHostName hostname; + if (!(serverName instanceof SNIHostName)) { + if (serverName.getType() != StandardConstants.SNI_HOST_NAME) { + throw new IllegalArgumentException( + "The server name type is not host_name"); + } + + try { + hostname = new SNIHostName(serverName.getEncoded()); + } catch (NullPointerException | IllegalArgumentException e) { + return false; + } + } else { + hostname = (SNIHostName)serverName; + } + + // Let's first try the ascii name matching + String asciiName = hostname.getAsciiName(); + if (pattern.matcher(asciiName).matches()) { + return true; + } + + // May be an internationalized domain name, check the Unicode + // representations. + return pattern.matcher(IDN.toUnicode(asciiName)).matches(); + } + } +} diff --git a/jdk/src/share/classes/javax/net/ssl/SNIMatcher.java b/jdk/src/share/classes/javax/net/ssl/SNIMatcher.java new file mode 100644 index 00000000000..5025b99ed79 --- /dev/null +++ b/jdk/src/share/classes/javax/net/ssl/SNIMatcher.java @@ -0,0 +1,105 @@ +/* + * 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 javax.net.ssl; + +/** + * Instances of this class represent a matcher that performs match + * operations on an {@link SNIServerName} instance. + *

    + * Servers can use Server Name Indication (SNI) information to decide if + * specific {@link SSLSocket} or {@link SSLEngine} instances should accept + * a connection. For example, when multiple "virtual" or "name-based" + * servers are hosted on a single underlying network address, the server + * application can use SNI information to determine whether this server is + * the exact server that the client wants to access. Instances of this + * class can be used by a server to verify the acceptable server names of + * a particular type, such as host names. + *

    + * {@code SNIMatcher} objects are immutable. Subclasses should not provide + * methods that can change the state of an instance once it has been created. + * + * @see SNIServerName + * @see SNIHostName + * @see SSLParameters#getSNIMatchers() + * @see SSLParameters#setSNIMatchers(Collection) + * + * @since 1.8 + */ +public abstract class SNIMatcher { + + // the type of the server name that this matcher performs on + private final int type; + + /** + * Creates an {@code SNIMatcher} using the specified server name type. + * + * @param type + * the type of the server name that this matcher performs on + * + * @throws IllegalArgumentException if {@code type} is not in the range + * of 0 to 255, inclusive. + */ + protected SNIMatcher(int type) { + if (type < 0) { + throw new IllegalArgumentException( + "Server name type cannot be less than zero"); + } else if (type > 255) { + throw new IllegalArgumentException( + "Server name type cannot be greater than 255"); + } + + this.type = type; + } + + /** + * Returns the server name type of this {@code SNIMatcher} object. + * + * @return the server name type of this {@code SNIMatcher} object. + * + * @see SNIServerName + */ + public final int getType() { + return type; + } + + /** + * Attempts to match the given {@link SNIServerName}. + * + * @param serverName + * the {@link SNIServerName} instance on which this matcher + * performs match operations + * + * @return {@code true} if, and only if, the matcher matches the + * given {@code serverName} + * + * @throws NullPointerException if {@code serverName} is {@code null} + * @throws IllegalArgumentException if {@code serverName} is + * not of the given server name type of this matcher + * + * @see SNIServerName + */ + public abstract boolean matches(SNIServerName serverName); +} diff --git a/jdk/src/share/classes/javax/net/ssl/SNIServerName.java b/jdk/src/share/classes/javax/net/ssl/SNIServerName.java new file mode 100644 index 00000000000..afc2286d761 --- /dev/null +++ b/jdk/src/share/classes/javax/net/ssl/SNIServerName.java @@ -0,0 +1,213 @@ +/* + * 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 javax.net.ssl; + +import java.util.Arrays; + +/** + * Instances of this class represent a server name in a Server Name + * Indication (SNI) extension. + *

    + * The SNI extension is a feature that extends the SSL/TLS protocols to + * indicate what server name the client is attempting to connect to during + * handshaking. See section 3, "Server Name Indication", of TLS Extensions (RFC 6066). + *

    + * {@code SNIServerName} objects are immutable. Subclasses should not provide + * methods that can change the state of an instance once it has been created. + * + * @see SSLParameters#getServerNames() + * @see SSLParameters#setServerNames(List) + * + * @since 1.8 + */ +public abstract class SNIServerName { + + // the type of the server name + private final int type; + + // the encoded value of the server name + private final byte[] encoded; + + // the hex digitals + private static final char[] HEXES = "0123456789ABCDEF".toCharArray(); + + /** + * Creates an {@code SNIServerName} using the specified name type and + * encoded value. + *

    + * Note that the {@code encoded} byte array is cloned to protect against + * subsequent modification. + * + * @param type + * the type of the server name + * @param encoded + * the encoded value of the server name + * + * @throws IllegalArgumentException if {@code type} is not in the range + * of 0 to 255, inclusive. + * @throws NullPointerException if {@code encoded} is null + */ + protected SNIServerName(int type, byte[] encoded) { + if (type < 0) { + throw new IllegalArgumentException( + "Server name type cannot be less than zero"); + } else if (type > 255) { + throw new IllegalArgumentException( + "Server name type cannot be greater than 255"); + } + this.type = type; + + if (encoded == null) { + throw new NullPointerException( + "Server name encoded value cannot be null"); + } + this.encoded = encoded.clone(); + } + + + /** + * Returns the name type of this server name. + * + * @return the name type of this server name + */ + public final int getType() { + return type; + } + + /** + * Returns a copy of the encoded server name value of this server name. + * + * @return a copy of the encoded server name value of this server name + */ + public final byte[] getEncoded() { + return encoded.clone(); + } + + /** + * Indicates whether some other object is "equal to" this server name. + * + * @return true if, and only if, {@code other} is of the same class + * of this object, and has the same name type and + * encoded value as this server name. + */ + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (this.getClass() != other.getClass()) { + return false; + } + + SNIServerName that = (SNIServerName)other; + return (this.type == that.type) && + Arrays.equals(this.encoded, that.encoded); + } + + /** + * Returns a hash code value for this server name. + *

    + * The hash code value is generated using the name type and encoded + * value of this server name. + * + * @return a hash code value for this server name. + */ + @Override + public int hashCode() { + int result = 17; // 17/31: prime number to decrease collisions + result = 31 * result + type; + result = 31 * result + Arrays.hashCode(encoded); + + return result; + } + + /** + * Returns a string representation of this server name, including the server + * name type and the encoded server name value in this + * {@code SNIServerName} object. + *

    + * The exact details of the representation are unspecified and subject + * to change, but the following may be regarded as typical: + *

    +     *     "type={@literal }, value={@literal }"
    +     * 
    + *

    + * In this class, the format of "{@literal }" is + * "[LITERAL] (INTEGER)", where the optional "LITERAL" is the literal + * name, and INTEGER is the integer value of the name type. The format + * of "{@literal }" is "XX:...:XX", where "XX" is the + * hexadecimal digit representation of a byte value. For example, a + * returned value of an pseudo server name may look like: + *

    +     *     "type=(31), value=77:77:77:2E:65:78:61:6D:70:6C:65:2E:63:6E"
    +     * 
    + * or + *
    +     *     "type=host_name (0), value=77:77:77:2E:65:78:61:6D:70:6C:65:2E:63:6E"
    +     * 
    + * + *

    + * Please NOTE that the exact details of the representation are unspecified + * and subject to change, and subclasses may override the method with + * their own formats. + * + * @return a string representation of this server name + */ + @Override + public String toString() { + if (type == StandardConstants.SNI_HOST_NAME) { + return "type=host_name (0), value=" + toHexString(encoded); + } else { + return "type=(" + type + "), value=" + toHexString(encoded); + } + } + + // convert byte array to hex string + private static String toHexString(byte[] bytes) { + if (bytes.length == 0) { + return "(empty)"; + } + + StringBuilder sb = new StringBuilder(bytes.length * 3 - 1); + boolean isInitial = true; + for (byte b : bytes) { + if (isInitial) { + isInitial = false; + } else { + sb.append(':'); + } + + int k = b & 0xFF; + sb.append(HEXES[k >>> 4]); + sb.append(HEXES[k & 0xF]); + } + + return sb.toString(); + } +} + diff --git a/jdk/src/share/classes/javax/net/ssl/SSLEngine.java b/jdk/src/share/classes/javax/net/ssl/SSLEngine.java index 411626cd7a1..433361c6a6b 100644 --- a/jdk/src/share/classes/javax/net/ssl/SSLEngine.java +++ b/jdk/src/share/classes/javax/net/ssl/SSLEngine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -1214,15 +1214,19 @@ public abstract class SSLEngine { * *

    This means: *

      - *
    • if params.getCipherSuites() is non-null, - * setEnabledCipherSuites() is called with that value - *
    • if params.getProtocols() is non-null, - * setEnabledProtocols() is called with that value - *
    • if params.getNeedClientAuth() or - * params.getWantClientAuth() return true, - * setNeedClientAuth(true) and - * setWantClientAuth(true) are called, respectively; - * otherwise setWantClientAuth(false) is called. + *
    • If {@code params.getCipherSuites()} is non-null, + * {@code setEnabledCipherSuites()} is called with that value.
    • + *
    • If {@code params.getProtocols()} is non-null, + * {@code setEnabledProtocols()} is called with that value.
    • + *
    • If {@code params.getNeedClientAuth()} or + * {@code params.getWantClientAuth()} return {@code true}, + * {@code setNeedClientAuth(true)} and + * {@code setWantClientAuth(true)} are called, respectively; + * otherwise {@code setWantClientAuth(false)} is called.
    • + *
    • If {@code params.getServerNames()} is non-null, the engine will + * configure its server names with that value.
    • + *
    • If {@code params.getSNIMatchers()} is non-null, the engine will + * configure its SNI matchers with that value.
    • *
    * * @param params the parameters diff --git a/jdk/src/share/classes/javax/net/ssl/SSLParameters.java b/jdk/src/share/classes/javax/net/ssl/SSLParameters.java index 0cb5b7d424c..d207f6f9e6f 100644 --- a/jdk/src/share/classes/javax/net/ssl/SSLParameters.java +++ b/jdk/src/share/classes/javax/net/ssl/SSLParameters.java @@ -26,13 +26,23 @@ package javax.net.ssl; import java.security.AlgorithmConstraints; +import java.util.Map; +import java.util.List; +import java.util.HashSet; +import java.util.HashMap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.regex.Pattern; /** * Encapsulates parameters for an SSL/TLS connection. The parameters * are the list of ciphersuites to be accepted in an SSL/TLS handshake, * the list of protocols to be allowed, the endpoint identification - * algorithm during SSL/TLS handshaking, the algorithm constraints and - * whether SSL/TLS servers should request or require client authentication. + * algorithm during SSL/TLS handshaking, the Server Name Indication (SNI), + * the algorithm constraints and whether SSL/TLS servers should request + * or require client authentication. *

    * SSLParameters can be created via the constructors in this class. * Objects can also be obtained using the getSSLParameters() @@ -47,7 +57,7 @@ import java.security.AlgorithmConstraints; * SSLParameters can be applied to a connection via the methods * {@link SSLSocket#setSSLParameters SSLSocket.setSSLParameters()} and * {@link SSLServerSocket#setSSLParameters SSLServerSocket.setSSLParameters()} - * and {@link SSLEngine#setSSLParameters SSLEngine.getSSLParameters()}. + * and {@link SSLEngine#setSSLParameters SSLEngine.setSSLParameters()}. * * @see SSLSocket * @see SSLEngine @@ -63,11 +73,15 @@ public class SSLParameters { private boolean needClientAuth; private String identificationAlgorithm; private AlgorithmConstraints algorithmConstraints; + private Map sniNames = null; + private Map sniMatchers = null; /** * Constructs SSLParameters. *

    - * The cipherSuites and protocols values are set to null, + * The values of cipherSuites, protocols, cryptographic algorithm + * constraints, endpoint identification algorithm, server names and + * server name matchers are set to null, * wantClientAuth and needClientAuth are set to false. */ public SSLParameters() { @@ -254,4 +268,173 @@ public class SSLParameters { this.identificationAlgorithm = algorithm; } + /** + * Sets the desired {@link SNIServerName}s of the Server Name + * Indication (SNI) parameter. + *

    + * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s + * operating in client mode. + *

    + * Note that the {@code serverNames} list is cloned + * to protect against subsequent modification. + * + * @param serverNames + * the list of desired {@link SNIServerName}s (or null) + * + * @throws NullPointerException if the {@code serverNames} + * contains {@code null} element + * @throws IllegalArgumentException if the {@code serverNames} + * contains more than one name of the same name type + * + * @see SNIServerName + * @see #getServerNames() + * + * @since 1.8 + */ + public final void setServerNames(List serverNames) { + if (serverNames != null) { + if (!serverNames.isEmpty()) { + sniNames = new LinkedHashMap<>(serverNames.size()); + for (SNIServerName serverName : serverNames) { + if (sniNames.put(serverName.getType(), + serverName) != null) { + throw new IllegalArgumentException( + "Duplicated server name of type " + + serverName.getType()); + } + } + } else { + sniNames = Collections.emptyMap(); + } + } else { + sniNames = null; + } + } + + /** + * Returns a {@link List} containing all {@link SNIServerName}s of the + * Server Name Indication (SNI) parameter, or null if none has been set. + *

    + * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s + * operating in client mode. + *

    + * For SSL/TLS connections, the underlying SSL/TLS provider + * may specify a default value for a certain server name type. In + * client mode, it is recommended that, by default, providers should + * include the server name indication whenever the server can be located + * by a supported server name type. + *

    + * It is recommended that providers initialize default Server Name + * Indications when creating {@code SSLSocket}/{@code SSLEngine}s. + * In the following examples, the server name could be represented by an + * instance of {@link SNIHostName} which has been initialized with the + * hostname "www.example.com" and type + * {@link StandardConstants#SNI_HOST_NAME}. + * + *

    +     *     Socket socket =
    +     *         sslSocketFactory.createSocket("www.example.com", 443);
    +     * 
    + * or + *
    +     *     SSLEngine engine =
    +     *         sslContext.createSSLEngine("www.example.com", 443);
    +     * 
    + *

    + * + * @return null or an immutable list of non-null {@link SNIServerName}s + * + * @see List + * @see #setServerNames(List) + * + * @since 1.8 + */ + public final List getServerNames() { + if (sniNames != null) { + if (!sniNames.isEmpty()) { + return Collections.unmodifiableList( + new ArrayList<>(sniNames.values())); + } else { + return Collections.emptyList(); + } + } + + return null; + } + + /** + * Sets the {@link SNIMatcher}s of the Server Name Indication (SNI) + * parameter. + *

    + * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s + * operating in server mode. + *

    + * Note that the {@code matchers} collection is cloned to protect + * against subsequent modification. + * + * @param matchers + * the collection of {@link SNIMatcher}s (or null) + * + * @throws NullPointerException if the {@code matchers} + * contains {@code null} element + * @throws IllegalArgumentException if the {@code matchers} + * contains more than one name of the same name type + * + * @see Collection + * @see SNIMatcher + * @see #getSNIMatchers() + * + * @since 1.8 + */ + public final void setSNIMatchers(Collection matchers) { + if (matchers != null) { + if (!matchers.isEmpty()) { + sniMatchers = new HashMap<>(matchers.size()); + for (SNIMatcher matcher : matchers) { + if (sniMatchers.put(matcher.getType(), + matcher) != null) { + throw new IllegalArgumentException( + "Duplicated server name of type " + + matcher.getType()); + } + } + } else { + sniMatchers = Collections.emptyMap(); + } + } else { + sniMatchers = null; + } + } + + /** + * Returns a {@link Collection} containing all {@link SNIMatcher}s of the + * Server Name Indication (SNI) parameter, or null if none has been set. + *

    + * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s + * operating in server mode. + *

    + * For better interoperability, providers generally will not define + * default matchers so that by default servers will ignore the SNI + * extension and continue the handshake. + * + * @return null or an immutable collection of non-null {@link SNIMatcher}s + * + * @see SNIMatcher + * @see #setSNIMatchers(Collection) + * + * @since 1.8 + */ + public final Collection getSNIMatchers() { + if (sniMatchers != null) { + if (!sniMatchers.isEmpty()) { + return Collections.unmodifiableList( + new ArrayList<>(sniMatchers.values())); + } else { + return Collections.emptyList(); + } + } + + return null; + } } + diff --git a/jdk/src/share/classes/javax/net/ssl/SSLServerSocket.java b/jdk/src/share/classes/javax/net/ssl/SSLServerSocket.java index d5bbaaf5da5..48dc7facd44 100644 --- a/jdk/src/share/classes/javax/net/ssl/SSLServerSocket.java +++ b/jdk/src/share/classes/javax/net/ssl/SSLServerSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, 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 @@ -484,15 +484,19 @@ public abstract class SSLServerSocket extends ServerSocket { * *

    This means: *

      - *
    • if params.getCipherSuites() is non-null, - * setEnabledCipherSuites() is called with that value - *
    • if params.getProtocols() is non-null, - * setEnabledProtocols() is called with that value - *
    • if params.getNeedClientAuth() or - * params.getWantClientAuth() return true, - * setNeedClientAuth(true) and - * setWantClientAuth(true) are called, respectively; - * otherwise setWantClientAuth(false) is called. + *
    • If {@code params.getCipherSuites()} is non-null, + * {@code setEnabledCipherSuites()} is called with that value.
    • + *
    • If {@code params.getProtocols()} is non-null, + * {@code setEnabledProtocols()} is called with that value.
    • + *
    • If {@code params.getNeedClientAuth()} or + * {@code params.getWantClientAuth()} return {@code true}, + * {@code setNeedClientAuth(true)} and + * {@code setWantClientAuth(true)} are called, respectively; + * otherwise {@code setWantClientAuth(false)} is called.
    • + *
    • If {@code params.getServerNames()} is non-null, the socket will + * configure its server names with that value.
    • + *
    • If {@code params.getSNIMatchers()} is non-null, the socket will + * configure its SNI matchers with that value.
    • *
    * * @param params the parameters diff --git a/jdk/src/share/classes/javax/net/ssl/SSLSocket.java b/jdk/src/share/classes/javax/net/ssl/SSLSocket.java index b61f94a5a75..ab090130f2d 100644 --- a/jdk/src/share/classes/javax/net/ssl/SSLSocket.java +++ b/jdk/src/share/classes/javax/net/ssl/SSLSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, 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 @@ -626,15 +626,19 @@ public abstract class SSLSocket extends Socket * *

    This means: *

      - *
    • if params.getCipherSuites() is non-null, - * setEnabledCipherSuites() is called with that value - *
    • if params.getProtocols() is non-null, - * setEnabledProtocols() is called with that value - *
    • if params.getNeedClientAuth() or - * params.getWantClientAuth() return true, - * setNeedClientAuth(true) and - * setWantClientAuth(true) are called, respectively; - * otherwise setWantClientAuth(false) is called. + *
    • If {@code params.getCipherSuites()} is non-null, + * {@code setEnabledCipherSuites()} is called with that value.
    • + *
    • If {@code params.getProtocols()} is non-null, + * {@code setEnabledProtocols()} is called with that value.
    • + *
    • If {@code params.getNeedClientAuth()} or + * {@code params.getWantClientAuth()} return {@code true}, + * {@code setNeedClientAuth(true)} and + * {@code setWantClientAuth(true)} are called, respectively; + * otherwise {@code setWantClientAuth(false)} is called.
    • + *
    • If {@code params.getServerNames()} is non-null, the socket will + * configure its server names with that value.
    • + *
    • If {@code params.getSNIMatchers()} is non-null, the socket will + * configure its SNI matchers with that value.
    • *
    * * @param params the parameters diff --git a/jdk/src/share/classes/javax/net/ssl/SSLSocketFactory.java b/jdk/src/share/classes/javax/net/ssl/SSLSocketFactory.java index c3d33c34f70..73f48d197a4 100644 --- a/jdk/src/share/classes/javax/net/ssl/SSLSocketFactory.java +++ b/jdk/src/share/classes/javax/net/ssl/SSLSocketFactory.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 @@ -29,6 +29,7 @@ package javax.net.ssl; import java.net.*; import javax.net.SocketFactory; import java.io.IOException; +import java.io.InputStream; import java.security.*; import java.util.Locale; @@ -180,8 +181,55 @@ public abstract class SSLSocketFactory extends SocketFactory * @throws NullPointerException if the parameter s is null */ public abstract Socket createSocket(Socket s, String host, - int port, boolean autoClose) - throws IOException; + int port, boolean autoClose) throws IOException; + + /** + * Creates a server mode {@link Socket} layered over an + * existing connected socket, and is able to read data which has + * already been consumed/removed from the {@link Socket}'s + * underlying {@link InputStream}. + *

    + * This method can be used by a server application that needs to + * observe the inbound data but still create valid SSL/TLS + * connections: for example, inspection of Server Name Indication + * (SNI) extensions (See section 3 of TLS Extensions + * (RFC6066)). Data that has been already removed from the + * underlying {@link InputStream} should be loaded into the + * {@code consumed} stream before this method is called, perhaps + * using a {@link ByteArrayInputStream}. When this {@link Socket} + * begins handshaking, it will read all of the data in + * {@code consumed} until it reaches {@code EOF}, then all further + * data is read from the underlying {@link InputStream} as + * usual. + *

    + * The returned socket is configured using the socket options + * established for this factory, and is set to use server mode when + * handshaking (see {@link SSLSocket#setUseClientMode(boolean)}). + * + * @param s + * the existing socket + * @param consumed + * the consumed inbound network data that has already been + * removed from the existing {@link Socket} + * {@link InputStream}. This parameter may be + * {@code null} if no data has been removed. + * @param autoClose close the underlying socket when this socket is closed. + * + * @return the {@link Socket} compliant with the socket options + * established for this factory + * + * @throws IOException if an I/O error occurs when creating the socket + * @throws UnsupportedOperationException if the underlying provider + * does not implement the operation + * @throws NullPointerException if {@code s} is {@code null} + * + * @since 1.8 + */ + public Socket createSocket(Socket s, InputStream consumed, + boolean autoClose) throws IOException { + throw new UnsupportedOperationException(); + } } diff --git a/jdk/src/share/classes/javax/net/ssl/StandardConstants.java b/jdk/src/share/classes/javax/net/ssl/StandardConstants.java new file mode 100644 index 00000000000..8e1df977b97 --- /dev/null +++ b/jdk/src/share/classes/javax/net/ssl/StandardConstants.java @@ -0,0 +1,56 @@ +/* + * 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 javax.net.ssl; + +/** + * Standard constants definitions + * + * @since 1.8 + */ +public final class StandardConstants { + + // Suppress default constructor for noninstantiability + private StandardConstants() { + throw new AssertionError( + "No javax.net.ssl.StandardConstants instances for you!"); + } + + /** + * The "host_name" type representing of a DNS hostname + * (see {@link SNIHostName}) in a Server Name Indication (SNI) extension. + *

    + * The SNI extension is a feature that extends the SSL/TLS protocols to + * indicate what server name the client is attempting to connect to during + * handshaking. See section 3, "Server Name Indication", of TLS Extensions (RFC 6066). + *

    + * The value of this constant is {@value}. + * + * @see SNIServerName + * @see SNIHostName + */ + public static final int SNI_HOST_NAME = 0x00; +} diff --git a/jdk/src/share/classes/javax/sql/rowset/BaseRowSet.java b/jdk/src/share/classes/javax/sql/rowset/BaseRowSet.java index bbb1852b965..adf2e51dd4e 100644 --- a/jdk/src/share/classes/javax/sql/rowset/BaseRowSet.java +++ b/jdk/src/share/classes/javax/sql/rowset/BaseRowSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -1850,7 +1850,7 @@ public abstract class BaseRowSet implements Serializable, Cloneable { if(params == null){ throw new SQLException("Set initParams() before setFloat"); } - params.put(Integer.valueOf(parameterIndex - 1), new Float(x)); + params.put(Integer.valueOf(parameterIndex - 1), Float.valueOf(x)); } /** @@ -1882,7 +1882,7 @@ public abstract class BaseRowSet implements Serializable, Cloneable { if(params == null){ throw new SQLException("Set initParams() before setDouble"); } - params.put(Integer.valueOf(parameterIndex - 1), new Double(x)); + params.put(Integer.valueOf(parameterIndex - 1), Double.valueOf(x)); } /** @@ -2389,7 +2389,7 @@ public abstract class BaseRowSet implements Serializable, Cloneable { * @deprecated getCharacterStream should be used in its place * @see #getParams */ - + @Deprecated public void setUnicodeStream(int parameterIndex, java.io.InputStream x, int length) throws SQLException { Object unicodeStream[]; checkParamIndex(parameterIndex); diff --git a/jdk/src/share/classes/javax/sql/rowset/serial/SQLOutputImpl.java b/jdk/src/share/classes/javax/sql/rowset/serial/SQLOutputImpl.java index b46a880bd08..fbe4a741726 100644 --- a/jdk/src/share/classes/javax/sql/rowset/serial/SQLOutputImpl.java +++ b/jdk/src/share/classes/javax/sql/rowset/serial/SQLOutputImpl.java @@ -215,7 +215,7 @@ public class SQLOutputImpl implements SQLOutput { */ @SuppressWarnings("unchecked") public void writeFloat(float x) throws SQLException { - attribs.add(new Float(x)); + attribs.add(Float.valueOf(x)); } /** @@ -230,7 +230,7 @@ public class SQLOutputImpl implements SQLOutput { */ @SuppressWarnings("unchecked") public void writeDouble(double x) throws SQLException{ - attribs.add(new Double(x)); + attribs.add(Double.valueOf(x)); } /** diff --git a/jdk/src/share/classes/javax/sql/rowset/spi/SyncFactory.java b/jdk/src/share/classes/javax/sql/rowset/spi/SyncFactory.java index 11a59c4a9e1..10e6158e77b 100644 --- a/jdk/src/share/classes/javax/sql/rowset/spi/SyncFactory.java +++ b/jdk/src/share/classes/javax/sql/rowset/spi/SyncFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -229,11 +229,7 @@ public class SyncFactory { * The standard resource file name. */ private static String ROWSET_PROPERTIES = "rowset.properties"; - /** - * The RI Optimistic Provider. - */ - private static String default_provider = - "com.sun.rowset.providers.RIOptimisticProvider"; + /** * Permission required to invoke setJNDIContext and setLogger */ @@ -248,24 +244,13 @@ public class SyncFactory { * The Logger object to be used by the SyncFactory. */ private static volatile Logger rsLogger; - /** - * - */ - private static Level rsLevel; + /** * The registry of available SyncProvider implementations. * See section 2.0 of the class comment for SyncFactory for an * explanation of how a provider can be added to this registry. */ private static Hashtable implementations; - /** - * Internal sync object used to maintain the SPI as a singleton - */ - private static Object logSync = new Object(); - /** - * Internal PrintWriter field for logging facility - */ - private static java.io.PrintWriter logWriter = null; /** * Adds the the given synchronization provider to the factory register. Guidelines diff --git a/jdk/src/share/classes/javax/swing/text/DefaultFormatter.java b/jdk/src/share/classes/javax/swing/text/DefaultFormatter.java index 5e003b55bca..b67966ab70a 100644 --- a/jdk/src/share/classes/javax/swing/text/DefaultFormatter.java +++ b/jdk/src/share/classes/javax/swing/text/DefaultFormatter.java @@ -24,6 +24,8 @@ */ package javax.swing.text; +import sun.reflect.misc.ConstructorUtil; + import java.io.Serializable; import java.lang.reflect.*; import java.text.ParseException; @@ -245,7 +247,7 @@ public class DefaultFormatter extends JFormattedTextField.AbstractFormatter Constructor cons; try { - cons = vc.getConstructor(new Class[] { String.class }); + cons = ConstructorUtil.getConstructor(vc, new Class[]{String.class}); } catch (NoSuchMethodException nsme) { cons = null; diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/AnnotationVisitor.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/AnnotationVisitor.java new file mode 100644 index 00000000000..9690afe2cf0 --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/AnnotationVisitor.java @@ -0,0 +1,186 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +/** + * A visitor to visit a Java annotation. The methods of this class must be + * called in the following order: ( visit | visitEnum | + * visitAnnotation | visitArray )* visitEnd. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public abstract class AnnotationVisitor { + + /** + * The ASM API version implemented by this visitor. The value of this field + * must be one of {@link Opcodes#ASM4}. + */ + protected final int api; + + /** + * The annotation visitor to which this visitor must delegate method calls. + * May be null. + */ + protected AnnotationVisitor av; + + /** + * Constructs a new {@link AnnotationVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + */ + public AnnotationVisitor(final int api) { + this(api, null); + } + + /** + * Constructs a new {@link AnnotationVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param av the annotation visitor to which this visitor must delegate + * method calls. May be null. + */ + public AnnotationVisitor(final int api, final AnnotationVisitor av) { + /*if (api != Opcodes.ASM4) { + throw new IllegalArgumentException(); + }*/ + this.api = api; + this.av = av; + } + + /** + * Visits a primitive value of the annotation. + * + * @param name the value name. + * @param value the actual value, whose type must be {@link Byte}, + * {@link Boolean}, {@link Character}, {@link Short}, {@link Integer} + * , {@link Long}, {@link Float}, {@link Double}, {@link String} or + * {@link Type} or OBJECT or ARRAY sort. This value can also be an + * array of byte, boolean, short, char, int, long, float or double + * values (this is equivalent to using {@link #visitArray visitArray} + * and visiting each array element in turn, but is more convenient). + */ + public void visit(String name, Object value) { + if (av != null) { + av.visit(name, value); + } + } + + /** + * Visits an enumeration value of the annotation. + * + * @param name the value name. + * @param desc the class descriptor of the enumeration class. + * @param value the actual enumeration value. + */ + public void visitEnum(String name, String desc, String value) { + if (av != null) { + av.visitEnum(name, desc, value); + } + } + + /** + * Visits a nested annotation value of the annotation. + * + * @param name the value name. + * @param desc the class descriptor of the nested annotation class. + * @return a visitor to visit the actual nested annotation value, or + * null if this visitor is not interested in visiting + * this nested annotation. The nested annotation value must be + * fully visited before calling other methods on this annotation + * visitor. + */ + public AnnotationVisitor visitAnnotation(String name, String desc) { + if (av != null) { + return av.visitAnnotation(name, desc); + } + return null; + } + + /** + * Visits an array value of the annotation. Note that arrays of primitive + * types (such as byte, boolean, short, char, int, long, float or double) + * can be passed as value to {@link #visit visit}. This is what + * {@link ClassReader} does. + * + * @param name the value name. + * @return a visitor to visit the actual array value elements, or + * null if this visitor is not interested in visiting + * these values. The 'name' parameters passed to the methods of this + * visitor are ignored. All the array values must be visited + * before calling other methods on this annotation visitor. + */ + public AnnotationVisitor visitArray(String name) { + if (av != null) { + return av.visitArray(name); + } + return null; + } + + /** + * Visits the end of the annotation. + */ + public void visitEnd() { + if (av != null) { + av.visitEnd(); + } + } +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/AnnotationWriter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/AnnotationWriter.java new file mode 100644 index 00000000000..ca728393392 --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/AnnotationWriter.java @@ -0,0 +1,351 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +/** + * An {@link AnnotationVisitor} that generates annotations in bytecode form. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +final class AnnotationWriter extends AnnotationVisitor { + + /** + * The class writer to which this annotation must be added. + */ + private final ClassWriter cw; + + /** + * The number of values in this annotation. + */ + private int size; + + /** + * true if values are named, false otherwise. Annotation + * writers used for annotation default and annotation arrays use unnamed + * values. + */ + private final boolean named; + + /** + * The annotation values in bytecode form. This byte vector only contains + * the values themselves, i.e. the number of values must be stored as a + * unsigned short just before these bytes. + */ + private final ByteVector bv; + + /** + * The byte vector to be used to store the number of values of this + * annotation. See {@link #bv}. + */ + private final ByteVector parent; + + /** + * Where the number of values of this annotation must be stored in + * {@link #parent}. + */ + private final int offset; + + /** + * Next annotation writer. This field is used to store annotation lists. + */ + AnnotationWriter next; + + /** + * Previous annotation writer. This field is used to store annotation lists. + */ + AnnotationWriter prev; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructs a new {@link AnnotationWriter}. + * + * @param cw the class writer to which this annotation must be added. + * @param named true if values are named, false otherwise. + * @param bv where the annotation values must be stored. + * @param parent where the number of annotation values must be stored. + * @param offset where in parent the number of annotation values must + * be stored. + */ + AnnotationWriter( + final ClassWriter cw, + final boolean named, + final ByteVector bv, + final ByteVector parent, + final int offset) + { + super(Opcodes.ASM4); + this.cw = cw; + this.named = named; + this.bv = bv; + this.parent = parent; + this.offset = offset; + } + + // ------------------------------------------------------------------------ + // Implementation of the AnnotationVisitor abstract class + // ------------------------------------------------------------------------ + + @Override + public void visit(final String name, final Object value) { + ++size; + if (named) { + bv.putShort(cw.newUTF8(name)); + } + if (value instanceof String) { + bv.put12('s', cw.newUTF8((String) value)); + } else if (value instanceof Byte) { + bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index); + } else if (value instanceof Boolean) { + int v = ((Boolean) value).booleanValue() ? 1 : 0; + bv.put12('Z', cw.newInteger(v).index); + } else if (value instanceof Character) { + bv.put12('C', cw.newInteger(((Character) value).charValue()).index); + } else if (value instanceof Short) { + bv.put12('S', cw.newInteger(((Short) value).shortValue()).index); + } else if (value instanceof Type) { + bv.put12('c', cw.newUTF8(((Type) value).getDescriptor())); + } else if (value instanceof byte[]) { + byte[] v = (byte[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('B', cw.newInteger(v[i]).index); + } + } else if (value instanceof boolean[]) { + boolean[] v = (boolean[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index); + } + } else if (value instanceof short[]) { + short[] v = (short[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('S', cw.newInteger(v[i]).index); + } + } else if (value instanceof char[]) { + char[] v = (char[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('C', cw.newInteger(v[i]).index); + } + } else if (value instanceof int[]) { + int[] v = (int[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('I', cw.newInteger(v[i]).index); + } + } else if (value instanceof long[]) { + long[] v = (long[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('J', cw.newLong(v[i]).index); + } + } else if (value instanceof float[]) { + float[] v = (float[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('F', cw.newFloat(v[i]).index); + } + } else if (value instanceof double[]) { + double[] v = (double[]) value; + bv.put12('[', v.length); + for (int i = 0; i < v.length; i++) { + bv.put12('D', cw.newDouble(v[i]).index); + } + } else { + Item i = cw.newConstItem(value); + bv.put12(".s.IFJDCS".charAt(i.type), i.index); + } + } + + @Override + public void visitEnum( + final String name, + final String desc, + final String value) + { + ++size; + if (named) { + bv.putShort(cw.newUTF8(name)); + } + bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value)); + } + + @Override + public AnnotationVisitor visitAnnotation( + final String name, + final String desc) + { + ++size; + if (named) { + bv.putShort(cw.newUTF8(name)); + } + // write tag and type, and reserve space for values count + bv.put12('@', cw.newUTF8(desc)).putShort(0); + return new AnnotationWriter(cw, true, bv, bv, bv.length - 2); + } + + @Override + public AnnotationVisitor visitArray(final String name) { + ++size; + if (named) { + bv.putShort(cw.newUTF8(name)); + } + // write tag, and reserve space for array size + bv.put12('[', 0); + return new AnnotationWriter(cw, false, bv, bv, bv.length - 2); + } + + @Override + public void visitEnd() { + if (parent != null) { + byte[] data = parent.data; + data[offset] = (byte) (size >>> 8); + data[offset + 1] = (byte) size; + } + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + /** + * Returns the size of this annotation writer list. + * + * @return the size of this annotation writer list. + */ + int getSize() { + int size = 0; + AnnotationWriter aw = this; + while (aw != null) { + size += aw.bv.length; + aw = aw.next; + } + return size; + } + + /** + * Puts the annotations of this annotation writer list into the given byte + * vector. + * + * @param out where the annotations must be put. + */ + void put(final ByteVector out) { + int n = 0; + int size = 2; + AnnotationWriter aw = this; + AnnotationWriter last = null; + while (aw != null) { + ++n; + size += aw.bv.length; + aw.visitEnd(); // in case user forgot to call visitEnd + aw.prev = last; + last = aw; + aw = aw.next; + } + out.putInt(size); + out.putShort(n); + aw = last; + while (aw != null) { + out.putByteArray(aw.bv.data, 0, aw.bv.length); + aw = aw.prev; + } + } + + /** + * Puts the given annotation lists into the given byte vector. + * + * @param panns an array of annotation writer lists. + * @param off index of the first annotation to be written. + * @param out where the annotations must be put. + */ + static void put( + final AnnotationWriter[] panns, + final int off, + final ByteVector out) + { + int size = 1 + 2 * (panns.length - off); + for (int i = off; i < panns.length; ++i) { + size += panns[i] == null ? 0 : panns[i].getSize(); + } + out.putInt(size).putByte(panns.length - off); + for (int i = off; i < panns.length; ++i) { + AnnotationWriter aw = panns[i]; + AnnotationWriter last = null; + int n = 0; + while (aw != null) { + ++n; + aw.visitEnd(); // in case user forgot to call visitEnd + aw.prev = last; + last = aw; + aw = aw.next; + } + out.putShort(n); + aw = last; + while (aw != null) { + out.putByteArray(aw.bv.data, 0, aw.bv.length); + aw = aw.prev; + } + } + } +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Attribute.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Attribute.java new file mode 100644 index 00000000000..03817bc7841 --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Attribute.java @@ -0,0 +1,283 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +/** + * A non standard class, field, method or code attribute. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public class Attribute { + + /** + * The type of this attribute. + */ + public final String type; + + /** + * The raw value of this attribute, used only for unknown attributes. + */ + byte[] value; + + /** + * The next attribute in this attribute list. May be null. + */ + Attribute next; + + /** + * Constructs a new empty attribute. + * + * @param type the type of the attribute. + */ + protected Attribute(final String type) { + this.type = type; + } + + /** + * Returns true if this type of attribute is unknown. The default + * implementation of this method always returns true. + * + * @return true if this type of attribute is unknown. + */ + public boolean isUnknown() { + return true; + } + + /** + * Returns true if this type of attribute is a code attribute. + * + * @return true if this type of attribute is a code attribute. + */ + public boolean isCodeAttribute() { + return false; + } + + /** + * Returns the labels corresponding to this attribute. + * + * @return the labels corresponding to this attribute, or null if + * this attribute is not a code attribute that contains labels. + */ + protected Label[] getLabels() { + return null; + } + + /** + * Reads a {@link #type type} attribute. This method must return a new + * {@link Attribute} object, of type {@link #type type}, corresponding to + * the len bytes starting at the given offset, in the given class + * reader. + * + * @param cr the class that contains the attribute to be read. + * @param off index of the first byte of the attribute's content in {@link + * ClassReader#b cr.b}. The 6 attribute header bytes, containing the + * type and the length of the attribute, are not taken into account + * here. + * @param len the length of the attribute's content. + * @param buf buffer to be used to call + * {@link ClassReader#readUTF8 readUTF8}, + * {@link ClassReader#readClass(int,char[]) readClass} or + * {@link ClassReader#readConst readConst}. + * @param codeOff index of the first byte of code's attribute content in + * {@link ClassReader#b cr.b}, or -1 if the attribute to be read is + * not a code attribute. The 6 attribute header bytes, containing the + * type and the length of the attribute, are not taken into account + * here. + * @param labels the labels of the method's code, or null if the + * attribute to be read is not a code attribute. + * @return a new {@link Attribute} object corresponding to the given + * bytes. + */ + protected Attribute read( + final ClassReader cr, + final int off, + final int len, + final char[] buf, + final int codeOff, + final Label[] labels) + { + Attribute attr = new Attribute(type); + attr.value = new byte[len]; + System.arraycopy(cr.b, off, attr.value, 0, len); + return attr; + } + + /** + * Returns the byte array form of this attribute. + * + * @param cw the class to which this attribute must be added. This parameter + * can be used to add to the constant pool of this class the items + * that corresponds to this attribute. + * @param code the bytecode of the method corresponding to this code + * attribute, or null if this attribute is not a code + * attributes. + * @param len the length of the bytecode of the method corresponding to this + * code attribute, or null if this attribute is not a code + * attribute. + * @param maxStack the maximum stack size of the method corresponding to + * this code attribute, or -1 if this attribute is not a code + * attribute. + * @param maxLocals the maximum number of local variables of the method + * corresponding to this code attribute, or -1 if this attribute is + * not a code attribute. + * @return the byte array form of this attribute. + */ + protected ByteVector write( + final ClassWriter cw, + final byte[] code, + final int len, + final int maxStack, + final int maxLocals) + { + ByteVector v = new ByteVector(); + v.data = value; + v.length = value.length; + return v; + } + + /** + * Returns the length of the attribute list that begins with this attribute. + * + * @return the length of the attribute list that begins with this attribute. + */ + final int getCount() { + int count = 0; + Attribute attr = this; + while (attr != null) { + count += 1; + attr = attr.next; + } + return count; + } + + /** + * Returns the size of all the attributes in this attribute list. + * + * @param cw the class writer to be used to convert the attributes into byte + * arrays, with the {@link #write write} method. + * @param code the bytecode of the method corresponding to these code + * attributes, or null if these attributes are not code + * attributes. + * @param len the length of the bytecode of the method corresponding to + * these code attributes, or null if these attributes are + * not code attributes. + * @param maxStack the maximum stack size of the method corresponding to + * these code attributes, or -1 if these attributes are not code + * attributes. + * @param maxLocals the maximum number of local variables of the method + * corresponding to these code attributes, or -1 if these attributes + * are not code attributes. + * @return the size of all the attributes in this attribute list. This size + * includes the size of the attribute headers. + */ + final int getSize( + final ClassWriter cw, + final byte[] code, + final int len, + final int maxStack, + final int maxLocals) + { + Attribute attr = this; + int size = 0; + while (attr != null) { + cw.newUTF8(attr.type); + size += attr.write(cw, code, len, maxStack, maxLocals).length + 6; + attr = attr.next; + } + return size; + } + + /** + * Writes all the attributes of this attribute list in the given byte + * vector. + * + * @param cw the class writer to be used to convert the attributes into byte + * arrays, with the {@link #write write} method. + * @param code the bytecode of the method corresponding to these code + * attributes, or null if these attributes are not code + * attributes. + * @param len the length of the bytecode of the method corresponding to + * these code attributes, or null if these attributes are + * not code attributes. + * @param maxStack the maximum stack size of the method corresponding to + * these code attributes, or -1 if these attributes are not code + * attributes. + * @param maxLocals the maximum number of local variables of the method + * corresponding to these code attributes, or -1 if these attributes + * are not code attributes. + * @param out where the attributes must be written. + */ + final void put( + final ClassWriter cw, + final byte[] code, + final int len, + final int maxStack, + final int maxLocals, + final ByteVector out) + { + Attribute attr = this; + while (attr != null) { + ByteVector b = attr.write(cw, code, len, maxStack, maxLocals); + out.putShort(cw.newUTF8(attr.type)).putInt(b.length); + out.putByteArray(b.data, 0, b.length); + attr = attr.next; + } + } +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ByteVector.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ByteVector.java new file mode 100644 index 00000000000..6a00f9da48c --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ByteVector.java @@ -0,0 +1,322 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +/** + * A dynamically extensible vector of bytes. This class is roughly equivalent to + * a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient. + * + * @author Eric Bruneton + */ +public class ByteVector { + + /** + * The content of this vector. + */ + byte[] data; + + /** + * Actual number of bytes in this vector. + */ + int length; + + /** + * Constructs a new {@link ByteVector ByteVector} with a default initial + * size. + */ + public ByteVector() { + data = new byte[64]; + } + + /** + * Constructs a new {@link ByteVector ByteVector} with the given initial + * size. + * + * @param initialSize the initial size of the byte vector to be constructed. + */ + public ByteVector(final int initialSize) { + data = new byte[initialSize]; + } + + /** + * Puts a byte into this byte vector. The byte vector is automatically + * enlarged if necessary. + * + * @param b a byte. + * @return this byte vector. + */ + public ByteVector putByte(final int b) { + int length = this.length; + if (length + 1 > data.length) { + enlarge(1); + } + data[length++] = (byte) b; + this.length = length; + return this; + } + + /** + * Puts two bytes into this byte vector. The byte vector is automatically + * enlarged if necessary. + * + * @param b1 a byte. + * @param b2 another byte. + * @return this byte vector. + */ + ByteVector put11(final int b1, final int b2) { + int length = this.length; + if (length + 2 > data.length) { + enlarge(2); + } + byte[] data = this.data; + data[length++] = (byte) b1; + data[length++] = (byte) b2; + this.length = length; + return this; + } + + /** + * Puts a short into this byte vector. The byte vector is automatically + * enlarged if necessary. + * + * @param s a short. + * @return this byte vector. + */ + public ByteVector putShort(final int s) { + int length = this.length; + if (length + 2 > data.length) { + enlarge(2); + } + byte[] data = this.data; + data[length++] = (byte) (s >>> 8); + data[length++] = (byte) s; + this.length = length; + return this; + } + + /** + * Puts a byte and a short into this byte vector. The byte vector is + * automatically enlarged if necessary. + * + * @param b a byte. + * @param s a short. + * @return this byte vector. + */ + ByteVector put12(final int b, final int s) { + int length = this.length; + if (length + 3 > data.length) { + enlarge(3); + } + byte[] data = this.data; + data[length++] = (byte) b; + data[length++] = (byte) (s >>> 8); + data[length++] = (byte) s; + this.length = length; + return this; + } + + /** + * Puts an int into this byte vector. The byte vector is automatically + * enlarged if necessary. + * + * @param i an int. + * @return this byte vector. + */ + public ByteVector putInt(final int i) { + int length = this.length; + if (length + 4 > data.length) { + enlarge(4); + } + byte[] data = this.data; + data[length++] = (byte) (i >>> 24); + data[length++] = (byte) (i >>> 16); + data[length++] = (byte) (i >>> 8); + data[length++] = (byte) i; + this.length = length; + return this; + } + + /** + * Puts a long into this byte vector. The byte vector is automatically + * enlarged if necessary. + * + * @param l a long. + * @return this byte vector. + */ + public ByteVector putLong(final long l) { + int length = this.length; + if (length + 8 > data.length) { + enlarge(8); + } + byte[] data = this.data; + int i = (int) (l >>> 32); + data[length++] = (byte) (i >>> 24); + data[length++] = (byte) (i >>> 16); + data[length++] = (byte) (i >>> 8); + data[length++] = (byte) i; + i = (int) l; + data[length++] = (byte) (i >>> 24); + data[length++] = (byte) (i >>> 16); + data[length++] = (byte) (i >>> 8); + data[length++] = (byte) i; + this.length = length; + return this; + } + + /** + * Puts an UTF8 string into this byte vector. The byte vector is + * automatically enlarged if necessary. + * + * @param s a String. + * @return this byte vector. + */ + public ByteVector putUTF8(final String s) { + int charLength = s.length(); + int len = length; + if (len + 2 + charLength > data.length) { + enlarge(2 + charLength); + } + byte[] data = this.data; + // optimistic algorithm: instead of computing the byte length and then + // serializing the string (which requires two loops), we assume the byte + // length is equal to char length (which is the most frequent case), and + // we start serializing the string right away. During the serialization, + // if we find that this assumption is wrong, we continue with the + // general method. + data[len++] = (byte) (charLength >>> 8); + data[len++] = (byte) charLength; + for (int i = 0; i < charLength; ++i) { + char c = s.charAt(i); + if (c >= '\001' && c <= '\177') { + data[len++] = (byte) c; + } else { + int byteLength = i; + for (int j = i; j < charLength; ++j) { + c = s.charAt(j); + if (c >= '\001' && c <= '\177') { + byteLength++; + } else if (c > '\u07FF') { + byteLength += 3; + } else { + byteLength += 2; + } + } + data[length] = (byte) (byteLength >>> 8); + data[length + 1] = (byte) byteLength; + if (length + 2 + byteLength > data.length) { + length = len; + enlarge(2 + byteLength); + data = this.data; + } + for (int j = i; j < charLength; ++j) { + c = s.charAt(j); + if (c >= '\001' && c <= '\177') { + data[len++] = (byte) c; + } else if (c > '\u07FF') { + data[len++] = (byte) (0xE0 | c >> 12 & 0xF); + data[len++] = (byte) (0x80 | c >> 6 & 0x3F); + data[len++] = (byte) (0x80 | c & 0x3F); + } else { + data[len++] = (byte) (0xC0 | c >> 6 & 0x1F); + data[len++] = (byte) (0x80 | c & 0x3F); + } + } + break; + } + } + length = len; + return this; + } + + /** + * Puts an array of bytes into this byte vector. The byte vector is + * automatically enlarged if necessary. + * + * @param b an array of bytes. May be null to put len + * null bytes into this byte vector. + * @param off index of the fist byte of b that must be copied. + * @param len number of bytes of b that must be copied. + * @return this byte vector. + */ + public ByteVector putByteArray(final byte[] b, final int off, final int len) + { + if (length + len > data.length) { + enlarge(len); + } + if (b != null) { + System.arraycopy(b, off, data, length, len); + } + length += len; + return this; + } + + /** + * Enlarge this byte vector so that it can receive n more bytes. + * + * @param size number of additional bytes that this byte vector should be + * able to receive. + */ + private void enlarge(final int size) { + int length1 = 2 * data.length; + int length2 = length + size; + byte[] newData = new byte[length1 > length2 ? length1 : length2]; + System.arraycopy(data, 0, newData, 0, length); + data = newData; + } +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java new file mode 100644 index 00000000000..99d8a1092f4 --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java @@ -0,0 +1,2245 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +import java.io.IOException; +import java.io.InputStream; + +/** + * A Java class parser to make a {@link ClassVisitor} visit an existing class. + * This class parses a byte array conforming to the Java class file format and + * calls the appropriate visit methods of a given class visitor for each field, + * method and bytecode instruction encountered. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public class ClassReader { + + /** + * True to enable signatures support. + */ + static final boolean SIGNATURES = true; + + /** + * True to enable annotations support. + */ + static final boolean ANNOTATIONS = true; + + /** + * True to enable stack map frames support. + */ + static final boolean FRAMES = true; + + /** + * True to enable bytecode writing support. + */ + static final boolean WRITER = true; + + /** + * True to enable JSR_W and GOTO_W support. + */ + static final boolean RESIZE = true; + + /** + * Flag to skip method code. If this class is set CODE + * attribute won't be visited. This can be used, for example, to retrieve + * annotations for methods and method parameters. + */ + public static final int SKIP_CODE = 1; + + /** + * Flag to skip the debug information in the class. If this flag is set the + * debug information of the class is not visited, i.e. the + * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and + * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be + * called. + */ + public static final int SKIP_DEBUG = 2; + + /** + * Flag to skip the stack map frames in the class. If this flag is set the + * stack map frames of the class is not visited, i.e. the + * {@link MethodVisitor#visitFrame visitFrame} method will not be called. + * This flag is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is + * used: it avoids visiting frames that will be ignored and recomputed from + * scratch in the class writer. + */ + public static final int SKIP_FRAMES = 4; + + /** + * Flag to expand the stack map frames. By default stack map frames are + * visited in their original format (i.e. "expanded" for classes whose + * version is less than V1_6, and "compressed" for the other classes). If + * this flag is set, stack map frames are always visited in expanded format + * (this option adds a decompression/recompression step in ClassReader and + * ClassWriter which degrades performances quite a lot). + */ + public static final int EXPAND_FRAMES = 8; + + /** + * The class to be parsed. The content of this array must not be + * modified. This field is intended for {@link Attribute} sub classes, and + * is normally not needed by class generators or adapters. + */ + public final byte[] b; + + /** + * The start index of each constant pool item in {@link #b b}, plus one. + * The one byte offset skips the constant pool item tag that indicates its + * type. + */ + private final int[] items; + + /** + * The String objects corresponding to the CONSTANT_Utf8 items. This cache + * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item, + * which GREATLY improves performances (by a factor 2 to 3). This caching + * strategy could be extended to all constant pool items, but its benefit + * would not be so great for these items (because they are much less + * expensive to parse than CONSTANT_Utf8 items). + */ + private final String[] strings; + + /** + * Maximum length of the strings contained in the constant pool of the + * class. + */ + private final int maxStringLength; + + /** + * Start index of the class header information (access, name...) in + * {@link #b b}. + */ + public final int header; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructs a new {@link ClassReader} object. + * + * @param b the bytecode of the class to be read. + */ + public ClassReader(final byte[] b) { + this(b, 0, b.length); + } + + /** + * Constructs a new {@link ClassReader} object. + * + * @param b the bytecode of the class to be read. + * @param off the start offset of the class data. + * @param len the length of the class data. + */ + public ClassReader(final byte[] b, final int off, final int len) { + this.b = b; + // checks the class version + if (readShort(6) > Opcodes.V1_7) { + throw new IllegalArgumentException(); + } + // parses the constant pool + items = new int[readUnsignedShort(off + 8)]; + int n = items.length; + strings = new String[n]; + int max = 0; + int index = off + 10; + for (int i = 1; i < n; ++i) { + items[i] = index + 1; + int size; + switch (b[index]) { + case ClassWriter.FIELD: + case ClassWriter.METH: + case ClassWriter.IMETH: + case ClassWriter.INT: + case ClassWriter.FLOAT: + case ClassWriter.NAME_TYPE: + case ClassWriter.INDY: + size = 5; + break; + case ClassWriter.LONG: + case ClassWriter.DOUBLE: + size = 9; + ++i; + break; + case ClassWriter.UTF8: + size = 3 + readUnsignedShort(index + 1); + if (size > max) { + max = size; + } + break; + case ClassWriter.HANDLE: + size = 4; + break; + // case ClassWriter.CLASS: + // case ClassWriter.STR: + // case ClassWriter.MTYPE + default: + size = 3; + break; + } + index += size; + } + maxStringLength = max; + // the class header information starts just after the constant pool + header = index; + } + + /** + * Returns the class's access flags (see {@link Opcodes}). This value may + * not reflect Deprecated and Synthetic flags when bytecode is before 1.5 + * and those flags are represented by attributes. + * + * @return the class access flags + * + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public int getAccess() { + return readUnsignedShort(header); + } + + /** + * Returns the internal name of the class (see + * {@link Type#getInternalName() getInternalName}). + * + * @return the internal class name + * + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public String getClassName() { + return readClass(header + 2, new char[maxStringLength]); + } + + /** + * Returns the internal of name of the super class (see + * {@link Type#getInternalName() getInternalName}). For interfaces, the + * super class is {@link Object}. + * + * @return the internal name of super class, or null for + * {@link Object} class. + * + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public String getSuperName() { + int n = items[readUnsignedShort(header + 4)]; + return n == 0 ? null : readUTF8(n, new char[maxStringLength]); + } + + /** + * Returns the internal names of the class's interfaces (see + * {@link Type#getInternalName() getInternalName}). + * + * @return the array of internal names for all implemented interfaces or + * null. + * + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public String[] getInterfaces() { + int index = header + 6; + int n = readUnsignedShort(index); + String[] interfaces = new String[n]; + if (n > 0) { + char[] buf = new char[maxStringLength]; + for (int i = 0; i < n; ++i) { + index += 2; + interfaces[i] = readClass(index, buf); + } + } + return interfaces; + } + + /** + * Copies the constant pool data into the given {@link ClassWriter}. Should + * be called before the {@link #accept(ClassVisitor,int)} method. + * + * @param classWriter the {@link ClassWriter} to copy constant pool into. + */ + void copyPool(final ClassWriter classWriter) { + char[] buf = new char[maxStringLength]; + int ll = items.length; + Item[] items2 = new Item[ll]; + for (int i = 1; i < ll; i++) { + int index = items[i]; + int tag = b[index - 1]; + Item item = new Item(i); + int nameType; + switch (tag) { + case ClassWriter.FIELD: + case ClassWriter.METH: + case ClassWriter.IMETH: + nameType = items[readUnsignedShort(index + 2)]; + item.set(tag, + readClass(index, buf), + readUTF8(nameType, buf), + readUTF8(nameType + 2, buf)); + break; + + case ClassWriter.INT: + item.set(readInt(index)); + break; + + case ClassWriter.FLOAT: + item.set(Float.intBitsToFloat(readInt(index))); + break; + + case ClassWriter.NAME_TYPE: + item.set(tag, + readUTF8(index, buf), + readUTF8(index + 2, buf), + null); + break; + + case ClassWriter.LONG: + item.set(readLong(index)); + ++i; + break; + + case ClassWriter.DOUBLE: + item.set(Double.longBitsToDouble(readLong(index))); + ++i; + break; + + case ClassWriter.UTF8: { + String s = strings[i]; + if (s == null) { + index = items[i]; + s = strings[i] = readUTF(index + 2, + readUnsignedShort(index), + buf); + } + item.set(tag, s, null, null); + } + break; + + case ClassWriter.HANDLE: { + int fieldOrMethodRef = items[readUnsignedShort(index + 1)]; + nameType = items[readUnsignedShort(fieldOrMethodRef + 2)]; + item.set(ClassWriter.HANDLE_BASE + readByte(index), + readClass(fieldOrMethodRef, buf), + readUTF8(nameType, buf), + readUTF8(nameType + 2, buf)); + + } + break; + + + case ClassWriter.INDY: + if (classWriter.bootstrapMethods == null) { + copyBootstrapMethods(classWriter, items2, buf); + } + nameType = items[readUnsignedShort(index + 2)]; + item.set(readUTF8(nameType, buf), + readUTF8(nameType + 2, buf), + readUnsignedShort(index)); + break; + + + // case ClassWriter.STR: + // case ClassWriter.CLASS: + // case ClassWriter.MTYPE + default: + item.set(tag, readUTF8(index, buf), null, null); + break; + } + + int index2 = item.hashCode % items2.length; + item.next = items2[index2]; + items2[index2] = item; + } + + int off = items[1] - 1; + classWriter.pool.putByteArray(b, off, header - off); + classWriter.items = items2; + classWriter.threshold = (int) (0.75d * ll); + classWriter.index = ll; + } + + private void copyBootstrapMethods(ClassWriter classWriter, Item[] items2, char[] buf) { + int i, j, k, u, v; + + // skip class header + v = header; + v += 8 + (readUnsignedShort(v + 6) << 1); + + // skips fields and methods + i = readUnsignedShort(v); + v += 2; + for (; i > 0; --i) { + j = readUnsignedShort(v + 6); + v += 8; + for (; j > 0; --j) { + v += 6 + readInt(v + 2); + } + } + i = readUnsignedShort(v); + v += 2; + for (; i > 0; --i) { + j = readUnsignedShort(v + 6); + v += 8; + for (; j > 0; --j) { + v += 6 + readInt(v + 2); + } + } + + // read class attributes + i = readUnsignedShort(v); + v += 2; + for (; i > 0; --i) { + String attrName = readUTF8(v, buf); + int size = readInt(v + 2); + if ("BootstrapMethods".equals(attrName)) { + int boostrapMethodCount = readUnsignedShort(v + 6); + int x = v + 8; + for (j = 0; j < boostrapMethodCount; j++) { + int hashCode = readConst(readUnsignedShort(x), buf).hashCode(); + k = readUnsignedShort(x + 2); + u = x + 4; + for(; k > 0; --k) { + hashCode ^= readConst(readUnsignedShort(u), buf).hashCode(); + u += 2; + } + Item item = new Item(j); + item.set(x - v - 8, hashCode & 0x7FFFFFFF); + + int index2 = item.hashCode % items2.length; + item.next = items2[index2]; + items2[index2] = item; + + x = u; + } + + classWriter.bootstrapMethodsCount = boostrapMethodCount; + ByteVector bootstrapMethods = new ByteVector(size + 62); + bootstrapMethods.putByteArray(b, v + 8, size - 2); + classWriter.bootstrapMethods = bootstrapMethods; + return; + } + v += 6 + size; + } + + // we are in trouble !!! + } + + /** + * Constructs a new {@link ClassReader} object. + * + * @param is an input stream from which to read the class. + * @throws IOException if a problem occurs during reading. + */ + public ClassReader(final InputStream is) throws IOException { + this(readClass(is, false)); + } + + /** + * Constructs a new {@link ClassReader} object. + * + * @param name the binary qualified name of the class to be read. + * @throws IOException if an exception occurs during reading. + */ + public ClassReader(final String name) throws IOException { + this(readClass(ClassLoader.getSystemResourceAsStream(name.replace('.', '/') + + ".class"), true)); + } + + /** + * Reads the bytecode of a class. + * + * @param is an input stream from which to read the class. + * @param close true to close the input stream after reading. + * @return the bytecode read from the given input stream. + * @throws IOException if a problem occurs during reading. + */ + private static byte[] readClass(final InputStream is, boolean close) + throws IOException + { + if (is == null) { + throw new IOException("Class not found"); + } + try { + byte[] b = new byte[is.available()]; + int len = 0; + while (true) { + int n = is.read(b, len, b.length - len); + if (n == -1) { + if (len < b.length) { + byte[] c = new byte[len]; + System.arraycopy(b, 0, c, 0, len); + b = c; + } + return b; + } + len += n; + if (len == b.length) { + int last = is.read(); + if (last < 0) { + return b; + } + byte[] c = new byte[b.length + 1000]; + System.arraycopy(b, 0, c, 0, len); + c[len++] = (byte) last; + b = c; + } + } + } finally { + if (close) { + is.close(); + } + } + } + + // ------------------------------------------------------------------------ + // Public methods + // ------------------------------------------------------------------------ + + /** + * Makes the given visitor visit the Java class of this {@link ClassReader}. + * This class is the one specified in the constructor (see + * {@link #ClassReader(byte[]) ClassReader}). + * + * @param classVisitor the visitor that must visit this class. + * @param flags option flags that can be used to modify the default behavior + * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}, + * {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. + */ + public void accept(final ClassVisitor classVisitor, final int flags) { + accept(classVisitor, new Attribute[0], flags); + } + + /** + * Makes the given visitor visit the Java class of this {@link ClassReader}. + * This class is the one specified in the constructor (see + * {@link #ClassReader(byte[]) ClassReader}). + * + * @param classVisitor the visitor that must visit this class. + * @param attrs prototypes of the attributes that must be parsed during the + * visit of the class. Any attribute whose type is not equal to the + * type of one the prototypes will not be parsed: its byte array + * value will be passed unchanged to the ClassWriter. This may + * corrupt it if this value contains references to the constant pool, + * or has syntactic or semantic links with a class element that has + * been transformed by a class adapter between the reader and the + * writer. + * @param flags option flags that can be used to modify the default behavior + * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}, + * {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. + */ + public void accept( + final ClassVisitor classVisitor, + final Attribute[] attrs, + final int flags) + { + byte[] b = this.b; // the bytecode array + char[] c = new char[maxStringLength]; // buffer used to read strings + int i, j, k; // loop variables + int u, v, w; // indexes in b + Attribute attr; + + int access; + String name; + String desc; + String attrName; + String signature; + int anns = 0; + int ianns = 0; + Attribute cattrs = null; + + // visits the header + u = header; + access = readUnsignedShort(u); + name = readClass(u + 2, c); + v = items[readUnsignedShort(u + 4)]; + String superClassName = v == 0 ? null : readUTF8(v, c); + String[] implementedItfs = new String[readUnsignedShort(u + 6)]; + w = 0; + u += 8; + for (i = 0; i < implementedItfs.length; ++i) { + implementedItfs[i] = readClass(u, c); + u += 2; + } + + boolean skipCode = (flags & SKIP_CODE) != 0; + boolean skipDebug = (flags & SKIP_DEBUG) != 0; + boolean unzip = (flags & EXPAND_FRAMES) != 0; + + // skips fields and methods + v = u; + i = readUnsignedShort(v); + v += 2; + for (; i > 0; --i) { + j = readUnsignedShort(v + 6); + v += 8; + for (; j > 0; --j) { + v += 6 + readInt(v + 2); + } + } + i = readUnsignedShort(v); + v += 2; + for (; i > 0; --i) { + j = readUnsignedShort(v + 6); + v += 8; + for (; j > 0; --j) { + v += 6 + readInt(v + 2); + } + } + // reads the class's attributes + signature = null; + String sourceFile = null; + String sourceDebug = null; + String enclosingOwner = null; + String enclosingName = null; + String enclosingDesc = null; + int[] bootstrapMethods = null; // start indexed of the bsms + + i = readUnsignedShort(v); + v += 2; + for (; i > 0; --i) { + attrName = readUTF8(v, c); + // tests are sorted in decreasing frequency order + // (based on frequencies observed on typical classes) + if ("SourceFile".equals(attrName)) { + sourceFile = readUTF8(v + 6, c); + } else if ("InnerClasses".equals(attrName)) { + w = v + 6; + } else if ("EnclosingMethod".equals(attrName)) { + enclosingOwner = readClass(v + 6, c); + int item = readUnsignedShort(v + 8); + if (item != 0) { + enclosingName = readUTF8(items[item], c); + enclosingDesc = readUTF8(items[item] + 2, c); + } + } else if (SIGNATURES && "Signature".equals(attrName)) { + signature = readUTF8(v + 6, c); + } else if (ANNOTATIONS && "RuntimeVisibleAnnotations".equals(attrName)) { + anns = v + 6; + } else if ("Deprecated".equals(attrName)) { + access |= Opcodes.ACC_DEPRECATED; + } else if ("Synthetic".equals(attrName)) { + access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; + } else if ("SourceDebugExtension".equals(attrName)) { + int len = readInt(v + 2); + sourceDebug = readUTF(v + 6, len, new char[len]); + } else if (ANNOTATIONS && "RuntimeInvisibleAnnotations".equals(attrName)) { + ianns = v + 6; + } else if ("BootstrapMethods".equals(attrName)) { + int boostrapMethodCount = readUnsignedShort(v + 6); + bootstrapMethods = new int[boostrapMethodCount]; + int x = v + 8; + for (j = 0; j < boostrapMethodCount; j++) { + bootstrapMethods[j] = x; + x += 2 + readUnsignedShort(x + 2) << 1; + } + } else { + attr = readAttribute(attrs, + attrName, + v + 6, + readInt(v + 2), + c, + -1, + null); + if (attr != null) { + attr.next = cattrs; + cattrs = attr; + } + } + v += 6 + readInt(v + 2); + } + // calls the visit method + classVisitor.visit(readInt(4), + access, + name, + signature, + superClassName, + implementedItfs); + + // calls the visitSource method + if (!skipDebug && (sourceFile != null || sourceDebug != null)) { + classVisitor.visitSource(sourceFile, sourceDebug); + } + + // calls the visitOuterClass method + if (enclosingOwner != null) { + classVisitor.visitOuterClass(enclosingOwner, + enclosingName, + enclosingDesc); + } + + // visits the class annotations + if (ANNOTATIONS) { + for (i = 1; i >= 0; --i) { + v = i == 0 ? ianns : anns; + if (v != 0) { + j = readUnsignedShort(v); + v += 2; + for (; j > 0; --j) { + v = readAnnotationValues(v + 2, + c, + true, + classVisitor.visitAnnotation(readUTF8(v, c), i != 0)); + } + } + } + } + + // visits the class attributes + while (cattrs != null) { + attr = cattrs.next; + cattrs.next = null; + classVisitor.visitAttribute(cattrs); + cattrs = attr; + } + + // calls the visitInnerClass method + if (w != 0) { + i = readUnsignedShort(w); + w += 2; + for (; i > 0; --i) { + classVisitor.visitInnerClass(readUnsignedShort(w) == 0 + ? null + : readClass(w, c), readUnsignedShort(w + 2) == 0 + ? null + : readClass(w + 2, c), readUnsignedShort(w + 4) == 0 + ? null + : readUTF8(w + 4, c), readUnsignedShort(w + 6)); + w += 8; + } + } + + // visits the fields + i = readUnsignedShort(u); + u += 2; + for (; i > 0; --i) { + access = readUnsignedShort(u); + name = readUTF8(u + 2, c); + desc = readUTF8(u + 4, c); + // visits the field's attributes and looks for a ConstantValue + // attribute + int fieldValueItem = 0; + signature = null; + anns = 0; + ianns = 0; + cattrs = null; + + j = readUnsignedShort(u + 6); + u += 8; + for (; j > 0; --j) { + attrName = readUTF8(u, c); + // tests are sorted in decreasing frequency order + // (based on frequencies observed on typical classes) + if ("ConstantValue".equals(attrName)) { + fieldValueItem = readUnsignedShort(u + 6); + } else if (SIGNATURES && "Signature".equals(attrName)) { + signature = readUTF8(u + 6, c); + } else if ("Deprecated".equals(attrName)) { + access |= Opcodes.ACC_DEPRECATED; + } else if ("Synthetic".equals(attrName)) { + access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; + } else if (ANNOTATIONS && "RuntimeVisibleAnnotations".equals(attrName)) { + anns = u + 6; + } else if (ANNOTATIONS && "RuntimeInvisibleAnnotations".equals(attrName)) { + ianns = u + 6; + } else { + attr = readAttribute(attrs, + attrName, + u + 6, + readInt(u + 2), + c, + -1, + null); + if (attr != null) { + attr.next = cattrs; + cattrs = attr; + } + } + u += 6 + readInt(u + 2); + } + // visits the field + FieldVisitor fv = classVisitor.visitField(access, + name, + desc, + signature, + fieldValueItem == 0 ? null : readConst(fieldValueItem, c)); + // visits the field annotations and attributes + if (fv != null) { + if (ANNOTATIONS) { + for (j = 1; j >= 0; --j) { + v = j == 0 ? ianns : anns; + if (v != 0) { + k = readUnsignedShort(v); + v += 2; + for (; k > 0; --k) { + v = readAnnotationValues(v + 2, + c, + true, + fv.visitAnnotation(readUTF8(v, c), j != 0)); + } + } + } + } + while (cattrs != null) { + attr = cattrs.next; + cattrs.next = null; + fv.visitAttribute(cattrs); + cattrs = attr; + } + fv.visitEnd(); + } + } + + // visits the methods + i = readUnsignedShort(u); + u += 2; + for (; i > 0; --i) { + int u0 = u + 6; + access = readUnsignedShort(u); + name = readUTF8(u + 2, c); + desc = readUTF8(u + 4, c); + signature = null; + anns = 0; + ianns = 0; + int dann = 0; + int mpanns = 0; + int impanns = 0; + cattrs = null; + v = 0; + w = 0; + + // looks for Code and Exceptions attributes + j = readUnsignedShort(u + 6); + u += 8; + for (; j > 0; --j) { + attrName = readUTF8(u, c); + int attrSize = readInt(u + 2); + u += 6; + // tests are sorted in decreasing frequency order + // (based on frequencies observed on typical classes) + if ("Code".equals(attrName)) { + if (!skipCode) { + v = u; + } + } else if ("Exceptions".equals(attrName)) { + w = u; + } else if (SIGNATURES && "Signature".equals(attrName)) { + signature = readUTF8(u, c); + } else if ("Deprecated".equals(attrName)) { + access |= Opcodes.ACC_DEPRECATED; + } else if (ANNOTATIONS && "RuntimeVisibleAnnotations".equals(attrName)) { + anns = u; + } else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) { + dann = u; + } else if ("Synthetic".equals(attrName)) { + access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; + } else if (ANNOTATIONS && "RuntimeInvisibleAnnotations".equals(attrName)) { + ianns = u; + } else if (ANNOTATIONS && "RuntimeVisibleParameterAnnotations".equals(attrName)) + { + mpanns = u; + } else if (ANNOTATIONS && "RuntimeInvisibleParameterAnnotations".equals(attrName)) + { + impanns = u; + } else { + attr = readAttribute(attrs, + attrName, + u, + attrSize, + c, + -1, + null); + if (attr != null) { + attr.next = cattrs; + cattrs = attr; + } + } + u += attrSize; + } + // reads declared exceptions + String[] exceptions; + if (w == 0) { + exceptions = null; + } else { + exceptions = new String[readUnsignedShort(w)]; + w += 2; + for (j = 0; j < exceptions.length; ++j) { + exceptions[j] = readClass(w, c); + w += 2; + } + } + + // visits the method's code, if any + MethodVisitor mv = classVisitor.visitMethod(access, + name, + desc, + signature, + exceptions); + + if (mv != null) { + /* + * if the returned MethodVisitor is in fact a MethodWriter, it + * means there is no method adapter between the reader and the + * writer. If, in addition, the writer's constant pool was + * copied from this reader (mw.cw.cr == this), and the signature + * and exceptions of the method have not been changed, then it + * is possible to skip all visit events and just copy the + * original code of the method to the writer (the access, name + * and descriptor can have been changed, this is not important + * since they are not copied as is from the reader). + */ + if (WRITER && mv instanceof MethodWriter) { + MethodWriter mw = (MethodWriter) mv; + if (mw.cw.cr == this) { + if (signature == mw.signature) { + boolean sameExceptions = false; + if (exceptions == null) { + sameExceptions = mw.exceptionCount == 0; + } else { + if (exceptions.length == mw.exceptionCount) { + sameExceptions = true; + for (j = exceptions.length - 1; j >= 0; --j) + { + w -= 2; + if (mw.exceptions[j] != readUnsignedShort(w)) + { + sameExceptions = false; + break; + } + } + } + } + if (sameExceptions) { + /* + * we do not copy directly the code into + * MethodWriter to save a byte array copy + * operation. The real copy will be done in + * ClassWriter.toByteArray(). + */ + mw.classReaderOffset = u0; + mw.classReaderLength = u - u0; + continue; + } + } + } + } + + if (ANNOTATIONS && dann != 0) { + AnnotationVisitor dv = mv.visitAnnotationDefault(); + readAnnotationValue(dann, c, null, dv); + if (dv != null) { + dv.visitEnd(); + } + } + if (ANNOTATIONS) { + for (j = 1; j >= 0; --j) { + w = j == 0 ? ianns : anns; + if (w != 0) { + k = readUnsignedShort(w); + w += 2; + for (; k > 0; --k) { + w = readAnnotationValues(w + 2, + c, + true, + mv.visitAnnotation(readUTF8(w, c), j != 0)); + } + } + } + } + if (ANNOTATIONS && mpanns != 0) { + readParameterAnnotations(mpanns, desc, c, true, mv); + } + if (ANNOTATIONS && impanns != 0) { + readParameterAnnotations(impanns, desc, c, false, mv); + } + while (cattrs != null) { + attr = cattrs.next; + cattrs.next = null; + mv.visitAttribute(cattrs); + cattrs = attr; + } + } + + if (mv != null && v != 0) { + int maxStack = readUnsignedShort(v); + int maxLocals = readUnsignedShort(v + 2); + int codeLength = readInt(v + 4); + v += 8; + + int codeStart = v; + int codeEnd = v + codeLength; + + mv.visitCode(); + + // 1st phase: finds the labels + int label; + Label[] labels = new Label[codeLength + 2]; + readLabel(codeLength + 1, labels); + while (v < codeEnd) { + w = v - codeStart; + int opcode = b[v] & 0xFF; + switch (ClassWriter.TYPE[opcode]) { + case ClassWriter.NOARG_INSN: + case ClassWriter.IMPLVAR_INSN: + v += 1; + break; + case ClassWriter.LABEL_INSN: + readLabel(w + readShort(v + 1), labels); + v += 3; + break; + case ClassWriter.LABELW_INSN: + readLabel(w + readInt(v + 1), labels); + v += 5; + break; + case ClassWriter.WIDE_INSN: + opcode = b[v + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + v += 6; + } else { + v += 4; + } + break; + case ClassWriter.TABL_INSN: + // skips 0 to 3 padding bytes* + v = v + 4 - (w & 3); + // reads instruction + readLabel(w + readInt(v), labels); + j = readInt(v + 8) - readInt(v + 4) + 1; + v += 12; + for (; j > 0; --j) { + readLabel(w + readInt(v), labels); + v += 4; + } + break; + case ClassWriter.LOOK_INSN: + // skips 0 to 3 padding bytes* + v = v + 4 - (w & 3); + // reads instruction + readLabel(w + readInt(v), labels); + j = readInt(v + 4); + v += 8; + for (; j > 0; --j) { + readLabel(w + readInt(v + 4), labels); + v += 8; + } + break; + case ClassWriter.VAR_INSN: + case ClassWriter.SBYTE_INSN: + case ClassWriter.LDC_INSN: + v += 2; + break; + case ClassWriter.SHORT_INSN: + case ClassWriter.LDCW_INSN: + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.TYPE_INSN: + case ClassWriter.IINC_INSN: + v += 3; + break; + case ClassWriter.ITFMETH_INSN: + case ClassWriter.INDYMETH_INSN: + v += 5; + break; + // case MANA_INSN: + default: + v += 4; + break; + } + } + // parses the try catch entries + j = readUnsignedShort(v); + v += 2; + for (; j > 0; --j) { + Label start = readLabel(readUnsignedShort(v), labels); + Label end = readLabel(readUnsignedShort(v + 2), labels); + Label handler = readLabel(readUnsignedShort(v + 4), labels); + int type = readUnsignedShort(v + 6); + if (type == 0) { + mv.visitTryCatchBlock(start, end, handler, null); + } else { + mv.visitTryCatchBlock(start, + end, + handler, + readUTF8(items[type], c)); + } + v += 8; + } + // parses the local variable, line number tables, and code + // attributes + int varTable = 0; + int varTypeTable = 0; + int stackMap = 0; + int stackMapSize = 0; + int frameCount = 0; + int frameMode = 0; + int frameOffset = 0; + int frameLocalCount = 0; + int frameLocalDiff = 0; + int frameStackCount = 0; + Object[] frameLocal = null; + Object[] frameStack = null; + boolean zip = true; + cattrs = null; + j = readUnsignedShort(v); + v += 2; + for (; j > 0; --j) { + attrName = readUTF8(v, c); + if ("LocalVariableTable".equals(attrName)) { + if (!skipDebug) { + varTable = v + 6; + k = readUnsignedShort(v + 6); + w = v + 8; + for (; k > 0; --k) { + label = readUnsignedShort(w); + if (labels[label] == null) { + readLabel(label, labels).status |= Label.DEBUG; + } + label += readUnsignedShort(w + 2); + if (labels[label] == null) { + readLabel(label, labels).status |= Label.DEBUG; + } + w += 10; + } + } + } else if ("LocalVariableTypeTable".equals(attrName)) { + varTypeTable = v + 6; + } else if ("LineNumberTable".equals(attrName)) { + if (!skipDebug) { + k = readUnsignedShort(v + 6); + w = v + 8; + for (; k > 0; --k) { + label = readUnsignedShort(w); + if (labels[label] == null) { + readLabel(label, labels).status |= Label.DEBUG; + } + labels[label].line = readUnsignedShort(w + 2); + w += 4; + } + } + } else if (FRAMES && "StackMapTable".equals(attrName)) { + if ((flags & SKIP_FRAMES) == 0) { + stackMap = v + 8; + stackMapSize = readInt(v + 2); + frameCount = readUnsignedShort(v + 6); + } + /* + * here we do not extract the labels corresponding to + * the attribute content. This would require a full + * parsing of the attribute, which would need to be + * repeated in the second phase (see below). Instead the + * content of the attribute is read one frame at a time + * (i.e. after a frame has been visited, the next frame + * is read), and the labels it contains are also + * extracted one frame at a time. Thanks to the ordering + * of frames, having only a "one frame lookahead" is not + * a problem, i.e. it is not possible to see an offset + * smaller than the offset of the current insn and for + * which no Label exist. + */ + /* + * This is not true for UNINITIALIZED type offsets. We + * solve this by parsing the stack map table without a + * full decoding (see below). + */ + } else if (FRAMES && "StackMap".equals(attrName)) { + if ((flags & SKIP_FRAMES) == 0) { + stackMap = v + 8; + stackMapSize = readInt(v + 2); + frameCount = readUnsignedShort(v + 6); + zip = false; + } + /* + * IMPORTANT! here we assume that the frames are + * ordered, as in the StackMapTable attribute, although + * this is not guaranteed by the attribute format. + */ + } else { + for (k = 0; k < attrs.length; ++k) { + if (attrs[k].type.equals(attrName)) { + attr = attrs[k].read(this, + v + 6, + readInt(v + 2), + c, + codeStart - 8, + labels); + if (attr != null) { + attr.next = cattrs; + cattrs = attr; + } + } + } + } + v += 6 + readInt(v + 2); + } + + // 2nd phase: visits each instruction + if (FRAMES && stackMap != 0) { + // creates the very first (implicit) frame from the method + // descriptor + frameLocal = new Object[maxLocals]; + frameStack = new Object[maxStack]; + if (unzip) { + int local = 0; + if ((access & Opcodes.ACC_STATIC) == 0) { + if ("".equals(name)) { + frameLocal[local++] = Opcodes.UNINITIALIZED_THIS; + } else { + frameLocal[local++] = readClass(header + 2, c); + } + } + j = 1; + loop: while (true) { + k = j; + switch (desc.charAt(j++)) { + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + frameLocal[local++] = Opcodes.INTEGER; + break; + case 'F': + frameLocal[local++] = Opcodes.FLOAT; + break; + case 'J': + frameLocal[local++] = Opcodes.LONG; + break; + case 'D': + frameLocal[local++] = Opcodes.DOUBLE; + break; + case '[': + while (desc.charAt(j) == '[') { + ++j; + } + if (desc.charAt(j) == 'L') { + ++j; + while (desc.charAt(j) != ';') { + ++j; + } + } + frameLocal[local++] = desc.substring(k, ++j); + break; + case 'L': + while (desc.charAt(j) != ';') { + ++j; + } + frameLocal[local++] = desc.substring(k + 1, + j++); + break; + default: + break loop; + } + } + frameLocalCount = local; + } + /* + * for the first explicit frame the offset is not + * offset_delta + 1 but only offset_delta; setting the + * implicit frame offset to -1 allow the use of the + * "offset_delta + 1" rule in all cases + */ + frameOffset = -1; + /* + * Finds labels for UNINITIALIZED frame types. Instead of + * decoding each element of the stack map table, we look + * for 3 consecutive bytes that "look like" an UNINITIALIZED + * type (tag 8, offset within code bounds, NEW instruction + * at this offset). We may find false positives (i.e. not + * real UNINITIALIZED types), but this should be rare, and + * the only consequence will be the creation of an unneeded + * label. This is better than creating a label for each NEW + * instruction, and faster than fully decoding the whole + * stack map table. + */ + for (j = stackMap; j < stackMap + stackMapSize - 2; ++j) { + if (b[j] == 8) { // UNINITIALIZED FRAME TYPE + k = readUnsignedShort(j + 1); + if (k >= 0 && k < codeLength) { // potential offset + if ((b[codeStart + k] & 0xFF) == Opcodes.NEW) { // NEW at this offset + readLabel(k, labels); + } + } + } + } + } + v = codeStart; + Label l; + while (v < codeEnd) { + w = v - codeStart; + + l = labels[w]; + if (l != null) { + mv.visitLabel(l); + if (!skipDebug && l.line > 0) { + mv.visitLineNumber(l.line, l); + } + } + + while (FRAMES && frameLocal != null + && (frameOffset == w || frameOffset == -1)) + { + // if there is a frame for this offset, + // makes the visitor visit it, + // and reads the next frame if there is one. + if (!zip || unzip) { + mv.visitFrame(Opcodes.F_NEW, + frameLocalCount, + frameLocal, + frameStackCount, + frameStack); + } else if (frameOffset != -1) { + mv.visitFrame(frameMode, + frameLocalDiff, + frameLocal, + frameStackCount, + frameStack); + } + + if (frameCount > 0) { + int tag, delta, n; + if (zip) { + tag = b[stackMap++] & 0xFF; + } else { + tag = MethodWriter.FULL_FRAME; + frameOffset = -1; + } + frameLocalDiff = 0; + if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME) + { + delta = tag; + frameMode = Opcodes.F_SAME; + frameStackCount = 0; + } else if (tag < MethodWriter.RESERVED) { + delta = tag + - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME; + stackMap = readFrameType(frameStack, + 0, + stackMap, + c, + labels); + frameMode = Opcodes.F_SAME1; + frameStackCount = 1; + } else { + delta = readUnsignedShort(stackMap); + stackMap += 2; + if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) + { + stackMap = readFrameType(frameStack, + 0, + stackMap, + c, + labels); + frameMode = Opcodes.F_SAME1; + frameStackCount = 1; + } else if (tag >= MethodWriter.CHOP_FRAME + && tag < MethodWriter.SAME_FRAME_EXTENDED) + { + frameMode = Opcodes.F_CHOP; + frameLocalDiff = MethodWriter.SAME_FRAME_EXTENDED + - tag; + frameLocalCount -= frameLocalDiff; + frameStackCount = 0; + } else if (tag == MethodWriter.SAME_FRAME_EXTENDED) + { + frameMode = Opcodes.F_SAME; + frameStackCount = 0; + } else if (tag < MethodWriter.FULL_FRAME) { + j = unzip ? frameLocalCount : 0; + for (k = tag + - MethodWriter.SAME_FRAME_EXTENDED; k > 0; k--) + { + stackMap = readFrameType(frameLocal, + j++, + stackMap, + c, + labels); + } + frameMode = Opcodes.F_APPEND; + frameLocalDiff = tag + - MethodWriter.SAME_FRAME_EXTENDED; + frameLocalCount += frameLocalDiff; + frameStackCount = 0; + } else { // if (tag == FULL_FRAME) { + frameMode = Opcodes.F_FULL; + n = frameLocalDiff = frameLocalCount = readUnsignedShort(stackMap); + stackMap += 2; + for (j = 0; n > 0; n--) { + stackMap = readFrameType(frameLocal, + j++, + stackMap, + c, + labels); + } + n = frameStackCount = readUnsignedShort(stackMap); + stackMap += 2; + for (j = 0; n > 0; n--) { + stackMap = readFrameType(frameStack, + j++, + stackMap, + c, + labels); + } + } + } + frameOffset += delta + 1; + readLabel(frameOffset, labels); + + --frameCount; + } else { + frameLocal = null; + } + } + + int opcode = b[v] & 0xFF; + switch (ClassWriter.TYPE[opcode]) { + case ClassWriter.NOARG_INSN: + mv.visitInsn(opcode); + v += 1; + break; + case ClassWriter.IMPLVAR_INSN: + if (opcode > Opcodes.ISTORE) { + opcode -= 59; // ISTORE_0 + mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), + opcode & 0x3); + } else { + opcode -= 26; // ILOAD_0 + mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), + opcode & 0x3); + } + v += 1; + break; + case ClassWriter.LABEL_INSN: + mv.visitJumpInsn(opcode, labels[w + + readShort(v + 1)]); + v += 3; + break; + case ClassWriter.LABELW_INSN: + mv.visitJumpInsn(opcode - 33, labels[w + + readInt(v + 1)]); + v += 5; + break; + case ClassWriter.WIDE_INSN: + opcode = b[v + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + mv.visitIincInsn(readUnsignedShort(v + 2), + readShort(v + 4)); + v += 6; + } else { + mv.visitVarInsn(opcode, + readUnsignedShort(v + 2)); + v += 4; + } + break; + case ClassWriter.TABL_INSN: + // skips 0 to 3 padding bytes + v = v + 4 - (w & 3); + // reads instruction + label = w + readInt(v); + int min = readInt(v + 4); + int max = readInt(v + 8); + v += 12; + Label[] table = new Label[max - min + 1]; + for (j = 0; j < table.length; ++j) { + table[j] = labels[w + readInt(v)]; + v += 4; + } + mv.visitTableSwitchInsn(min, + max, + labels[label], + table); + break; + case ClassWriter.LOOK_INSN: + // skips 0 to 3 padding bytes + v = v + 4 - (w & 3); + // reads instruction + label = w + readInt(v); + j = readInt(v + 4); + v += 8; + int[] keys = new int[j]; + Label[] values = new Label[j]; + for (j = 0; j < keys.length; ++j) { + keys[j] = readInt(v); + values[j] = labels[w + readInt(v + 4)]; + v += 8; + } + mv.visitLookupSwitchInsn(labels[label], + keys, + values); + break; + case ClassWriter.VAR_INSN: + mv.visitVarInsn(opcode, b[v + 1] & 0xFF); + v += 2; + break; + case ClassWriter.SBYTE_INSN: + mv.visitIntInsn(opcode, b[v + 1]); + v += 2; + break; + case ClassWriter.SHORT_INSN: + mv.visitIntInsn(opcode, readShort(v + 1)); + v += 3; + break; + case ClassWriter.LDC_INSN: + mv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c)); + v += 2; + break; + case ClassWriter.LDCW_INSN: + mv.visitLdcInsn(readConst(readUnsignedShort(v + 1), + c)); + v += 3; + break; + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.ITFMETH_INSN: { + int cpIndex = items[readUnsignedShort(v + 1)]; + String iowner = readClass(cpIndex, c); + cpIndex = items[readUnsignedShort(cpIndex + 2)]; + String iname = readUTF8(cpIndex, c); + String idesc = readUTF8(cpIndex + 2, c); + if (opcode < Opcodes.INVOKEVIRTUAL) { + mv.visitFieldInsn(opcode, iowner, iname, idesc); + } else { + mv.visitMethodInsn(opcode, iowner, iname, idesc); + } + if (opcode == Opcodes.INVOKEINTERFACE) { + v += 5; + } else { + v += 3; + } + break; + } + case ClassWriter.INDYMETH_INSN: { + int cpIndex = items[readUnsignedShort(v + 1)]; + int bsmIndex = bootstrapMethods[readUnsignedShort(cpIndex)]; + cpIndex = items[readUnsignedShort(cpIndex + 2)]; + String iname = readUTF8(cpIndex, c); + String idesc = readUTF8(cpIndex + 2, c); + + int mhIndex = readUnsignedShort(bsmIndex); + Handle bsm = (Handle) readConst(mhIndex, c); + int bsmArgCount = readUnsignedShort(bsmIndex + 2); + Object[] bsmArgs = new Object[bsmArgCount]; + bsmIndex += 4; + for(int a = 0; a < bsmArgCount; a++) { + int argIndex = readUnsignedShort(bsmIndex); + bsmArgs[a] = readConst(argIndex, c); + bsmIndex += 2; + } + mv.visitInvokeDynamicInsn(iname, idesc, bsm, bsmArgs); + + v += 5; + break; + } + case ClassWriter.TYPE_INSN: + mv.visitTypeInsn(opcode, readClass(v + 1, c)); + v += 3; + break; + case ClassWriter.IINC_INSN: + mv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]); + v += 3; + break; + // case MANA_INSN: + default: + mv.visitMultiANewArrayInsn(readClass(v + 1, c), + b[v + 3] & 0xFF); + v += 4; + break; + } + } + l = labels[codeEnd - codeStart]; + if (l != null) { + mv.visitLabel(l); + } + // visits the local variable tables + if (!skipDebug && varTable != 0) { + int[] typeTable = null; + if (varTypeTable != 0) { + k = readUnsignedShort(varTypeTable) * 3; + w = varTypeTable + 2; + typeTable = new int[k]; + while (k > 0) { + typeTable[--k] = w + 6; // signature + typeTable[--k] = readUnsignedShort(w + 8); // index + typeTable[--k] = readUnsignedShort(w); // start + w += 10; + } + } + k = readUnsignedShort(varTable); + w = varTable + 2; + for (; k > 0; --k) { + int start = readUnsignedShort(w); + int length = readUnsignedShort(w + 2); + int index = readUnsignedShort(w + 8); + String vsignature = null; + if (typeTable != null) { + for (int a = 0; a < typeTable.length; a += 3) { + if (typeTable[a] == start + && typeTable[a + 1] == index) + { + vsignature = readUTF8(typeTable[a + 2], c); + break; + } + } + } + mv.visitLocalVariable(readUTF8(w + 4, c), + readUTF8(w + 6, c), + vsignature, + labels[start], + labels[start + length], + index); + w += 10; + } + } + // visits the other attributes + while (cattrs != null) { + attr = cattrs.next; + cattrs.next = null; + mv.visitAttribute(cattrs); + cattrs = attr; + } + // visits the max stack and max locals values + mv.visitMaxs(maxStack, maxLocals); + } + + if (mv != null) { + mv.visitEnd(); + } + } + + // visits the end of the class + classVisitor.visitEnd(); + } + + /** + * Reads parameter annotations and makes the given visitor visit them. + * + * @param v start offset in {@link #b b} of the annotations to be read. + * @param desc the method descriptor. + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, + * {@link #readClass(int,char[]) readClass} or + * {@link #readConst readConst}. + * @param visible true if the annotations to be read are visible + * at runtime. + * @param mv the visitor that must visit the annotations. + */ + private void readParameterAnnotations( + int v, + final String desc, + final char[] buf, + final boolean visible, + final MethodVisitor mv) + { + int i; + int n = b[v++] & 0xFF; + // workaround for a bug in javac (javac compiler generates a parameter + // annotation array whose size is equal to the number of parameters in + // the Java source file, while it should generate an array whose size is + // equal to the number of parameters in the method descriptor - which + // includes the synthetic parameters added by the compiler). This work- + // around supposes that the synthetic parameters are the first ones. + int synthetics = Type.getArgumentTypes(desc).length - n; + AnnotationVisitor av; + for (i = 0; i < synthetics; ++i) { + // virtual annotation to detect synthetic parameters in MethodWriter + av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", false); + if (av != null) { + av.visitEnd(); + } + } + for (; i < n + synthetics; ++i) { + int j = readUnsignedShort(v); + v += 2; + for (; j > 0; --j) { + av = mv.visitParameterAnnotation(i, readUTF8(v, buf), visible); + v = readAnnotationValues(v + 2, buf, true, av); + } + } + } + + /** + * Reads the values of an annotation and makes the given visitor visit them. + * + * @param v the start offset in {@link #b b} of the values to be read + * (including the unsigned short that gives the number of values). + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, + * {@link #readClass(int,char[]) readClass} or + * {@link #readConst readConst}. + * @param named if the annotation values are named or not. + * @param av the visitor that must visit the values. + * @return the end offset of the annotation values. + */ + private int readAnnotationValues( + int v, + final char[] buf, + final boolean named, + final AnnotationVisitor av) + { + int i = readUnsignedShort(v); + v += 2; + if (named) { + for (; i > 0; --i) { + v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av); + } + } else { + for (; i > 0; --i) { + v = readAnnotationValue(v, buf, null, av); + } + } + if (av != null) { + av.visitEnd(); + } + return v; + } + + /** + * Reads a value of an annotation and makes the given visitor visit it. + * + * @param v the start offset in {@link #b b} of the value to be read (not + * including the value name constant pool index). + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, + * {@link #readClass(int,char[]) readClass} or + * {@link #readConst readConst}. + * @param name the name of the value to be read. + * @param av the visitor that must visit the value. + * @return the end offset of the annotation value. + */ + private int readAnnotationValue( + int v, + final char[] buf, + final String name, + final AnnotationVisitor av) + { + int i; + if (av == null) { + switch (b[v] & 0xFF) { + case 'e': // enum_const_value + return v + 5; + case '@': // annotation_value + return readAnnotationValues(v + 3, buf, true, null); + case '[': // array_value + return readAnnotationValues(v + 1, buf, false, null); + default: + return v + 3; + } + } + switch (b[v++] & 0xFF) { + case 'I': // pointer to CONSTANT_Integer + case 'J': // pointer to CONSTANT_Long + case 'F': // pointer to CONSTANT_Float + case 'D': // pointer to CONSTANT_Double + av.visit(name, readConst(readUnsignedShort(v), buf)); + v += 2; + break; + case 'B': // pointer to CONSTANT_Byte + av.visit(name, + new Byte((byte) readInt(items[readUnsignedShort(v)]))); + v += 2; + break; + case 'Z': // pointer to CONSTANT_Boolean + av.visit(name, readInt(items[readUnsignedShort(v)]) == 0 + ? Boolean.FALSE + : Boolean.TRUE); + v += 2; + break; + case 'S': // pointer to CONSTANT_Short + av.visit(name, + new Short((short) readInt(items[readUnsignedShort(v)]))); + v += 2; + break; + case 'C': // pointer to CONSTANT_Char + av.visit(name, + new Character((char) readInt(items[readUnsignedShort(v)]))); + v += 2; + break; + case 's': // pointer to CONSTANT_Utf8 + av.visit(name, readUTF8(v, buf)); + v += 2; + break; + case 'e': // enum_const_value + av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf)); + v += 4; + break; + case 'c': // class_info + av.visit(name, Type.getType(readUTF8(v, buf))); + v += 2; + break; + case '@': // annotation_value + v = readAnnotationValues(v + 2, + buf, + true, + av.visitAnnotation(name, readUTF8(v, buf))); + break; + case '[': // array_value + int size = readUnsignedShort(v); + v += 2; + if (size == 0) { + return readAnnotationValues(v - 2, + buf, + false, + av.visitArray(name)); + } + switch (this.b[v++] & 0xFF) { + case 'B': + byte[] bv = new byte[size]; + for (i = 0; i < size; i++) { + bv[i] = (byte) readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, bv); + --v; + break; + case 'Z': + boolean[] zv = new boolean[size]; + for (i = 0; i < size; i++) { + zv[i] = readInt(items[readUnsignedShort(v)]) != 0; + v += 3; + } + av.visit(name, zv); + --v; + break; + case 'S': + short[] sv = new short[size]; + for (i = 0; i < size; i++) { + sv[i] = (short) readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, sv); + --v; + break; + case 'C': + char[] cv = new char[size]; + for (i = 0; i < size; i++) { + cv[i] = (char) readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, cv); + --v; + break; + case 'I': + int[] iv = new int[size]; + for (i = 0; i < size; i++) { + iv[i] = readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, iv); + --v; + break; + case 'J': + long[] lv = new long[size]; + for (i = 0; i < size; i++) { + lv[i] = readLong(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, lv); + --v; + break; + case 'F': + float[] fv = new float[size]; + for (i = 0; i < size; i++) { + fv[i] = Float.intBitsToFloat(readInt(items[readUnsignedShort(v)])); + v += 3; + } + av.visit(name, fv); + --v; + break; + case 'D': + double[] dv = new double[size]; + for (i = 0; i < size; i++) { + dv[i] = Double.longBitsToDouble(readLong(items[readUnsignedShort(v)])); + v += 3; + } + av.visit(name, dv); + --v; + break; + default: + v = readAnnotationValues(v - 3, + buf, + false, + av.visitArray(name)); + } + } + return v; + } + + private int readFrameType( + final Object[] frame, + final int index, + int v, + final char[] buf, + final Label[] labels) + { + int type = b[v++] & 0xFF; + switch (type) { + case 0: + frame[index] = Opcodes.TOP; + break; + case 1: + frame[index] = Opcodes.INTEGER; + break; + case 2: + frame[index] = Opcodes.FLOAT; + break; + case 3: + frame[index] = Opcodes.DOUBLE; + break; + case 4: + frame[index] = Opcodes.LONG; + break; + case 5: + frame[index] = Opcodes.NULL; + break; + case 6: + frame[index] = Opcodes.UNINITIALIZED_THIS; + break; + case 7: // Object + frame[index] = readClass(v, buf); + v += 2; + break; + default: // Uninitialized + frame[index] = readLabel(readUnsignedShort(v), labels); + v += 2; + } + return v; + } + + /** + * Returns the label corresponding to the given offset. The default + * implementation of this method creates a label for the given offset if it + * has not been already created. + * + * @param offset a bytecode offset in a method. + * @param labels the already created labels, indexed by their offset. If a + * label already exists for offset this method must not create a new + * one. Otherwise it must store the new label in this array. + * @return a non null Label, which must be equal to labels[offset]. + */ + protected Label readLabel(int offset, Label[] labels) { + if (labels[offset] == null) { + labels[offset] = new Label(); + } + return labels[offset]; + } + + /** + * Reads an attribute in {@link #b b}. + * + * @param attrs prototypes of the attributes that must be parsed during the + * visit of the class. Any attribute whose type is not equal to the + * type of one the prototypes is ignored (i.e. an empty + * {@link Attribute} instance is returned). + * @param type the type of the attribute. + * @param off index of the first byte of the attribute's content in + * {@link #b b}. The 6 attribute header bytes, containing the type + * and the length of the attribute, are not taken into account here + * (they have already been read). + * @param len the length of the attribute's content. + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, + * {@link #readClass(int,char[]) readClass} or + * {@link #readConst readConst}. + * @param codeOff index of the first byte of code's attribute content in + * {@link #b b}, or -1 if the attribute to be read is not a code + * attribute. The 6 attribute header bytes, containing the type and + * the length of the attribute, are not taken into account here. + * @param labels the labels of the method's code, or null if the + * attribute to be read is not a code attribute. + * @return the attribute that has been read, or null to skip this + * attribute. + */ + private Attribute readAttribute( + final Attribute[] attrs, + final String type, + final int off, + final int len, + final char[] buf, + final int codeOff, + final Label[] labels) + { + for (int i = 0; i < attrs.length; ++i) { + if (attrs[i].type.equals(type)) { + return attrs[i].read(this, off, len, buf, codeOff, labels); + } + } + return new Attribute(type).read(this, off, len, null, -1, null); + } + + // ------------------------------------------------------------------------ + // Utility methods: low level parsing + // ------------------------------------------------------------------------ + + /** + * Returns the number of constant pool items in {@link #b b}. + * + * @return the number of constant pool items in {@link #b b}. + */ + public int getItemCount() { + return items.length; + } + + /** + * Returns the start index of the constant pool item in {@link #b b}, plus + * one. This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @param item the index a constant pool item. + * @return the start index of the constant pool item in {@link #b b}, plus + * one. + */ + public int getItem(final int item) { + return items[item]; + } + + /** + * Returns the maximum length of the strings contained in the constant pool + * of the class. + * + * @return the maximum length of the strings contained in the constant pool + * of the class. + */ + public int getMaxStringLength() { + return maxStringLength; + } + + /** + * Reads a byte value in {@link #b b}. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class + * generators or adapters. + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public int readByte(final int index) { + return b[index] & 0xFF; + } + + /** + * Reads an unsigned short value in {@link #b b}. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by + * class generators or adapters. + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public int readUnsignedShort(final int index) { + byte[] b = this.b; + return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); + } + + /** + * Reads a signed short value in {@link #b b}. This method is intended + * for {@link Attribute} sub classes, and is normally not needed by class + * generators or adapters. + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public short readShort(final int index) { + byte[] b = this.b; + return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); + } + + /** + * Reads a signed int value in {@link #b b}. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class + * generators or adapters. + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public int readInt(final int index) { + byte[] b = this.b; + return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) + | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); + } + + /** + * Reads a signed long value in {@link #b b}. This method is intended + * for {@link Attribute} sub classes, and is normally not needed by class + * generators or adapters. + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public long readLong(final int index) { + long l1 = readInt(index); + long l0 = readInt(index + 4) & 0xFFFFFFFFL; + return (l1 << 32) | l0; + } + + /** + * Reads an UTF8 string constant pool item in {@link #b b}. This method + * is intended for {@link Attribute} sub classes, and is normally not needed + * by class generators or adapters. + * + * @param index the start index of an unsigned short value in {@link #b b}, + * whose value is the index of an UTF8 constant pool item. + * @param buf buffer to be used to read the item. This buffer must be + * sufficiently large. It is not automatically resized. + * @return the String corresponding to the specified UTF8 item. + */ + public String readUTF8(int index, final char[] buf) { + int item = readUnsignedShort(index); + String s = strings[item]; + if (s != null) { + return s; + } + index = items[item]; + return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf); + } + + /** + * Reads UTF8 string in {@link #b b}. + * + * @param index start offset of the UTF8 string to be read. + * @param utfLen length of the UTF8 string to be read. + * @param buf buffer to be used to read the string. This buffer must be + * sufficiently large. It is not automatically resized. + * @return the String corresponding to the specified UTF8 string. + */ + private String readUTF(int index, final int utfLen, final char[] buf) { + int endIndex = index + utfLen; + byte[] b = this.b; + int strLen = 0; + int c; + int st = 0; + char cc = 0; + while (index < endIndex) { + c = b[index++]; + switch (st) { + case 0: + c = c & 0xFF; + if (c < 0x80) { // 0xxxxxxx + buf[strLen++] = (char) c; + } else if (c < 0xE0 && c > 0xBF) { // 110x xxxx 10xx xxxx + cc = (char) (c & 0x1F); + st = 1; + } else { // 1110 xxxx 10xx xxxx 10xx xxxx + cc = (char) (c & 0x0F); + st = 2; + } + break; + + case 1: // byte 2 of 2-byte char or byte 3 of 3-byte char + buf[strLen++] = (char) ((cc << 6) | (c & 0x3F)); + st = 0; + break; + + case 2: // byte 2 of 3-byte char + cc = (char) ((cc << 6) | (c & 0x3F)); + st = 1; + break; + } + } + return new String(buf, 0, strLen); + } + + /** + * Reads a class constant pool item in {@link #b b}. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by + * class generators or adapters. + * + * @param index the start index of an unsigned short value in {@link #b b}, + * whose value is the index of a class constant pool item. + * @param buf buffer to be used to read the item. This buffer must be + * sufficiently large. It is not automatically resized. + * @return the String corresponding to the specified class item. + */ + public String readClass(final int index, final char[] buf) { + // computes the start index of the CONSTANT_Class item in b + // and reads the CONSTANT_Utf8 item designated by + // the first two bytes of this CONSTANT_Class item + return readUTF8(items[readUnsignedShort(index)], buf); + } + + /** + * Reads a numeric or string constant pool item in {@link #b b}. This + * method is intended for {@link Attribute} sub classes, and is normally not + * needed by class generators or adapters. + * + * @param item the index of a constant pool item. + * @param buf buffer to be used to read the item. This buffer must be + * sufficiently large. It is not automatically resized. + * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, + * {@link String}, {@link Type} or {@link Handle} corresponding to + * the given constant pool item. + */ + public Object readConst(final int item, final char[] buf) { + int index = items[item]; + switch (b[index - 1]) { + case ClassWriter.INT: + return new Integer(readInt(index)); + case ClassWriter.FLOAT: + return new Float(Float.intBitsToFloat(readInt(index))); + case ClassWriter.LONG: + return new Long(readLong(index)); + case ClassWriter.DOUBLE: + return new Double(Double.longBitsToDouble(readLong(index))); + case ClassWriter.CLASS: + return Type.getObjectType(readUTF8(index, buf)); + case ClassWriter.STR: + return readUTF8(index, buf); + case ClassWriter.MTYPE: + return Type.getMethodType(readUTF8(index, buf)); + + //case ClassWriter.HANDLE_BASE + [1..9]: + default: { + int tag = readByte(index); + int[] items = this.items; + int cpIndex = items[readUnsignedShort(index + 1)]; + String owner = readClass(cpIndex, buf); + cpIndex = items[readUnsignedShort(cpIndex + 2)]; + String name = readUTF8(cpIndex, buf); + String desc = readUTF8(cpIndex + 2, buf); + return new Handle(tag, owner, name, desc); + } + } + } +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassVisitor.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassVisitor.java new file mode 100644 index 00000000000..73096fa9e70 --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassVisitor.java @@ -0,0 +1,306 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +/** + * A visitor to visit a Java class. The methods of this class must be called + * in the following order: visit [ visitSource ] [ + * visitOuterClass ] ( visitAnnotation | + * visitAttribute )* ( visitInnerClass | + * visitField | visitMethod )* visitEnd. + * + * @author Eric Bruneton + */ +public abstract class ClassVisitor { + + /** + * The ASM API version implemented by this visitor. The value of this field + * must be one of {@link Opcodes#ASM4}. + */ + protected final int api; + + /** + * The class visitor to which this visitor must delegate method calls. May + * be null. + */ + protected ClassVisitor cv; + + /** + * Constructs a new {@link ClassVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + */ + public ClassVisitor(final int api) { + this(api, null); + } + + /** + * Constructs a new {@link ClassVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param cv the class visitor to which this visitor must delegate method + * calls. May be null. + */ + public ClassVisitor(final int api, final ClassVisitor cv) { + /*if (api != Opcodes.ASM4) { + throw new IllegalArgumentException(); + }*/ + this.api = api; + this.cv = cv; + } + + /** + * Visits the header of the class. + * + * @param version the class version. + * @param access the class's access flags (see {@link Opcodes}). This + * parameter also indicates if the class is deprecated. + * @param name the internal name of the class (see + * {@link Type#getInternalName() getInternalName}). + * @param signature the signature of this class. May be null if + * the class is not a generic one, and does not extend or implement + * generic classes or interfaces. + * @param superName the internal of name of the super class (see + * {@link Type#getInternalName() getInternalName}). For interfaces, + * the super class is {@link Object}. May be null, but + * only for the {@link Object} class. + * @param interfaces the internal names of the class's interfaces (see + * {@link Type#getInternalName() getInternalName}). May be + * null. + */ + public void visit( + int version, + int access, + String name, + String signature, + String superName, + String[] interfaces) + { + if (cv != null) { + cv.visit(version, access, name, signature, superName, interfaces); + } + } + + /** + * Visits the source of the class. + * + * @param source the name of the source file from which the class was + * compiled. May be null. + * @param debug additional debug information to compute the correspondance + * between source and compiled elements of the class. May be + * null. + */ + public void visitSource(String source, String debug) { + if (cv != null) { + cv.visitSource(source, debug); + } + } + + /** + * Visits the enclosing class of the class. This method must be called only + * if the class has an enclosing class. + * + * @param owner internal name of the enclosing class of the class. + * @param name the name of the method that contains the class, or + * null if the class is not enclosed in a method of its + * enclosing class. + * @param desc the descriptor of the method that contains the class, or + * null if the class is not enclosed in a method of its + * enclosing class. + */ + public void visitOuterClass(String owner, String name, String desc) { + if (cv != null) { + cv.visitOuterClass(owner, name, desc); + } + } + + /** + * Visits an annotation of the class. + * + * @param desc the class descriptor of the annotation class. + * @param visible true if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or null if + * this visitor is not interested in visiting this annotation. + */ + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + if (cv != null) { + return cv.visitAnnotation(desc, visible); + } + return null; + } + + /** + * Visits a non standard attribute of the class. + * + * @param attr an attribute. + */ + public void visitAttribute(Attribute attr) { + if (cv != null) { + cv.visitAttribute(attr); + } + } + + /** + * Visits information about an inner class. This inner class is not + * necessarily a member of the class being visited. + * + * @param name the internal name of an inner class (see + * {@link Type#getInternalName() getInternalName}). + * @param outerName the internal name of the class to which the inner class + * belongs (see {@link Type#getInternalName() getInternalName}). May + * be null for not member classes. + * @param innerName the (simple) name of the inner class inside its + * enclosing class. May be null for anonymous inner + * classes. + * @param access the access flags of the inner class as originally declared + * in the enclosing class. + */ + public void visitInnerClass( + String name, + String outerName, + String innerName, + int access) + { + if (cv != null) { + cv.visitInnerClass(name, outerName, innerName, access); + } + } + + /** + * Visits a field of the class. + * + * @param access the field's access flags (see {@link Opcodes}). This + * parameter also indicates if the field is synthetic and/or + * deprecated. + * @param name the field's name. + * @param desc the field's descriptor (see {@link Type Type}). + * @param signature the field's signature. May be null if the + * field's type does not use generic types. + * @param value the field's initial value. This parameter, which may be + * null if the field does not have an initial value, must + * be an {@link Integer}, a {@link Float}, a {@link Long}, a + * {@link Double} or a {@link String} (for int, + * float, long or String fields + * respectively). This parameter is only used for static fields. + * Its value is ignored for non static fields, which must be + * initialized through bytecode instructions in constructors or + * methods. + * @return a visitor to visit field annotations and attributes, or + * null if this class visitor is not interested in + * visiting these annotations and attributes. + */ + public FieldVisitor visitField( + int access, + String name, + String desc, + String signature, + Object value) + { + if (cv != null) { + return cv.visitField(access, name, desc, signature, value); + } + return null; + } + + /** + * Visits a method of the class. This method must return a new + * {@link MethodVisitor} instance (or null) each time it is + * called, i.e., it should not return a previously returned visitor. + * + * @param access the method's access flags (see {@link Opcodes}). This + * parameter also indicates if the method is synthetic and/or + * deprecated. + * @param name the method's name. + * @param desc the method's descriptor (see {@link Type Type}). + * @param signature the method's signature. May be null if the + * method parameters, return type and exceptions do not use generic + * types. + * @param exceptions the internal names of the method's exception classes + * (see {@link Type#getInternalName() getInternalName}). May be + * null. + * @return an object to visit the byte code of the method, or null + * if this class visitor is not interested in visiting the code of + * this method. + */ + public MethodVisitor visitMethod( + int access, + String name, + String desc, + String signature, + String[] exceptions) + { + if (cv != null) { + return cv.visitMethod(access, name, desc, signature, exceptions); + } + return null; + } + + /** + * Visits the end of the class. This method, which is the last one to be + * called, is used to inform the visitor that all the fields and methods of + * the class have been visited. + */ + public void visitEnd() { + if (cv != null) { + cv.visitEnd(); + } + } +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java new file mode 100644 index 00000000000..33c98295db0 --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java @@ -0,0 +1,1701 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +/** + * A {@link ClassVisitor} that generates classes in bytecode form. More + * precisely this visitor generates a byte array conforming to the Java class + * file format. It can be used alone, to generate a Java class "from scratch", + * or with one or more {@link ClassReader ClassReader} and adapter class visitor + * to generate a modified class from one or more existing Java classes. + * + * @author Eric Bruneton + */ +public class ClassWriter extends ClassVisitor { + + /** + * Flag to automatically compute the maximum stack size and the maximum + * number of local variables of methods. If this flag is set, then the + * arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method of the + * {@link MethodVisitor} returned by the {@link #visitMethod visitMethod} + * method will be ignored, and computed automatically from the signature and + * the bytecode of each method. + * + * @see #ClassWriter(int) + */ + public static final int COMPUTE_MAXS = 1; + + /** + * Flag to automatically compute the stack map frames of methods from + * scratch. If this flag is set, then the calls to the + * {@link MethodVisitor#visitFrame} method are ignored, and the stack map + * frames are recomputed from the methods bytecode. The arguments of the + * {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and + * recomputed from the bytecode. In other words, computeFrames implies + * computeMaxs. + * + * @see #ClassWriter(int) + */ + public static final int COMPUTE_FRAMES = 2; + + /** + * Pseudo access flag to distinguish between the synthetic attribute and + * the synthetic access flag. + */ + static final int ACC_SYNTHETIC_ATTRIBUTE = 0x40000; + + /** + * The type of instructions without any argument. + */ + static final int NOARG_INSN = 0; + + /** + * The type of instructions with an signed byte argument. + */ + static final int SBYTE_INSN = 1; + + /** + * The type of instructions with an signed short argument. + */ + static final int SHORT_INSN = 2; + + /** + * The type of instructions with a local variable index argument. + */ + static final int VAR_INSN = 3; + + /** + * The type of instructions with an implicit local variable index argument. + */ + static final int IMPLVAR_INSN = 4; + + /** + * The type of instructions with a type descriptor argument. + */ + static final int TYPE_INSN = 5; + + /** + * The type of field and method invocations instructions. + */ + static final int FIELDORMETH_INSN = 6; + + /** + * The type of the INVOKEINTERFACE/INVOKEDYNAMIC instruction. + */ + static final int ITFMETH_INSN = 7; + + /** + * The type of the INVOKEDYNAMIC instruction. + */ + static final int INDYMETH_INSN = 8; + + /** + * The type of instructions with a 2 bytes bytecode offset label. + */ + static final int LABEL_INSN = 9; + + /** + * The type of instructions with a 4 bytes bytecode offset label. + */ + static final int LABELW_INSN = 10; + + /** + * The type of the LDC instruction. + */ + static final int LDC_INSN = 11; + + /** + * The type of the LDC_W and LDC2_W instructions. + */ + static final int LDCW_INSN = 12; + + /** + * The type of the IINC instruction. + */ + static final int IINC_INSN = 13; + + /** + * The type of the TABLESWITCH instruction. + */ + static final int TABL_INSN = 14; + + /** + * The type of the LOOKUPSWITCH instruction. + */ + static final int LOOK_INSN = 15; + + /** + * The type of the MULTIANEWARRAY instruction. + */ + static final int MANA_INSN = 16; + + /** + * The type of the WIDE instruction. + */ + static final int WIDE_INSN = 17; + + /** + * The instruction types of all JVM opcodes. + */ + static final byte[] TYPE; + + /** + * The type of CONSTANT_Class constant pool items. + */ + static final int CLASS = 7; + + /** + * The type of CONSTANT_Fieldref constant pool items. + */ + static final int FIELD = 9; + + /** + * The type of CONSTANT_Methodref constant pool items. + */ + static final int METH = 10; + + /** + * The type of CONSTANT_InterfaceMethodref constant pool items. + */ + static final int IMETH = 11; + + /** + * The type of CONSTANT_String constant pool items. + */ + static final int STR = 8; + + /** + * The type of CONSTANT_Integer constant pool items. + */ + static final int INT = 3; + + /** + * The type of CONSTANT_Float constant pool items. + */ + static final int FLOAT = 4; + + /** + * The type of CONSTANT_Long constant pool items. + */ + static final int LONG = 5; + + /** + * The type of CONSTANT_Double constant pool items. + */ + static final int DOUBLE = 6; + + /** + * The type of CONSTANT_NameAndType constant pool items. + */ + static final int NAME_TYPE = 12; + + /** + * The type of CONSTANT_Utf8 constant pool items. + */ + static final int UTF8 = 1; + + /** + * The type of CONSTANT_MethodType constant pool items. + */ + static final int MTYPE = 16; + + /** + * The type of CONSTANT_MethodHandle constant pool items. + */ + static final int HANDLE = 15; + + /** + * The type of CONSTANT_InvokeDynamic constant pool items. + */ + static final int INDY = 18; + + /** + * The base value for all CONSTANT_MethodHandle constant pool items. + * Internally, ASM store the 9 variations of CONSTANT_MethodHandle into + * 9 different items. + */ + static final int HANDLE_BASE = 20; + + /** + * Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable}, + * instead of the constant pool, in order to avoid clashes with normal + * constant pool items in the ClassWriter constant pool's hash table. + */ + static final int TYPE_NORMAL = 30; + + /** + * Uninitialized type Item stored in the ClassWriter + * {@link ClassWriter#typeTable}, instead of the constant pool, in order to + * avoid clashes with normal constant pool items in the ClassWriter constant + * pool's hash table. + */ + static final int TYPE_UNINIT = 31; + + /** + * Merged type Item stored in the ClassWriter {@link ClassWriter#typeTable}, + * instead of the constant pool, in order to avoid clashes with normal + * constant pool items in the ClassWriter constant pool's hash table. + */ + static final int TYPE_MERGED = 32; + + /** + * The type of BootstrapMethods items. These items are stored in a + * special class attribute named BootstrapMethods and + * not in the constant pool. + */ + static final int BSM = 33; + + /** + * The class reader from which this class writer was constructed, if any. + */ + ClassReader cr; + + /** + * Minor and major version numbers of the class to be generated. + */ + int version; + + /** + * Index of the next item to be added in the constant pool. + */ + int index; + + /** + * The constant pool of this class. + */ + final ByteVector pool; + + /** + * The constant pool's hash table data. + */ + Item[] items; + + /** + * The threshold of the constant pool's hash table. + */ + int threshold; + + /** + * A reusable key used to look for items in the {@link #items} hash table. + */ + final Item key; + + /** + * A reusable key used to look for items in the {@link #items} hash table. + */ + final Item key2; + + /** + * A reusable key used to look for items in the {@link #items} hash table. + */ + final Item key3; + + /** + * A reusable key used to look for items in the {@link #items} hash table. + */ + final Item key4; + + /** + * A type table used to temporarily store internal names that will not + * necessarily be stored in the constant pool. This type table is used by + * the control flow and data flow analysis algorithm used to compute stack + * map frames from scratch. This array associates to each index i + * the Item whose index is i. All Item objects stored in this + * array are also stored in the {@link #items} hash table. These two arrays + * allow to retrieve an Item from its index or, conversely, to get the index + * of an Item from its value. Each Item stores an internal name in its + * {@link Item#strVal1} field. + */ + Item[] typeTable; + + /** + * Number of elements in the {@link #typeTable} array. + */ + private short typeCount; + + /** + * The access flags of this class. + */ + private int access; + + /** + * The constant pool item that contains the internal name of this class. + */ + private int name; + + /** + * The internal name of this class. + */ + String thisName; + + /** + * The constant pool item that contains the signature of this class. + */ + private int signature; + + /** + * The constant pool item that contains the internal name of the super class + * of this class. + */ + private int superName; + + /** + * Number of interfaces implemented or extended by this class or interface. + */ + private int interfaceCount; + + /** + * The interfaces implemented or extended by this class or interface. More + * precisely, this array contains the indexes of the constant pool items + * that contain the internal names of these interfaces. + */ + private int[] interfaces; + + /** + * The index of the constant pool item that contains the name of the source + * file from which this class was compiled. + */ + private int sourceFile; + + /** + * The SourceDebug attribute of this class. + */ + private ByteVector sourceDebug; + + /** + * The constant pool item that contains the name of the enclosing class of + * this class. + */ + private int enclosingMethodOwner; + + /** + * The constant pool item that contains the name and descriptor of the + * enclosing method of this class. + */ + private int enclosingMethod; + + /** + * The runtime visible annotations of this class. + */ + private AnnotationWriter anns; + + /** + * The runtime invisible annotations of this class. + */ + private AnnotationWriter ianns; + + /** + * The non standard attributes of this class. + */ + private Attribute attrs; + + /** + * The number of entries in the InnerClasses attribute. + */ + private int innerClassesCount; + + /** + * The InnerClasses attribute. + */ + private ByteVector innerClasses; + + /** + * The number of entries in the BootstrapMethods attribute. + */ + int bootstrapMethodsCount; + + /** + * The BootstrapMethods attribute. + */ + ByteVector bootstrapMethods; + + /** + * The fields of this class. These fields are stored in a linked list of + * {@link FieldWriter} objects, linked to each other by their + * {@link FieldWriter#fv} field. This field stores the first element of + * this list. + */ + FieldWriter firstField; + + /** + * The fields of this class. These fields are stored in a linked list of + * {@link FieldWriter} objects, linked to each other by their + * {@link FieldWriter#fv} field. This field stores the last element of + * this list. + */ + FieldWriter lastField; + + /** + * The methods of this class. These methods are stored in a linked list of + * {@link MethodWriter} objects, linked to each other by their + * {@link MethodWriter#mv} field. This field stores the first element of + * this list. + */ + MethodWriter firstMethod; + + /** + * The methods of this class. These methods are stored in a linked list of + * {@link MethodWriter} objects, linked to each other by their + * {@link MethodWriter#mv} field. This field stores the last element of + * this list. + */ + MethodWriter lastMethod; + + /** + * true if the maximum stack size and number of local variables + * must be automatically computed. + */ + private final boolean computeMaxs; + + /** + * true if the stack map frames must be recomputed from scratch. + */ + private final boolean computeFrames; + + /** + * true if the stack map tables of this class are invalid. The + * {@link MethodWriter#resizeInstructions} method cannot transform existing + * stack map tables, and so produces potentially invalid classes when it is + * executed. In this case the class is reread and rewritten with the + * {@link #COMPUTE_FRAMES} option (the resizeInstructions method can resize + * stack map tables when this option is used). + */ + boolean invalidFrames; + + // ------------------------------------------------------------------------ + // Static initializer + // ------------------------------------------------------------------------ + + /** + * Computes the instruction types of JVM opcodes. + */ + static { + int i; + byte[] b = new byte[220]; + String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD" + + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA" + + "AAAAGGGGGGGHIFBFAAFFAARQJJKKJJJJJJJJJJJJJJJJJJ"; + for (i = 0; i < b.length; ++i) { + b[i] = (byte) (s.charAt(i) - 'A'); + } + TYPE = b; + + // code to generate the above string + // + // // SBYTE_INSN instructions + // b[Constants.NEWARRAY] = SBYTE_INSN; + // b[Constants.BIPUSH] = SBYTE_INSN; + // + // // SHORT_INSN instructions + // b[Constants.SIPUSH] = SHORT_INSN; + // + // // (IMPL)VAR_INSN instructions + // b[Constants.RET] = VAR_INSN; + // for (i = Constants.ILOAD; i <= Constants.ALOAD; ++i) { + // b[i] = VAR_INSN; + // } + // for (i = Constants.ISTORE; i <= Constants.ASTORE; ++i) { + // b[i] = VAR_INSN; + // } + // for (i = 26; i <= 45; ++i) { // ILOAD_0 to ALOAD_3 + // b[i] = IMPLVAR_INSN; + // } + // for (i = 59; i <= 78; ++i) { // ISTORE_0 to ASTORE_3 + // b[i] = IMPLVAR_INSN; + // } + // + // // TYPE_INSN instructions + // b[Constants.NEW] = TYPE_INSN; + // b[Constants.ANEWARRAY] = TYPE_INSN; + // b[Constants.CHECKCAST] = TYPE_INSN; + // b[Constants.INSTANCEOF] = TYPE_INSN; + // + // // (Set)FIELDORMETH_INSN instructions + // for (i = Constants.GETSTATIC; i <= Constants.INVOKESTATIC; ++i) { + // b[i] = FIELDORMETH_INSN; + // } + // b[Constants.INVOKEINTERFACE] = ITFMETH_INSN; + // b[Constants.INVOKEDYNAMIC] = INDYMETH_INSN; + // + // // LABEL(W)_INSN instructions + // for (i = Constants.IFEQ; i <= Constants.JSR; ++i) { + // b[i] = LABEL_INSN; + // } + // b[Constants.IFNULL] = LABEL_INSN; + // b[Constants.IFNONNULL] = LABEL_INSN; + // b[200] = LABELW_INSN; // GOTO_W + // b[201] = LABELW_INSN; // JSR_W + // // temporary opcodes used internally by ASM - see Label and + // MethodWriter + // for (i = 202; i < 220; ++i) { + // b[i] = LABEL_INSN; + // } + // + // // LDC(_W) instructions + // b[Constants.LDC] = LDC_INSN; + // b[19] = LDCW_INSN; // LDC_W + // b[20] = LDCW_INSN; // LDC2_W + // + // // special instructions + // b[Constants.IINC] = IINC_INSN; + // b[Constants.TABLESWITCH] = TABL_INSN; + // b[Constants.LOOKUPSWITCH] = LOOK_INSN; + // b[Constants.MULTIANEWARRAY] = MANA_INSN; + // b[196] = WIDE_INSN; // WIDE + // + // for (i = 0; i < b.length; ++i) { + // System.err.print((char)('A' + b[i])); + // } + // System.err.println(); + } + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructs a new {@link ClassWriter} object. + * + * @param flags option flags that can be used to modify the default behavior + * of this class. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}. + */ + public ClassWriter(final int flags) { + super(Opcodes.ASM4); + index = 1; + pool = new ByteVector(); + items = new Item[256]; + threshold = (int) (0.75d * items.length); + key = new Item(); + key2 = new Item(); + key3 = new Item(); + key4 = new Item(); + this.computeMaxs = (flags & COMPUTE_MAXS) != 0; + this.computeFrames = (flags & COMPUTE_FRAMES) != 0; + } + + /** + * Constructs a new {@link ClassWriter} object and enables optimizations for + * "mostly add" bytecode transformations. These optimizations are the + * following: + * + *

    • The constant pool from the original class is copied as is in the + * new class, which saves time. New constant pool entries will be added at + * the end if necessary, but unused constant pool entries won't be + * removed.
    • Methods that are not transformed are copied as is + * in the new class, directly from the original class bytecode (i.e. without + * emitting visit events for all the method instructions), which saves a + * lot of time. Untransformed methods are detected by the fact that + * the {@link ClassReader} receives {@link MethodVisitor} objects that come + * from a {@link ClassWriter} (and not from any other {@link ClassVisitor} + * instance).
    + * + * @param classReader the {@link ClassReader} used to read the original + * class. It will be used to copy the entire constant pool from the + * original class and also to copy other fragments of original + * bytecode where applicable. + * @param flags option flags that can be used to modify the default behavior + * of this class. These option flags do not affect methods that + * are copied as is in the new class. This means that the maximum + * stack size nor the stack frames will be computed for these + * methods. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}. + */ + public ClassWriter(final ClassReader classReader, final int flags) { + this(flags); + classReader.copyPool(this); + this.cr = classReader; + } + + // ------------------------------------------------------------------------ + // Implementation of the ClassVisitor abstract class + // ------------------------------------------------------------------------ + + @Override + public final void visit( + final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) + { + this.version = version; + this.access = access; + this.name = newClass(name); + thisName = name; + if (ClassReader.SIGNATURES && signature != null) { + this.signature = newUTF8(signature); + } + this.superName = superName == null ? 0 : newClass(superName); + if (interfaces != null && interfaces.length > 0) { + interfaceCount = interfaces.length; + this.interfaces = new int[interfaceCount]; + for (int i = 0; i < interfaceCount; ++i) { + this.interfaces[i] = newClass(interfaces[i]); + } + } + } + + @Override + public final void visitSource(final String file, final String debug) { + if (file != null) { + sourceFile = newUTF8(file); + } + if (debug != null) { + sourceDebug = new ByteVector().putUTF8(debug); + } + } + + @Override + public final void visitOuterClass( + final String owner, + final String name, + final String desc) + { + enclosingMethodOwner = newClass(owner); + if (name != null && desc != null) { + enclosingMethod = newNameType(name, desc); + } + } + + @Override + public final AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + if (!ClassReader.ANNOTATIONS) { + return null; + } + ByteVector bv = new ByteVector(); + // write type, and reserve space for values count + bv.putShort(newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2); + if (visible) { + aw.next = anns; + anns = aw; + } else { + aw.next = ianns; + ianns = aw; + } + return aw; + } + + @Override + public final void visitAttribute(final Attribute attr) { + attr.next = attrs; + attrs = attr; + } + + @Override + public final void visitInnerClass( + final String name, + final String outerName, + final String innerName, + final int access) + { + if (innerClasses == null) { + innerClasses = new ByteVector(); + } + ++innerClassesCount; + innerClasses.putShort(name == null ? 0 : newClass(name)); + innerClasses.putShort(outerName == null ? 0 : newClass(outerName)); + innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName)); + innerClasses.putShort(access); + } + + @Override + public final FieldVisitor visitField( + final int access, + final String name, + final String desc, + final String signature, + final Object value) + { + return new FieldWriter(this, access, name, desc, signature, value); + } + + @Override + public final MethodVisitor visitMethod( + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions) + { + return new MethodWriter(this, + access, + name, + desc, + signature, + exceptions, + computeMaxs, + computeFrames); + } + + @Override + public final void visitEnd() { + } + + // ------------------------------------------------------------------------ + // Other public methods + // ------------------------------------------------------------------------ + + /** + * Returns the bytecode of the class that was build with this class writer. + * + * @return the bytecode of the class that was build with this class writer. + */ + public byte[] toByteArray() { + if (index > Short.MAX_VALUE) { + throw new RuntimeException("Class file too large!"); + } + // computes the real size of the bytecode of this class + int size = 24 + 2 * interfaceCount; + int nbFields = 0; + FieldWriter fb = firstField; + while (fb != null) { + ++nbFields; + size += fb.getSize(); + fb = (FieldWriter) fb.fv; + } + int nbMethods = 0; + MethodWriter mb = firstMethod; + while (mb != null) { + ++nbMethods; + size += mb.getSize(); + mb = (MethodWriter) mb.mv; + } + int attributeCount = 0; + if (bootstrapMethods != null) { // we put it as first argument in order + // to improve a bit ClassReader.copyBootstrapMethods + ++attributeCount; + size += 8 + bootstrapMethods.length; + newUTF8("BootstrapMethods"); + } + if (ClassReader.SIGNATURES && signature != 0) { + ++attributeCount; + size += 8; + newUTF8("Signature"); + } + if (sourceFile != 0) { + ++attributeCount; + size += 8; + newUTF8("SourceFile"); + } + if (sourceDebug != null) { + ++attributeCount; + size += sourceDebug.length + 4; + newUTF8("SourceDebugExtension"); + } + if (enclosingMethodOwner != 0) { + ++attributeCount; + size += 10; + newUTF8("EnclosingMethod"); + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + ++attributeCount; + size += 6; + newUTF8("Deprecated"); + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0 + && ((version & 0xFFFF) < Opcodes.V1_5 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0)) + { + ++attributeCount; + size += 6; + newUTF8("Synthetic"); + } + if (innerClasses != null) { + ++attributeCount; + size += 8 + innerClasses.length; + newUTF8("InnerClasses"); + } + if (ClassReader.ANNOTATIONS && anns != null) { + ++attributeCount; + size += 8 + anns.getSize(); + newUTF8("RuntimeVisibleAnnotations"); + } + if (ClassReader.ANNOTATIONS && ianns != null) { + ++attributeCount; + size += 8 + ianns.getSize(); + newUTF8("RuntimeInvisibleAnnotations"); + } + if (attrs != null) { + attributeCount += attrs.getCount(); + size += attrs.getSize(this, null, 0, -1, -1); + } + size += pool.length; + // allocates a byte vector of this size, in order to avoid unnecessary + // arraycopy operations in the ByteVector.enlarge() method + ByteVector out = new ByteVector(size); + out.putInt(0xCAFEBABE).putInt(version); + out.putShort(index).putByteArray(pool.data, 0, pool.length); + int mask = Opcodes.ACC_DEPRECATED + | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE + | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / (ClassWriter.ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC)); + out.putShort(access & ~mask).putShort(name).putShort(superName); + out.putShort(interfaceCount); + for (int i = 0; i < interfaceCount; ++i) { + out.putShort(interfaces[i]); + } + out.putShort(nbFields); + fb = firstField; + while (fb != null) { + fb.put(out); + fb = (FieldWriter) fb.fv; + } + out.putShort(nbMethods); + mb = firstMethod; + while (mb != null) { + mb.put(out); + mb = (MethodWriter) mb.mv; + } + out.putShort(attributeCount); + if (bootstrapMethods != null) { // should be the first class attribute ? + out.putShort(newUTF8("BootstrapMethods")); + out.putInt(bootstrapMethods.length + 2).putShort(bootstrapMethodsCount); + out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length); + } + if (ClassReader.SIGNATURES && signature != 0) { + out.putShort(newUTF8("Signature")).putInt(2).putShort(signature); + } + if (sourceFile != 0) { + out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile); + } + if (sourceDebug != null) { + int len = sourceDebug.length - 2; + out.putShort(newUTF8("SourceDebugExtension")).putInt(len); + out.putByteArray(sourceDebug.data, 2, len); + } + if (enclosingMethodOwner != 0) { + out.putShort(newUTF8("EnclosingMethod")).putInt(4); + out.putShort(enclosingMethodOwner).putShort(enclosingMethod); + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + out.putShort(newUTF8("Deprecated")).putInt(0); + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0 + && ((version & 0xFFFF) < Opcodes.V1_5 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0)) + { + out.putShort(newUTF8("Synthetic")).putInt(0); + } + if (innerClasses != null) { + out.putShort(newUTF8("InnerClasses")); + out.putInt(innerClasses.length + 2).putShort(innerClassesCount); + out.putByteArray(innerClasses.data, 0, innerClasses.length); + } + if (ClassReader.ANNOTATIONS && anns != null) { + out.putShort(newUTF8("RuntimeVisibleAnnotations")); + anns.put(out); + } + if (ClassReader.ANNOTATIONS && ianns != null) { + out.putShort(newUTF8("RuntimeInvisibleAnnotations")); + ianns.put(out); + } + if (attrs != null) { + attrs.put(this, null, 0, -1, -1, out); + } + if (invalidFrames) { + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + new ClassReader(out.data).accept(cw, ClassReader.SKIP_FRAMES); + return cw.toByteArray(); + } + return out.data; + } + + // ------------------------------------------------------------------------ + // Utility methods: constant pool management + // ------------------------------------------------------------------------ + + /** + * Adds a number or string constant to the constant pool of the class being + * build. Does nothing if the constant pool already contains a similar item. + * + * @param cst the value of the constant to be added to the constant pool. + * This parameter must be an {@link Integer}, a {@link Float}, a + * {@link Long}, a {@link Double}, a {@link String} or a + * {@link Type}. + * @return a new or already existing constant item with the given value. + */ + Item newConstItem(final Object cst) { + if (cst instanceof Integer) { + int val = ((Integer) cst).intValue(); + return newInteger(val); + } else if (cst instanceof Byte) { + int val = ((Byte) cst).intValue(); + return newInteger(val); + } else if (cst instanceof Character) { + int val = ((Character) cst).charValue(); + return newInteger(val); + } else if (cst instanceof Short) { + int val = ((Short) cst).intValue(); + return newInteger(val); + } else if (cst instanceof Boolean) { + int val = ((Boolean) cst).booleanValue() ? 1 : 0; + return newInteger(val); + } else if (cst instanceof Float) { + float val = ((Float) cst).floatValue(); + return newFloat(val); + } else if (cst instanceof Long) { + long val = ((Long) cst).longValue(); + return newLong(val); + } else if (cst instanceof Double) { + double val = ((Double) cst).doubleValue(); + return newDouble(val); + } else if (cst instanceof String) { + return newString((String) cst); + } else if (cst instanceof Type) { + Type t = (Type) cst; + int s = t.getSort(); + if (s == Type.ARRAY) { + return newClassItem(t.getDescriptor()); + } else if (s == Type.OBJECT) { + return newClassItem(t.getInternalName()); + } else { // s == Type.METHOD + return newMethodTypeItem(t.getDescriptor()); + } + } else if (cst instanceof Handle) { + Handle h = (Handle) cst; + return newHandleItem(h.tag, h.owner, h.name, h.desc); + } else { + throw new IllegalArgumentException("value " + cst); + } + } + + /** + * Adds a number or string constant to the constant pool of the class being + * build. Does nothing if the constant pool already contains a similar item. + * This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @param cst the value of the constant to be added to the constant pool. + * This parameter must be an {@link Integer}, a {@link Float}, a + * {@link Long}, a {@link Double} or a {@link String}. + * @return the index of a new or already existing constant item with the + * given value. + */ + public int newConst(final Object cst) { + return newConstItem(cst).index; + } + + /** + * Adds an UTF8 string to the constant pool of the class being build. Does + * nothing if the constant pool already contains a similar item. This + * method is intended for {@link Attribute} sub classes, and is normally not + * needed by class generators or adapters. + * + * @param value the String value. + * @return the index of a new or already existing UTF8 item. + */ + public int newUTF8(final String value) { + key.set(UTF8, value, null, null); + Item result = get(key); + if (result == null) { + pool.putByte(UTF8).putUTF8(value); + result = new Item(index++, key); + put(result); + } + return result.index; + } + + /** + * Adds a class reference to the constant pool of the class being build. + * Does nothing if the constant pool already contains a similar item. + * This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @param value the internal name of the class. + * @return a new or already existing class reference item. + */ + Item newClassItem(final String value) { + key2.set(CLASS, value, null, null); + Item result = get(key2); + if (result == null) { + pool.put12(CLASS, newUTF8(value)); + result = new Item(index++, key2); + put(result); + } + return result; + } + + /** + * Adds a class reference to the constant pool of the class being build. + * Does nothing if the constant pool already contains a similar item. + * This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @param value the internal name of the class. + * @return the index of a new or already existing class reference item. + */ + public int newClass(final String value) { + return newClassItem(value).index; + } + + /** + * Adds a method type reference to the constant pool of the class being + * build. Does nothing if the constant pool already contains a similar item. + * This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @param methodDesc method descriptor of the method type. + * @return a new or already existing method type reference item. + */ + Item newMethodTypeItem(final String methodDesc) { + key2.set(MTYPE, methodDesc, null, null); + Item result = get(key2); + if (result == null) { + pool.put12(MTYPE, newUTF8(methodDesc)); + result = new Item(index++, key2); + put(result); + } + return result; + } + + /** + * Adds a method type reference to the constant pool of the class being + * build. Does nothing if the constant pool already contains a similar item. + * This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @param methodDesc method descriptor of the method type. + * @return the index of a new or already existing method type reference + * item. + */ + public int newMethodType(final String methodDesc) { + return newMethodTypeItem(methodDesc).index; + } + + /** + * Adds a handle to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by + * class generators or adapters. + * + * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, + * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, + * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, + * {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner the internal name of the field or method owner class. + * @param name the name of the field or method. + * @param desc the descriptor of the field or method. + * @return a new or an already existing method type reference item. + */ + Item newHandleItem( + final int tag, + final String owner, + final String name, + final String desc) + { + key4.set(HANDLE_BASE + tag, owner, name, desc); + Item result = get(key4); + if (result == null) { + if (tag <= Opcodes.H_PUTSTATIC) { + put112(HANDLE, tag, newField(owner, name, desc)); + } else { + put112(HANDLE, tag, newMethod(owner, + name, + desc, + tag == Opcodes.H_INVOKEINTERFACE)); + } + result = new Item(index++, key4); + put(result); + } + return result; + } + + /** + * Adds a handle to the constant pool of the class being + * build. Does nothing if the constant pool already contains a similar item. + * This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, + * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, + * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, + * {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner the internal name of the field or method owner class. + * @param name the name of the field or method. + * @param desc the descriptor of the field or method. + * @return the index of a new or already existing method type reference + * item. + */ + public int newHandle( + final int tag, + final String owner, + final String name, + final String desc) + { + return newHandleItem(tag, owner, name, desc).index; + } + + /** + * Adds an invokedynamic reference to the constant pool of the class being + * build. Does nothing if the constant pool already contains a similar item. + * This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @param name name of the invoked method. + * @param desc descriptor of the invoke method. + * @param bsm the bootstrap method. + * @param bsmArgs the bootstrap method constant arguments. + * + * @return a new or an already existing invokedynamic type reference item. + */ + Item newInvokeDynamicItem( + final String name, + final String desc, + final Handle bsm, + final Object... bsmArgs) + { + // cache for performance + ByteVector bootstrapMethods = this.bootstrapMethods; + if (bootstrapMethods == null) { + bootstrapMethods = this.bootstrapMethods = new ByteVector(); + } + + int position = bootstrapMethods.length; // record current position + + int hashCode = bsm.hashCode(); + bootstrapMethods.putShort(newHandle(bsm.tag, + bsm.owner, + bsm.name, + bsm.desc)); + + int argsLength = bsmArgs.length; + bootstrapMethods.putShort(argsLength); + + for (int i = 0; i < argsLength; i++) { + Object bsmArg = bsmArgs[i]; + hashCode ^= bsmArg.hashCode(); + bootstrapMethods.putShort(newConst(bsmArg)); + } + + byte[] data = bootstrapMethods.data; + int length = (1 + 1 + argsLength) << 1; // (bsm + argCount + arguments) + hashCode &= 0x7FFFFFFF; + Item result = items[hashCode % items.length]; + loop: while (result != null) { + if (result.type != BSM || result.hashCode != hashCode) { + result = result.next; + continue; + } + + // because the data encode the size of the argument + // we don't need to test if these size are equals + int resultPosition = result.intVal; + for (int p = 0; p < length; p++) { + if (data[position + p] != data[resultPosition + p]) { + result = result.next; + continue loop; + } + } + break; + } + + int bootstrapMethodIndex; + if (result != null) { + bootstrapMethodIndex = result.index; + bootstrapMethods.length = position; // revert to old position + } else { + bootstrapMethodIndex = bootstrapMethodsCount++; + result = new Item(bootstrapMethodIndex); + result.set(position, hashCode); + put(result); + } + + // now, create the InvokeDynamic constant + key3.set(name, desc, bootstrapMethodIndex); + result = get(key3); + if (result == null) { + put122(INDY, bootstrapMethodIndex, newNameType(name, desc)); + result = new Item(index++, key3); + put(result); + } + return result; + } + + /** + * Adds an invokedynamic reference to the constant pool of the class being + * build. Does nothing if the constant pool already contains a similar item. + * This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @param name name of the invoked method. + * @param desc descriptor of the invoke method. + * @param bsm the bootstrap method. + * @param bsmArgs the bootstrap method constant arguments. + * + * @return the index of a new or already existing invokedynamic + * reference item. + */ + public int newInvokeDynamic( + final String name, + final String desc, + final Handle bsm, + final Object... bsmArgs) + { + return newInvokeDynamicItem(name, desc, bsm, bsmArgs).index; + } + + /** + * Adds a field reference to the constant pool of the class being build. + * Does nothing if the constant pool already contains a similar item. + * + * @param owner the internal name of the field's owner class. + * @param name the field's name. + * @param desc the field's descriptor. + * @return a new or already existing field reference item. + */ + Item newFieldItem(final String owner, final String name, final String desc) + { + key3.set(FIELD, owner, name, desc); + Item result = get(key3); + if (result == null) { + put122(FIELD, newClass(owner), newNameType(name, desc)); + result = new Item(index++, key3); + put(result); + } + return result; + } + + /** + * Adds a field reference to the constant pool of the class being build. + * Does nothing if the constant pool already contains a similar item. + * This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @param owner the internal name of the field's owner class. + * @param name the field's name. + * @param desc the field's descriptor. + * @return the index of a new or already existing field reference item. + */ + public int newField(final String owner, final String name, final String desc) + { + return newFieldItem(owner, name, desc).index; + } + + /** + * Adds a method reference to the constant pool of the class being build. + * Does nothing if the constant pool already contains a similar item. + * + * @param owner the internal name of the method's owner class. + * @param name the method's name. + * @param desc the method's descriptor. + * @param itf true if owner is an interface. + * @return a new or already existing method reference item. + */ + Item newMethodItem( + final String owner, + final String name, + final String desc, + final boolean itf) + { + int type = itf ? IMETH : METH; + key3.set(type, owner, name, desc); + Item result = get(key3); + if (result == null) { + put122(type, newClass(owner), newNameType(name, desc)); + result = new Item(index++, key3); + put(result); + } + return result; + } + + /** + * Adds a method reference to the constant pool of the class being build. + * Does nothing if the constant pool already contains a similar item. + * This method is intended for {@link Attribute} sub classes, and is + * normally not needed by class generators or adapters. + * + * @param owner the internal name of the method's owner class. + * @param name the method's name. + * @param desc the method's descriptor. + * @param itf true if owner is an interface. + * @return the index of a new or already existing method reference item. + */ + public int newMethod( + final String owner, + final String name, + final String desc, + final boolean itf) + { + return newMethodItem(owner, name, desc, itf).index; + } + + /** + * Adds an integer to the constant pool of the class being build. Does + * nothing if the constant pool already contains a similar item. + * + * @param value the int value. + * @return a new or already existing int item. + */ + Item newInteger(final int value) { + key.set(value); + Item result = get(key); + if (result == null) { + pool.putByte(INT).putInt(value); + result = new Item(index++, key); + put(result); + } + return result; + } + + /** + * Adds a float to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. + * + * @param value the float value. + * @return a new or already existing float item. + */ + Item newFloat(final float value) { + key.set(value); + Item result = get(key); + if (result == null) { + pool.putByte(FLOAT).putInt(key.intVal); + result = new Item(index++, key); + put(result); + } + return result; + } + + /** + * Adds a long to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. + * + * @param value the long value. + * @return a new or already existing long item. + */ + Item newLong(final long value) { + key.set(value); + Item result = get(key); + if (result == null) { + pool.putByte(LONG).putLong(value); + result = new Item(index, key); + index += 2; + put(result); + } + return result; + } + + /** + * Adds a double to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. + * + * @param value the double value. + * @return a new or already existing double item. + */ + Item newDouble(final double value) { + key.set(value); + Item result = get(key); + if (result == null) { + pool.putByte(DOUBLE).putLong(key.longVal); + result = new Item(index, key); + index += 2; + put(result); + } + return result; + } + + /** + * Adds a string to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. + * + * @param value the String value. + * @return a new or already existing string item. + */ + private Item newString(final String value) { + key2.set(STR, value, null, null); + Item result = get(key2); + if (result == null) { + pool.put12(STR, newUTF8(value)); + result = new Item(index++, key2); + put(result); + } + return result; + } + + /** + * Adds a name and type to the constant pool of the class being build. Does + * nothing if the constant pool already contains a similar item. This + * method is intended for {@link Attribute} sub classes, and is normally not + * needed by class generators or adapters. + * + * @param name a name. + * @param desc a type descriptor. + * @return the index of a new or already existing name and type item. + */ + public int newNameType(final String name, final String desc) { + return newNameTypeItem(name, desc).index; + } + + /** + * Adds a name and type to the constant pool of the class being build. Does + * nothing if the constant pool already contains a similar item. + * + * @param name a name. + * @param desc a type descriptor. + * @return a new or already existing name and type item. + */ + Item newNameTypeItem(final String name, final String desc) { + key2.set(NAME_TYPE, name, desc, null); + Item result = get(key2); + if (result == null) { + put122(NAME_TYPE, newUTF8(name), newUTF8(desc)); + result = new Item(index++, key2); + put(result); + } + return result; + } + + /** + * Adds the given internal name to {@link #typeTable} and returns its index. + * Does nothing if the type table already contains this internal name. + * + * @param type the internal name to be added to the type table. + * @return the index of this internal name in the type table. + */ + int addType(final String type) { + key.set(TYPE_NORMAL, type, null, null); + Item result = get(key); + if (result == null) { + result = addType(key); + } + return result.index; + } + + /** + * Adds the given "uninitialized" type to {@link #typeTable} and returns its + * index. This method is used for UNINITIALIZED types, made of an internal + * name and a bytecode offset. + * + * @param type the internal name to be added to the type table. + * @param offset the bytecode offset of the NEW instruction that created + * this UNINITIALIZED type value. + * @return the index of this internal name in the type table. + */ + int addUninitializedType(final String type, final int offset) { + key.type = TYPE_UNINIT; + key.intVal = offset; + key.strVal1 = type; + key.hashCode = 0x7FFFFFFF & (TYPE_UNINIT + type.hashCode() + offset); + Item result = get(key); + if (result == null) { + result = addType(key); + } + return result.index; + } + + /** + * Adds the given Item to {@link #typeTable}. + * + * @param item the value to be added to the type table. + * @return the added Item, which a new Item instance with the same value as + * the given Item. + */ + private Item addType(final Item item) { + ++typeCount; + Item result = new Item(typeCount, key); + put(result); + if (typeTable == null) { + typeTable = new Item[16]; + } + if (typeCount == typeTable.length) { + Item[] newTable = new Item[2 * typeTable.length]; + System.arraycopy(typeTable, 0, newTable, 0, typeTable.length); + typeTable = newTable; + } + typeTable[typeCount] = result; + return result; + } + + /** + * Returns the index of the common super type of the two given types. This + * method calls {@link #getCommonSuperClass} and caches the result in the + * {@link #items} hash table to speedup future calls with the same + * parameters. + * + * @param type1 index of an internal name in {@link #typeTable}. + * @param type2 index of an internal name in {@link #typeTable}. + * @return the index of the common super type of the two given types. + */ + int getMergedType(final int type1, final int type2) { + key2.type = TYPE_MERGED; + key2.longVal = type1 | (((long) type2) << 32); + key2.hashCode = 0x7FFFFFFF & (TYPE_MERGED + type1 + type2); + Item result = get(key2); + if (result == null) { + String t = typeTable[type1].strVal1; + String u = typeTable[type2].strVal1; + key2.intVal = addType(getCommonSuperClass(t, u)); + result = new Item((short) 0, key2); + put(result); + } + return result.intVal; + } + + /** + * Returns the common super type of the two given types. The default + * implementation of this method loads the two given classes and uses + * the java.lang.Class methods to find the common super class. It can be + * overridden to compute this common super type in other ways, in particular + * without actually loading any class, or to take into account the class + * that is currently being generated by this ClassWriter, which can of + * course not be loaded since it is under construction. + * + * @param type1 the internal name of a class. + * @param type2 the internal name of another class. + * @return the internal name of the common super class of the two given + * classes. + */ + protected String getCommonSuperClass(final String type1, final String type2) + { + Class c, d; + ClassLoader classLoader = getClass().getClassLoader(); + try { + c = Class.forName(type1.replace('/', '.'), false, classLoader); + d = Class.forName(type2.replace('/', '.'), false, classLoader); + } catch (Exception e) { + throw new RuntimeException(e.toString()); + } + if (c.isAssignableFrom(d)) { + return type1; + } + if (d.isAssignableFrom(c)) { + return type2; + } + if (c.isInterface() || d.isInterface()) { + return "java/lang/Object"; + } else { + do { + c = c.getSuperclass(); + } while (!c.isAssignableFrom(d)); + return c.getName().replace('.', '/'); + } + } + + /** + * Returns the constant pool's hash table item which is equal to the given + * item. + * + * @param key a constant pool item. + * @return the constant pool's hash table item which is equal to the given + * item, or null if there is no such item. + */ + private Item get(final Item key) { + Item i = items[key.hashCode % items.length]; + while (i != null && (i.type != key.type || !key.isEqualTo(i))) { + i = i.next; + } + return i; + } + + /** + * Puts the given item in the constant pool's hash table. The hash table + * must not already contains this item. + * + * @param i the item to be added to the constant pool's hash table. + */ + private void put(final Item i) { + if (index + typeCount > threshold) { + int ll = items.length; + int nl = ll * 2 + 1; + Item[] newItems = new Item[nl]; + for (int l = ll - 1; l >= 0; --l) { + Item j = items[l]; + while (j != null) { + int index = j.hashCode % newItems.length; + Item k = j.next; + j.next = newItems[index]; + newItems[index] = j; + j = k; + } + } + items = newItems; + threshold = (int) (nl * 0.75); + } + int index = i.hashCode % items.length; + i.next = items[index]; + items[index] = i; + } + + /** + * Puts one byte and two shorts into the constant pool. + * + * @param b a byte. + * @param s1 a short. + * @param s2 another short. + */ + private void put122(final int b, final int s1, final int s2) { + pool.put12(b, s1).putShort(s2); + } + + /** + * Puts two bytes and one short into the constant pool. + * + * @param b1 a byte. + * @param b2 another byte. + * @param s a short. + */ + private void put112(final int b1, final int b2, final int s) { + pool.put11(b1, b2).putShort(s); + } +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Edge.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Edge.java new file mode 100644 index 00000000000..62e1e6ddd6a --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Edge.java @@ -0,0 +1,104 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +/** + * An edge in the control flow graph of a method body. See {@link Label Label}. + * + * @author Eric Bruneton + */ +class Edge { + + /** + * Denotes a normal control flow graph edge. + */ + static final int NORMAL = 0; + + /** + * Denotes a control flow graph edge corresponding to an exception handler. + * More precisely any {@link Edge} whose {@link #info} is strictly positive + * corresponds to an exception handler. The actual value of {@link #info} is + * the index, in the {@link ClassWriter} type table, of the exception that + * is catched. + */ + static final int EXCEPTION = 0x7FFFFFFF; + + /** + * Information about this control flow graph edge. If + * {@link ClassWriter#COMPUTE_MAXS} is used this field is the (relative) + * stack size in the basic block from which this edge originates. This size + * is equal to the stack size at the "jump" instruction to which this edge + * corresponds, relatively to the stack size at the beginning of the + * originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used, + * this field is the kind of this control flow graph edge (i.e. NORMAL or + * EXCEPTION). + */ + int info; + + /** + * The successor block of the basic block from which this edge originates. + */ + Label successor; + + /** + * The next edge in the list of successors of the originating basic block. + * See {@link Label#successors successors}. + */ + Edge next; +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/FieldVisitor.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/FieldVisitor.java new file mode 100644 index 00000000000..116be9fe7af --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/FieldVisitor.java @@ -0,0 +1,144 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +/** + * A visitor to visit a Java field. The methods of this class must be called + * in the following order: ( visitAnnotation | + * visitAttribute )* visitEnd. + * + * @author Eric Bruneton + */ +public abstract class FieldVisitor { + + /** + * The ASM API version implemented by this visitor. The value of this field + * must be one of {@link Opcodes#ASM4}. + */ + protected final int api; + + /** + * The field visitor to which this visitor must delegate method calls. May + * be null. + */ + protected FieldVisitor fv; + + /** + * Constructs a new {@link FieldVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + */ + public FieldVisitor(final int api) { + this(api, null); + } + + /** + * Constructs a new {@link FieldVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param fv the field visitor to which this visitor must delegate method + * calls. May be null. + */ + public FieldVisitor(final int api, final FieldVisitor fv) { + /*if (api != Opcodes.ASM4) { + throw new IllegalArgumentException(); + }*/ + this.api = api; + this.fv = fv; + } + + /** + * Visits an annotation of the field. + * + * @param desc the class descriptor of the annotation class. + * @param visible true if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or null if + * this visitor is not interested in visiting this annotation. + */ + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + if (fv != null) { + return fv.visitAnnotation(desc, visible); + } + return null; + } + + /** + * Visits a non standard attribute of the field. + * + * @param attr an attribute. + */ + public void visitAttribute(Attribute attr) { + if (fv != null) { + fv.visitAttribute(attr); + } + } + + /** + * Visits the end of the field. This method, which is the last one to be + * called, is used to inform the visitor that all the annotations and + * attributes of the field have been visited. + */ + public void visitEnd() { + if (fv != null) { + fv.visitEnd(); + } + } +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/FieldWriter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/FieldWriter.java new file mode 100644 index 00000000000..53d3fa2866f --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/FieldWriter.java @@ -0,0 +1,300 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +/** + * An {@link FieldVisitor} that generates Java fields in bytecode form. + * + * @author Eric Bruneton + */ +final class FieldWriter extends FieldVisitor { + + /** + * The class writer to which this field must be added. + */ + private final ClassWriter cw; + + /** + * Access flags of this field. + */ + private final int access; + + /** + * The index of the constant pool item that contains the name of this + * method. + */ + private final int name; + + /** + * The index of the constant pool item that contains the descriptor of this + * field. + */ + private final int desc; + + /** + * The index of the constant pool item that contains the signature of this + * field. + */ + private int signature; + + /** + * The index of the constant pool item that contains the constant value of + * this field. + */ + private int value; + + /** + * The runtime visible annotations of this field. May be null. + */ + private AnnotationWriter anns; + + /** + * The runtime invisible annotations of this field. May be null. + */ + private AnnotationWriter ianns; + + /** + * The non standard attributes of this field. May be null. + */ + private Attribute attrs; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructs a new {@link FieldWriter}. + * + * @param cw the class writer to which this field must be added. + * @param access the field's access flags (see {@link Opcodes}). + * @param name the field's name. + * @param desc the field's descriptor (see {@link Type}). + * @param signature the field's signature. May be null. + * @param value the field's constant value. May be null. + */ + FieldWriter( + final ClassWriter cw, + final int access, + final String name, + final String desc, + final String signature, + final Object value) + { + super(Opcodes.ASM4); + if (cw.firstField == null) { + cw.firstField = this; + } else { + cw.lastField.fv = this; + } + cw.lastField = this; + this.cw = cw; + this.access = access; + this.name = cw.newUTF8(name); + this.desc = cw.newUTF8(desc); + if (ClassReader.SIGNATURES && signature != null) { + this.signature = cw.newUTF8(signature); + } + if (value != null) { + this.value = cw.newConstItem(value).index; + } + } + + // ------------------------------------------------------------------------ + // Implementation of the FieldVisitor abstract class + // ------------------------------------------------------------------------ + + @Override + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + if (!ClassReader.ANNOTATIONS) { + return null; + } + ByteVector bv = new ByteVector(); + // write type, and reserve space for values count + bv.putShort(cw.newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); + if (visible) { + aw.next = anns; + anns = aw; + } else { + aw.next = ianns; + ianns = aw; + } + return aw; + } + + @Override + public void visitAttribute(final Attribute attr) { + attr.next = attrs; + attrs = attr; + } + + @Override + public void visitEnd() { + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + /** + * Returns the size of this field. + * + * @return the size of this field. + */ + int getSize() { + int size = 8; + if (value != 0) { + cw.newUTF8("ConstantValue"); + size += 8; + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0 + && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) + { + cw.newUTF8("Synthetic"); + size += 6; + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + cw.newUTF8("Deprecated"); + size += 6; + } + if (ClassReader.SIGNATURES && signature != 0) { + cw.newUTF8("Signature"); + size += 8; + } + if (ClassReader.ANNOTATIONS && anns != null) { + cw.newUTF8("RuntimeVisibleAnnotations"); + size += 8 + anns.getSize(); + } + if (ClassReader.ANNOTATIONS && ianns != null) { + cw.newUTF8("RuntimeInvisibleAnnotations"); + size += 8 + ianns.getSize(); + } + if (attrs != null) { + size += attrs.getSize(cw, null, 0, -1, -1); + } + return size; + } + + /** + * Puts the content of this field into the given byte vector. + * + * @param out where the content of this field must be put. + */ + void put(final ByteVector out) { + int mask = Opcodes.ACC_DEPRECATED + | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE + | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / (ClassWriter.ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC)); + out.putShort(access & ~mask).putShort(name).putShort(desc); + int attributeCount = 0; + if (value != 0) { + ++attributeCount; + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0 + && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) + { + ++attributeCount; + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + ++attributeCount; + } + if (ClassReader.SIGNATURES && signature != 0) { + ++attributeCount; + } + if (ClassReader.ANNOTATIONS && anns != null) { + ++attributeCount; + } + if (ClassReader.ANNOTATIONS && ianns != null) { + ++attributeCount; + } + if (attrs != null) { + attributeCount += attrs.getCount(); + } + out.putShort(attributeCount); + if (value != 0) { + out.putShort(cw.newUTF8("ConstantValue")); + out.putInt(2).putShort(value); + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0 + && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) + { + out.putShort(cw.newUTF8("Synthetic")).putInt(0); + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + out.putShort(cw.newUTF8("Deprecated")).putInt(0); + } + if (ClassReader.SIGNATURES && signature != 0) { + out.putShort(cw.newUTF8("Signature")); + out.putInt(2).putShort(signature); + } + if (ClassReader.ANNOTATIONS && anns != null) { + out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); + anns.put(out); + } + if (ClassReader.ANNOTATIONS && ianns != null) { + out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); + ianns.put(out); + } + if (attrs != null) { + attrs.put(cw, null, 0, -1, -1, out); + } + } +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Frame.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Frame.java new file mode 100644 index 00000000000..48e331d35f5 --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Frame.java @@ -0,0 +1,1464 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +/** + * Information about the input and output stack map frames of a basic block. + * + * @author Eric Bruneton + */ +final class Frame { + + /* + * Frames are computed in a two steps process: during the visit of each + * instruction, the state of the frame at the end of current basic block is + * updated by simulating the action of the instruction on the previous state + * of this so called "output frame". In visitMaxs, a fix point algorithm is + * used to compute the "input frame" of each basic block, i.e. the stack map + * frame at the beginning of the basic block, starting from the input frame + * of the first basic block (which is computed from the method descriptor), + * and by using the previously computed output frames to compute the input + * state of the other blocks. + * + * All output and input frames are stored as arrays of integers. Reference + * and array types are represented by an index into a type table (which is + * not the same as the constant pool of the class, in order to avoid adding + * unnecessary constants in the pool - not all computed frames will end up + * being stored in the stack map table). This allows very fast type + * comparisons. + * + * Output stack map frames are computed relatively to the input frame of the + * basic block, which is not yet known when output frames are computed. It + * is therefore necessary to be able to represent abstract types such as + * "the type at position x in the input frame locals" or "the type at + * position x from the top of the input frame stack" or even "the type at + * position x in the input frame, with y more (or less) array dimensions". + * This explains the rather complicated type format used in output frames. + * + * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a + * signed number of array dimensions (from -8 to 7). KIND is either BASE, + * LOCAL or STACK. BASE is used for types that are not relative to the input + * frame. LOCAL is used for types that are relative to the input local + * variable types. STACK is used for types that are relative to the input + * stack types. VALUE depends on KIND. For LOCAL types, it is an index in + * the input local variable types. For STACK types, it is a position + * relatively to the top of input frame stack. For BASE types, it is either + * one of the constants defined in FrameVisitor, or for OBJECT and + * UNINITIALIZED types, a tag and an index in the type table. + * + * Output frames can contain types of any kind and with a positive or + * negative dimension (and even unassigned types, represented by 0 - which + * does not correspond to any valid type value). Input frames can only + * contain BASE types of positive or null dimension. In all cases the type + * table contains only internal type names (array type descriptors are + * forbidden - dimensions must be represented through the DIM field). + * + * The LONG and DOUBLE types are always represented by using two slots (LONG + + * TOP or DOUBLE + TOP), for local variable types as well as in the operand + * stack. This is necessary to be able to simulate DUPx_y instructions, + * whose effect would be dependent on the actual type values if types were + * always represented by a single slot in the stack (and this is not + * possible, since actual type values are not always known - cf LOCAL and + * STACK type kinds). + */ + + /** + * Mask to get the dimension of a frame type. This dimension is a signed + * integer between -8 and 7. + */ + static final int DIM = 0xF0000000; + + /** + * Constant to be added to a type to get a type with one more dimension. + */ + static final int ARRAY_OF = 0x10000000; + + /** + * Constant to be added to a type to get a type with one less dimension. + */ + static final int ELEMENT_OF = 0xF0000000; + + /** + * Mask to get the kind of a frame type. + * + * @see #BASE + * @see #LOCAL + * @see #STACK + */ + static final int KIND = 0xF000000; + + /** + * Flag used for LOCAL and STACK types. Indicates that if this type happens + * to be a long or double type (during the computations of input frames), + * then it must be set to TOP because the second word of this value has + * been reused to store other data in the basic block. Hence the first word + * no longer stores a valid long or double value. + */ + static final int TOP_IF_LONG_OR_DOUBLE = 0x800000; + + /** + * Mask to get the value of a frame type. + */ + static final int VALUE = 0x7FFFFF; + + /** + * Mask to get the kind of base types. + */ + static final int BASE_KIND = 0xFF00000; + + /** + * Mask to get the value of base types. + */ + static final int BASE_VALUE = 0xFFFFF; + + /** + * Kind of the types that are not relative to an input stack map frame. + */ + static final int BASE = 0x1000000; + + /** + * Base kind of the base reference types. The BASE_VALUE of such types is an + * index into the type table. + */ + static final int OBJECT = BASE | 0x700000; + + /** + * Base kind of the uninitialized base types. The BASE_VALUE of such types + * in an index into the type table (the Item at that index contains both an + * instruction offset and an internal class name). + */ + static final int UNINITIALIZED = BASE | 0x800000; + + /** + * Kind of the types that are relative to the local variable types of an + * input stack map frame. The value of such types is a local variable index. + */ + private static final int LOCAL = 0x2000000; + + /** + * Kind of the the types that are relative to the stack of an input stack + * map frame. The value of such types is a position relatively to the top of + * this stack. + */ + private static final int STACK = 0x3000000; + + /** + * The TOP type. This is a BASE type. + */ + static final int TOP = BASE | 0; + + /** + * The BOOLEAN type. This is a BASE type mainly used for array types. + */ + static final int BOOLEAN = BASE | 9; + + /** + * The BYTE type. This is a BASE type mainly used for array types. + */ + static final int BYTE = BASE | 10; + + /** + * The CHAR type. This is a BASE type mainly used for array types. + */ + static final int CHAR = BASE | 11; + + /** + * The SHORT type. This is a BASE type mainly used for array types. + */ + static final int SHORT = BASE | 12; + + /** + * The INTEGER type. This is a BASE type. + */ + static final int INTEGER = BASE | 1; + + /** + * The FLOAT type. This is a BASE type. + */ + static final int FLOAT = BASE | 2; + + /** + * The DOUBLE type. This is a BASE type. + */ + static final int DOUBLE = BASE | 3; + + /** + * The LONG type. This is a BASE type. + */ + static final int LONG = BASE | 4; + + /** + * The NULL type. This is a BASE type. + */ + static final int NULL = BASE | 5; + + /** + * The UNINITIALIZED_THIS type. This is a BASE type. + */ + static final int UNINITIALIZED_THIS = BASE | 6; + + /** + * The stack size variation corresponding to each JVM instruction. This + * stack variation is equal to the size of the values produced by an + * instruction, minus the size of the values consumed by this instruction. + */ + static final int[] SIZE; + + /** + * Computes the stack size variation corresponding to each JVM instruction. + */ + static { + int i; + int[] b = new int[202]; + String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD" + + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD" + + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED" + + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE"; + for (i = 0; i < b.length; ++i) { + b[i] = s.charAt(i) - 'E'; + } + SIZE = b; + + // code to generate the above string + // + // int NA = 0; // not applicable (unused opcode or variable size opcode) + // + // b = new int[] { + // 0, //NOP, // visitInsn + // 1, //ACONST_NULL, // - + // 1, //ICONST_M1, // - + // 1, //ICONST_0, // - + // 1, //ICONST_1, // - + // 1, //ICONST_2, // - + // 1, //ICONST_3, // - + // 1, //ICONST_4, // - + // 1, //ICONST_5, // - + // 2, //LCONST_0, // - + // 2, //LCONST_1, // - + // 1, //FCONST_0, // - + // 1, //FCONST_1, // - + // 1, //FCONST_2, // - + // 2, //DCONST_0, // - + // 2, //DCONST_1, // - + // 1, //BIPUSH, // visitIntInsn + // 1, //SIPUSH, // - + // 1, //LDC, // visitLdcInsn + // NA, //LDC_W, // - + // NA, //LDC2_W, // - + // 1, //ILOAD, // visitVarInsn + // 2, //LLOAD, // - + // 1, //FLOAD, // - + // 2, //DLOAD, // - + // 1, //ALOAD, // - + // NA, //ILOAD_0, // - + // NA, //ILOAD_1, // - + // NA, //ILOAD_2, // - + // NA, //ILOAD_3, // - + // NA, //LLOAD_0, // - + // NA, //LLOAD_1, // - + // NA, //LLOAD_2, // - + // NA, //LLOAD_3, // - + // NA, //FLOAD_0, // - + // NA, //FLOAD_1, // - + // NA, //FLOAD_2, // - + // NA, //FLOAD_3, // - + // NA, //DLOAD_0, // - + // NA, //DLOAD_1, // - + // NA, //DLOAD_2, // - + // NA, //DLOAD_3, // - + // NA, //ALOAD_0, // - + // NA, //ALOAD_1, // - + // NA, //ALOAD_2, // - + // NA, //ALOAD_3, // - + // -1, //IALOAD, // visitInsn + // 0, //LALOAD, // - + // -1, //FALOAD, // - + // 0, //DALOAD, // - + // -1, //AALOAD, // - + // -1, //BALOAD, // - + // -1, //CALOAD, // - + // -1, //SALOAD, // - + // -1, //ISTORE, // visitVarInsn + // -2, //LSTORE, // - + // -1, //FSTORE, // - + // -2, //DSTORE, // - + // -1, //ASTORE, // - + // NA, //ISTORE_0, // - + // NA, //ISTORE_1, // - + // NA, //ISTORE_2, // - + // NA, //ISTORE_3, // - + // NA, //LSTORE_0, // - + // NA, //LSTORE_1, // - + // NA, //LSTORE_2, // - + // NA, //LSTORE_3, // - + // NA, //FSTORE_0, // - + // NA, //FSTORE_1, // - + // NA, //FSTORE_2, // - + // NA, //FSTORE_3, // - + // NA, //DSTORE_0, // - + // NA, //DSTORE_1, // - + // NA, //DSTORE_2, // - + // NA, //DSTORE_3, // - + // NA, //ASTORE_0, // - + // NA, //ASTORE_1, // - + // NA, //ASTORE_2, // - + // NA, //ASTORE_3, // - + // -3, //IASTORE, // visitInsn + // -4, //LASTORE, // - + // -3, //FASTORE, // - + // -4, //DASTORE, // - + // -3, //AASTORE, // - + // -3, //BASTORE, // - + // -3, //CASTORE, // - + // -3, //SASTORE, // - + // -1, //POP, // - + // -2, //POP2, // - + // 1, //DUP, // - + // 1, //DUP_X1, // - + // 1, //DUP_X2, // - + // 2, //DUP2, // - + // 2, //DUP2_X1, // - + // 2, //DUP2_X2, // - + // 0, //SWAP, // - + // -1, //IADD, // - + // -2, //LADD, // - + // -1, //FADD, // - + // -2, //DADD, // - + // -1, //ISUB, // - + // -2, //LSUB, // - + // -1, //FSUB, // - + // -2, //DSUB, // - + // -1, //IMUL, // - + // -2, //LMUL, // - + // -1, //FMUL, // - + // -2, //DMUL, // - + // -1, //IDIV, // - + // -2, //LDIV, // - + // -1, //FDIV, // - + // -2, //DDIV, // - + // -1, //IREM, // - + // -2, //LREM, // - + // -1, //FREM, // - + // -2, //DREM, // - + // 0, //INEG, // - + // 0, //LNEG, // - + // 0, //FNEG, // - + // 0, //DNEG, // - + // -1, //ISHL, // - + // -1, //LSHL, // - + // -1, //ISHR, // - + // -1, //LSHR, // - + // -1, //IUSHR, // - + // -1, //LUSHR, // - + // -1, //IAND, // - + // -2, //LAND, // - + // -1, //IOR, // - + // -2, //LOR, // - + // -1, //IXOR, // - + // -2, //LXOR, // - + // 0, //IINC, // visitIincInsn + // 1, //I2L, // visitInsn + // 0, //I2F, // - + // 1, //I2D, // - + // -1, //L2I, // - + // -1, //L2F, // - + // 0, //L2D, // - + // 0, //F2I, // - + // 1, //F2L, // - + // 1, //F2D, // - + // -1, //D2I, // - + // 0, //D2L, // - + // -1, //D2F, // - + // 0, //I2B, // - + // 0, //I2C, // - + // 0, //I2S, // - + // -3, //LCMP, // - + // -1, //FCMPL, // - + // -1, //FCMPG, // - + // -3, //DCMPL, // - + // -3, //DCMPG, // - + // -1, //IFEQ, // visitJumpInsn + // -1, //IFNE, // - + // -1, //IFLT, // - + // -1, //IFGE, // - + // -1, //IFGT, // - + // -1, //IFLE, // - + // -2, //IF_ICMPEQ, // - + // -2, //IF_ICMPNE, // - + // -2, //IF_ICMPLT, // - + // -2, //IF_ICMPGE, // - + // -2, //IF_ICMPGT, // - + // -2, //IF_ICMPLE, // - + // -2, //IF_ACMPEQ, // - + // -2, //IF_ACMPNE, // - + // 0, //GOTO, // - + // 1, //JSR, // - + // 0, //RET, // visitVarInsn + // -1, //TABLESWITCH, // visiTableSwitchInsn + // -1, //LOOKUPSWITCH, // visitLookupSwitch + // -1, //IRETURN, // visitInsn + // -2, //LRETURN, // - + // -1, //FRETURN, // - + // -2, //DRETURN, // - + // -1, //ARETURN, // - + // 0, //RETURN, // - + // NA, //GETSTATIC, // visitFieldInsn + // NA, //PUTSTATIC, // - + // NA, //GETFIELD, // - + // NA, //PUTFIELD, // - + // NA, //INVOKEVIRTUAL, // visitMethodInsn + // NA, //INVOKESPECIAL, // - + // NA, //INVOKESTATIC, // - + // NA, //INVOKEINTERFACE, // - + // NA, //INVOKEDYNAMIC, // visitInvokeDynamicInsn + // 1, //NEW, // visitTypeInsn + // 0, //NEWARRAY, // visitIntInsn + // 0, //ANEWARRAY, // visitTypeInsn + // 0, //ARRAYLENGTH, // visitInsn + // NA, //ATHROW, // - + // 0, //CHECKCAST, // visitTypeInsn + // 0, //INSTANCEOF, // - + // -1, //MONITORENTER, // visitInsn + // -1, //MONITOREXIT, // - + // NA, //WIDE, // NOT VISITED + // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn + // -1, //IFNULL, // visitJumpInsn + // -1, //IFNONNULL, // - + // NA, //GOTO_W, // - + // NA, //JSR_W, // - + // }; + // for (i = 0; i < b.length; ++i) { + // System.err.print((char)('E' + b[i])); + // } + // System.err.println(); + } + + /** + * The label (i.e. basic block) to which these input and output stack map + * frames correspond. + */ + Label owner; + + /** + * The input stack map frame locals. + */ + int[] inputLocals; + + /** + * The input stack map frame stack. + */ + int[] inputStack; + + /** + * The output stack map frame locals. + */ + private int[] outputLocals; + + /** + * The output stack map frame stack. + */ + private int[] outputStack; + + /** + * Relative size of the output stack. The exact semantics of this field + * depends on the algorithm that is used. + * + * When only the maximum stack size is computed, this field is the size of + * the output stack relatively to the top of the input stack. + * + * When the stack map frames are completely computed, this field is the + * actual number of types in {@link #outputStack}. + */ + private int outputStackTop; + + /** + * Number of types that are initialized in the basic block. + * + * @see #initializations + */ + private int initializationCount; + + /** + * The types that are initialized in the basic block. A constructor + * invocation on an UNINITIALIZED or UNINITIALIZED_THIS type must replace + * every occurence of this type in the local variables and in the + * operand stack. This cannot be done during the first phase of the + * algorithm since, during this phase, the local variables and the operand + * stack are not completely computed. It is therefore necessary to store the + * types on which constructors are invoked in the basic block, in order to + * do this replacement during the second phase of the algorithm, where the + * frames are fully computed. Note that this array can contain types that + * are relative to input locals or to the input stack (see below for the + * description of the algorithm). + */ + private int[] initializations; + + /** + * Returns the output frame local variable type at the given index. + * + * @param local the index of the local that must be returned. + * @return the output frame local variable type at the given index. + */ + private int get(final int local) { + if (outputLocals == null || local >= outputLocals.length) { + // this local has never been assigned in this basic block, + // so it is still equal to its value in the input frame + return LOCAL | local; + } else { + int type = outputLocals[local]; + if (type == 0) { + // this local has never been assigned in this basic block, + // so it is still equal to its value in the input frame + type = outputLocals[local] = LOCAL | local; + } + return type; + } + } + + /** + * Sets the output frame local variable type at the given index. + * + * @param local the index of the local that must be set. + * @param type the value of the local that must be set. + */ + private void set(final int local, final int type) { + // creates and/or resizes the output local variables array if necessary + if (outputLocals == null) { + outputLocals = new int[10]; + } + int n = outputLocals.length; + if (local >= n) { + int[] t = new int[Math.max(local + 1, 2 * n)]; + System.arraycopy(outputLocals, 0, t, 0, n); + outputLocals = t; + } + // sets the local variable + outputLocals[local] = type; + } + + /** + * Pushes a new type onto the output frame stack. + * + * @param type the type that must be pushed. + */ + private void push(final int type) { + // creates and/or resizes the output stack array if necessary + if (outputStack == null) { + outputStack = new int[10]; + } + int n = outputStack.length; + if (outputStackTop >= n) { + int[] t = new int[Math.max(outputStackTop + 1, 2 * n)]; + System.arraycopy(outputStack, 0, t, 0, n); + outputStack = t; + } + // pushes the type on the output stack + outputStack[outputStackTop++] = type; + // updates the maximun height reached by the output stack, if needed + int top = owner.inputStackTop + outputStackTop; + if (top > owner.outputStackMax) { + owner.outputStackMax = top; + } + } + + /** + * Pushes a new type onto the output frame stack. + * + * @param cw the ClassWriter to which this label belongs. + * @param desc the descriptor of the type to be pushed. Can also be a method + * descriptor (in this case this method pushes its return type onto + * the output frame stack). + */ + private void push(final ClassWriter cw, final String desc) { + int type = type(cw, desc); + if (type != 0) { + push(type); + if (type == LONG || type == DOUBLE) { + push(TOP); + } + } + } + + /** + * Returns the int encoding of the given type. + * + * @param cw the ClassWriter to which this label belongs. + * @param desc a type descriptor. + * @return the int encoding of the given type. + */ + private static int type(final ClassWriter cw, final String desc) { + String t; + int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0; + switch (desc.charAt(index)) { + case 'V': + return 0; + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + return INTEGER; + case 'F': + return FLOAT; + case 'J': + return LONG; + case 'D': + return DOUBLE; + case 'L': + // stores the internal name, not the descriptor! + t = desc.substring(index + 1, desc.length() - 1); + return OBJECT | cw.addType(t); + // case '[': + default: + // extracts the dimensions and the element type + int data; + int dims = index + 1; + while (desc.charAt(dims) == '[') { + ++dims; + } + switch (desc.charAt(dims)) { + case 'Z': + data = BOOLEAN; + break; + case 'C': + data = CHAR; + break; + case 'B': + data = BYTE; + break; + case 'S': + data = SHORT; + break; + case 'I': + data = INTEGER; + break; + case 'F': + data = FLOAT; + break; + case 'J': + data = LONG; + break; + case 'D': + data = DOUBLE; + break; + // case 'L': + default: + // stores the internal name, not the descriptor + t = desc.substring(dims + 1, desc.length() - 1); + data = OBJECT | cw.addType(t); + } + return (dims - index) << 28 | data; + } + } + + /** + * Pops a type from the output frame stack and returns its value. + * + * @return the type that has been popped from the output frame stack. + */ + private int pop() { + if (outputStackTop > 0) { + return outputStack[--outputStackTop]; + } else { + // if the output frame stack is empty, pops from the input stack + return STACK | -(--owner.inputStackTop); + } + } + + /** + * Pops the given number of types from the output frame stack. + * + * @param elements the number of types that must be popped. + */ + private void pop(final int elements) { + if (outputStackTop >= elements) { + outputStackTop -= elements; + } else { + // if the number of elements to be popped is greater than the number + // of elements in the output stack, clear it, and pops the remaining + // elements from the input stack. + owner.inputStackTop -= elements - outputStackTop; + outputStackTop = 0; + } + } + + /** + * Pops a type from the output frame stack. + * + * @param desc the descriptor of the type to be popped. Can also be a method + * descriptor (in this case this method pops the types corresponding + * to the method arguments). + */ + private void pop(final String desc) { + char c = desc.charAt(0); + if (c == '(') { + pop((Type.getArgumentsAndReturnSizes(desc) >> 2) - 1); + } else if (c == 'J' || c == 'D') { + pop(2); + } else { + pop(1); + } + } + + /** + * Adds a new type to the list of types on which a constructor is invoked in + * the basic block. + * + * @param var a type on a which a constructor is invoked. + */ + private void init(final int var) { + // creates and/or resizes the initializations array if necessary + if (initializations == null) { + initializations = new int[2]; + } + int n = initializations.length; + if (initializationCount >= n) { + int[] t = new int[Math.max(initializationCount + 1, 2 * n)]; + System.arraycopy(initializations, 0, t, 0, n); + initializations = t; + } + // stores the type to be initialized + initializations[initializationCount++] = var; + } + + /** + * Replaces the given type with the appropriate type if it is one of the + * types on which a constructor is invoked in the basic block. + * + * @param cw the ClassWriter to which this label belongs. + * @param t a type + * @return t or, if t is one of the types on which a constructor is invoked + * in the basic block, the type corresponding to this constructor. + */ + private int init(final ClassWriter cw, final int t) { + int s; + if (t == UNINITIALIZED_THIS) { + s = OBJECT | cw.addType(cw.thisName); + } else if ((t & (DIM | BASE_KIND)) == UNINITIALIZED) { + String type = cw.typeTable[t & BASE_VALUE].strVal1; + s = OBJECT | cw.addType(type); + } else { + return t; + } + for (int j = 0; j < initializationCount; ++j) { + int u = initializations[j]; + int dim = u & DIM; + int kind = u & KIND; + if (kind == LOCAL) { + u = dim + inputLocals[u & VALUE]; + } else if (kind == STACK) { + u = dim + inputStack[inputStack.length - (u & VALUE)]; + } + if (t == u) { + return s; + } + } + return t; + } + + /** + * Initializes the input frame of the first basic block from the method + * descriptor. + * + * @param cw the ClassWriter to which this label belongs. + * @param access the access flags of the method to which this label belongs. + * @param args the formal parameter types of this method. + * @param maxLocals the maximum number of local variables of this method. + */ + void initInputFrame( + final ClassWriter cw, + final int access, + final Type[] args, + final int maxLocals) + { + inputLocals = new int[maxLocals]; + inputStack = new int[0]; + int i = 0; + if ((access & Opcodes.ACC_STATIC) == 0) { + if ((access & MethodWriter.ACC_CONSTRUCTOR) == 0) { + inputLocals[i++] = OBJECT | cw.addType(cw.thisName); + } else { + inputLocals[i++] = UNINITIALIZED_THIS; + } + } + for (int j = 0; j < args.length; ++j) { + int t = type(cw, args[j].getDescriptor()); + inputLocals[i++] = t; + if (t == LONG || t == DOUBLE) { + inputLocals[i++] = TOP; + } + } + while (i < maxLocals) { + inputLocals[i++] = TOP; + } + } + + /** + * Simulates the action of the given instruction on the output stack frame. + * + * @param opcode the opcode of the instruction. + * @param arg the operand of the instruction, if any. + * @param cw the class writer to which this label belongs. + * @param item the operand of the instructions, if any. + */ + void execute( + final int opcode, + final int arg, + final ClassWriter cw, + final Item item) + { + int t1, t2, t3, t4; + switch (opcode) { + case Opcodes.NOP: + case Opcodes.INEG: + case Opcodes.LNEG: + case Opcodes.FNEG: + case Opcodes.DNEG: + case Opcodes.I2B: + case Opcodes.I2C: + case Opcodes.I2S: + case Opcodes.GOTO: + case Opcodes.RETURN: + break; + case Opcodes.ACONST_NULL: + push(NULL); + break; + case Opcodes.ICONST_M1: + case Opcodes.ICONST_0: + case Opcodes.ICONST_1: + case Opcodes.ICONST_2: + case Opcodes.ICONST_3: + case Opcodes.ICONST_4: + case Opcodes.ICONST_5: + case Opcodes.BIPUSH: + case Opcodes.SIPUSH: + case Opcodes.ILOAD: + push(INTEGER); + break; + case Opcodes.LCONST_0: + case Opcodes.LCONST_1: + case Opcodes.LLOAD: + push(LONG); + push(TOP); + break; + case Opcodes.FCONST_0: + case Opcodes.FCONST_1: + case Opcodes.FCONST_2: + case Opcodes.FLOAD: + push(FLOAT); + break; + case Opcodes.DCONST_0: + case Opcodes.DCONST_1: + case Opcodes.DLOAD: + push(DOUBLE); + push(TOP); + break; + case Opcodes.LDC: + switch (item.type) { + case ClassWriter.INT: + push(INTEGER); + break; + case ClassWriter.LONG: + push(LONG); + push(TOP); + break; + case ClassWriter.FLOAT: + push(FLOAT); + break; + case ClassWriter.DOUBLE: + push(DOUBLE); + push(TOP); + break; + case ClassWriter.CLASS: + push(OBJECT | cw.addType("java/lang/Class")); + break; + case ClassWriter.STR: + push(OBJECT | cw.addType("java/lang/String")); + break; + case ClassWriter.MTYPE: + push(OBJECT | cw.addType("java/lang/invoke/MethodType")); + break; + // case ClassWriter.HANDLE_BASE + [1..9]: + default: + push(OBJECT | cw.addType("java/lang/invoke/MethodHandle")); + } + break; + case Opcodes.ALOAD: + push(get(arg)); + break; + case Opcodes.IALOAD: + case Opcodes.BALOAD: + case Opcodes.CALOAD: + case Opcodes.SALOAD: + pop(2); + push(INTEGER); + break; + case Opcodes.LALOAD: + case Opcodes.D2L: + pop(2); + push(LONG); + push(TOP); + break; + case Opcodes.FALOAD: + pop(2); + push(FLOAT); + break; + case Opcodes.DALOAD: + case Opcodes.L2D: + pop(2); + push(DOUBLE); + push(TOP); + break; + case Opcodes.AALOAD: + pop(1); + t1 = pop(); + push(ELEMENT_OF + t1); + break; + case Opcodes.ISTORE: + case Opcodes.FSTORE: + case Opcodes.ASTORE: + t1 = pop(); + set(arg, t1); + if (arg > 0) { + t2 = get(arg - 1); + // if t2 is of kind STACK or LOCAL we cannot know its size! + if (t2 == LONG || t2 == DOUBLE) { + set(arg - 1, TOP); + } else if ((t2 & KIND) != BASE) { + set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); + } + } + break; + case Opcodes.LSTORE: + case Opcodes.DSTORE: + pop(1); + t1 = pop(); + set(arg, t1); + set(arg + 1, TOP); + if (arg > 0) { + t2 = get(arg - 1); + // if t2 is of kind STACK or LOCAL we cannot know its size! + if (t2 == LONG || t2 == DOUBLE) { + set(arg - 1, TOP); + } else if ((t2 & KIND) != BASE) { + set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); + } + } + break; + case Opcodes.IASTORE: + case Opcodes.BASTORE: + case Opcodes.CASTORE: + case Opcodes.SASTORE: + case Opcodes.FASTORE: + case Opcodes.AASTORE: + pop(3); + break; + case Opcodes.LASTORE: + case Opcodes.DASTORE: + pop(4); + break; + case Opcodes.POP: + case Opcodes.IFEQ: + case Opcodes.IFNE: + case Opcodes.IFLT: + case Opcodes.IFGE: + case Opcodes.IFGT: + case Opcodes.IFLE: + case Opcodes.IRETURN: + case Opcodes.FRETURN: + case Opcodes.ARETURN: + case Opcodes.TABLESWITCH: + case Opcodes.LOOKUPSWITCH: + case Opcodes.ATHROW: + case Opcodes.MONITORENTER: + case Opcodes.MONITOREXIT: + case Opcodes.IFNULL: + case Opcodes.IFNONNULL: + pop(1); + break; + case Opcodes.POP2: + case Opcodes.IF_ICMPEQ: + case Opcodes.IF_ICMPNE: + case Opcodes.IF_ICMPLT: + case Opcodes.IF_ICMPGE: + case Opcodes.IF_ICMPGT: + case Opcodes.IF_ICMPLE: + case Opcodes.IF_ACMPEQ: + case Opcodes.IF_ACMPNE: + case Opcodes.LRETURN: + case Opcodes.DRETURN: + pop(2); + break; + case Opcodes.DUP: + t1 = pop(); + push(t1); + push(t1); + break; + case Opcodes.DUP_X1: + t1 = pop(); + t2 = pop(); + push(t1); + push(t2); + push(t1); + break; + case Opcodes.DUP_X2: + t1 = pop(); + t2 = pop(); + t3 = pop(); + push(t1); + push(t3); + push(t2); + push(t1); + break; + case Opcodes.DUP2: + t1 = pop(); + t2 = pop(); + push(t2); + push(t1); + push(t2); + push(t1); + break; + case Opcodes.DUP2_X1: + t1 = pop(); + t2 = pop(); + t3 = pop(); + push(t2); + push(t1); + push(t3); + push(t2); + push(t1); + break; + case Opcodes.DUP2_X2: + t1 = pop(); + t2 = pop(); + t3 = pop(); + t4 = pop(); + push(t2); + push(t1); + push(t4); + push(t3); + push(t2); + push(t1); + break; + case Opcodes.SWAP: + t1 = pop(); + t2 = pop(); + push(t1); + push(t2); + break; + case Opcodes.IADD: + case Opcodes.ISUB: + case Opcodes.IMUL: + case Opcodes.IDIV: + case Opcodes.IREM: + case Opcodes.IAND: + case Opcodes.IOR: + case Opcodes.IXOR: + case Opcodes.ISHL: + case Opcodes.ISHR: + case Opcodes.IUSHR: + case Opcodes.L2I: + case Opcodes.D2I: + case Opcodes.FCMPL: + case Opcodes.FCMPG: + pop(2); + push(INTEGER); + break; + case Opcodes.LADD: + case Opcodes.LSUB: + case Opcodes.LMUL: + case Opcodes.LDIV: + case Opcodes.LREM: + case Opcodes.LAND: + case Opcodes.LOR: + case Opcodes.LXOR: + pop(4); + push(LONG); + push(TOP); + break; + case Opcodes.FADD: + case Opcodes.FSUB: + case Opcodes.FMUL: + case Opcodes.FDIV: + case Opcodes.FREM: + case Opcodes.L2F: + case Opcodes.D2F: + pop(2); + push(FLOAT); + break; + case Opcodes.DADD: + case Opcodes.DSUB: + case Opcodes.DMUL: + case Opcodes.DDIV: + case Opcodes.DREM: + pop(4); + push(DOUBLE); + push(TOP); + break; + case Opcodes.LSHL: + case Opcodes.LSHR: + case Opcodes.LUSHR: + pop(3); + push(LONG); + push(TOP); + break; + case Opcodes.IINC: + set(arg, INTEGER); + break; + case Opcodes.I2L: + case Opcodes.F2L: + pop(1); + push(LONG); + push(TOP); + break; + case Opcodes.I2F: + pop(1); + push(FLOAT); + break; + case Opcodes.I2D: + case Opcodes.F2D: + pop(1); + push(DOUBLE); + push(TOP); + break; + case Opcodes.F2I: + case Opcodes.ARRAYLENGTH: + case Opcodes.INSTANCEOF: + pop(1); + push(INTEGER); + break; + case Opcodes.LCMP: + case Opcodes.DCMPL: + case Opcodes.DCMPG: + pop(4); + push(INTEGER); + break; + case Opcodes.JSR: + case Opcodes.RET: + throw new RuntimeException("JSR/RET are not supported with computeFrames option"); + case Opcodes.GETSTATIC: + push(cw, item.strVal3); + break; + case Opcodes.PUTSTATIC: + pop(item.strVal3); + break; + case Opcodes.GETFIELD: + pop(1); + push(cw, item.strVal3); + break; + case Opcodes.PUTFIELD: + pop(item.strVal3); + pop(); + break; + case Opcodes.INVOKEVIRTUAL: + case Opcodes.INVOKESPECIAL: + case Opcodes.INVOKESTATIC: + case Opcodes.INVOKEINTERFACE: + pop(item.strVal3); + if (opcode != Opcodes.INVOKESTATIC) { + t1 = pop(); + if (opcode == Opcodes.INVOKESPECIAL + && item.strVal2.charAt(0) == '<') + { + init(t1); + } + } + push(cw, item.strVal3); + break; + case Opcodes.INVOKEDYNAMIC: + pop(item.strVal2); + push(cw, item.strVal2); + break; + case Opcodes.NEW: + push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg)); + break; + case Opcodes.NEWARRAY: + pop(); + switch (arg) { + case Opcodes.T_BOOLEAN: + push(ARRAY_OF | BOOLEAN); + break; + case Opcodes.T_CHAR: + push(ARRAY_OF | CHAR); + break; + case Opcodes.T_BYTE: + push(ARRAY_OF | BYTE); + break; + case Opcodes.T_SHORT: + push(ARRAY_OF | SHORT); + break; + case Opcodes.T_INT: + push(ARRAY_OF | INTEGER); + break; + case Opcodes.T_FLOAT: + push(ARRAY_OF | FLOAT); + break; + case Opcodes.T_DOUBLE: + push(ARRAY_OF | DOUBLE); + break; + // case Opcodes.T_LONG: + default: + push(ARRAY_OF | LONG); + break; + } + break; + case Opcodes.ANEWARRAY: + String s = item.strVal1; + pop(); + if (s.charAt(0) == '[') { + push(cw, '[' + s); + } else { + push(ARRAY_OF | OBJECT | cw.addType(s)); + } + break; + case Opcodes.CHECKCAST: + s = item.strVal1; + pop(); + if (s.charAt(0) == '[') { + push(cw, s); + } else { + push(OBJECT | cw.addType(s)); + } + break; + // case Opcodes.MULTIANEWARRAY: + default: + pop(arg); + push(cw, item.strVal1); + break; + } + } + + /** + * Merges the input frame of the given basic block with the input and output + * frames of this basic block. Returns true if the input frame of + * the given label has been changed by this operation. + * + * @param cw the ClassWriter to which this label belongs. + * @param frame the basic block whose input frame must be updated. + * @param edge the kind of the {@link Edge} between this label and 'label'. + * See {@link Edge#info}. + * @return true if the input frame of the given label has been + * changed by this operation. + */ + boolean merge(final ClassWriter cw, final Frame frame, final int edge) { + boolean changed = false; + int i, s, dim, kind, t; + + int nLocal = inputLocals.length; + int nStack = inputStack.length; + if (frame.inputLocals == null) { + frame.inputLocals = new int[nLocal]; + changed = true; + } + + for (i = 0; i < nLocal; ++i) { + if (outputLocals != null && i < outputLocals.length) { + s = outputLocals[i]; + if (s == 0) { + t = inputLocals[i]; + } else { + dim = s & DIM; + kind = s & KIND; + if (kind == BASE) { + t = s; + } else { + if (kind == LOCAL) { + t = dim + inputLocals[s & VALUE]; + } else { + t = dim + inputStack[nStack - (s & VALUE)]; + } + if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (t == LONG || t == DOUBLE)) { + t = TOP; + } + } + } + } else { + t = inputLocals[i]; + } + if (initializations != null) { + t = init(cw, t); + } + changed |= merge(cw, t, frame.inputLocals, i); + } + + if (edge > 0) { + for (i = 0; i < nLocal; ++i) { + t = inputLocals[i]; + changed |= merge(cw, t, frame.inputLocals, i); + } + if (frame.inputStack == null) { + frame.inputStack = new int[1]; + changed = true; + } + changed |= merge(cw, edge, frame.inputStack, 0); + return changed; + } + + int nInputStack = inputStack.length + owner.inputStackTop; + if (frame.inputStack == null) { + frame.inputStack = new int[nInputStack + outputStackTop]; + changed = true; + } + + for (i = 0; i < nInputStack; ++i) { + t = inputStack[i]; + if (initializations != null) { + t = init(cw, t); + } + changed |= merge(cw, t, frame.inputStack, i); + } + for (i = 0; i < outputStackTop; ++i) { + s = outputStack[i]; + dim = s & DIM; + kind = s & KIND; + if (kind == BASE) { + t = s; + } else { + if (kind == LOCAL) { + t = dim + inputLocals[s & VALUE]; + } else { + t = dim + inputStack[nStack - (s & VALUE)]; + } + if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (t == LONG || t == DOUBLE)) { + t = TOP; + } + } + if (initializations != null) { + t = init(cw, t); + } + changed |= merge(cw, t, frame.inputStack, nInputStack + i); + } + return changed; + } + + /** + * Merges the type at the given index in the given type array with the given + * type. Returns true if the type array has been modified by this + * operation. + * + * @param cw the ClassWriter to which this label belongs. + * @param t the type with which the type array element must be merged. + * @param types an array of types. + * @param index the index of the type that must be merged in 'types'. + * @return true if the type array has been modified by this + * operation. + */ + private static boolean merge( + final ClassWriter cw, + int t, + final int[] types, + final int index) + { + int u = types[index]; + if (u == t) { + // if the types are equal, merge(u,t)=u, so there is no change + return false; + } + if ((t & ~DIM) == NULL) { + if (u == NULL) { + return false; + } + t = NULL; + } + if (u == 0) { + // if types[index] has never been assigned, merge(u,t)=t + types[index] = t; + return true; + } + int v; + if ((u & BASE_KIND) == OBJECT || (u & DIM) != 0) { + // if u is a reference type of any dimension + if (t == NULL) { + // if t is the NULL type, merge(u,t)=u, so there is no change + return false; + } else if ((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND))) { + if ((u & BASE_KIND) == OBJECT) { + // if t is also a reference type, and if u and t have the + // same dimension merge(u,t) = dim(t) | common parent of the + // element types of u and t + v = (t & DIM) | OBJECT + | cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE); + } else { + // if u and t are array types, but not with the same element + // type, merge(u,t)=java/lang/Object + v = OBJECT | cw.addType("java/lang/Object"); + } + } else if ((t & BASE_KIND) == OBJECT || (t & DIM) != 0) { + // if t is any other reference or array type, + // merge(u,t)=java/lang/Object + v = OBJECT | cw.addType("java/lang/Object"); + } else { + // if t is any other type, merge(u,t)=TOP + v = TOP; + } + } else if (u == NULL) { + // if u is the NULL type, merge(u,t)=t, + // or TOP if t is not a reference type + v = (t & BASE_KIND) == OBJECT || (t & DIM) != 0 ? t : TOP; + } else { + // if u is any other type, merge(u,t)=TOP whatever t + v = TOP; + } + if (u != v) { + types[index] = v; + return true; + } + return false; + } +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Handle.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Handle.java new file mode 100644 index 00000000000..a70e3859b80 --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Handle.java @@ -0,0 +1,188 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ + +package jdk.internal.org.objectweb.asm; + +/** + * A reference to a field or a method. + * + * @author Remi Forax + * @author Eric Bruneton + */ +public final class Handle { + + /** + * The kind of field or method designated by this Handle. Should be + * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, + * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, + * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + */ + final int tag; + + /** + * The internal name of the field or method designed by this handle. + */ + final String owner; + + /** + * The name of the field or method designated by this handle. + */ + final String name; + + /** + * The descriptor of the field or method designated by this handle. + */ + final String desc; + + /** + * Constructs a new field or method handle. + * + * @param tag the kind of field or method designated by this Handle. Must be + * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, + * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, + * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner the internal name of the field or method designed by this + * handle. + * @param name the name of the field or method designated by this handle. + * @param desc the descriptor of the field or method designated by this + * handle. + */ + public Handle(int tag, String owner, String name, String desc) { + this.tag = tag; + this.owner = owner; + this.name = name; + this.desc = desc; + } + + /** + * Returns the kind of field or method designated by this handle. + * + * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, + * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, + * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + */ + public int getTag() { + return tag; + } + + /** + * Returns the internal name of the field or method designed by this + * handle. + * + * @return the internal name of the field or method designed by this + * handle. + */ + public String getOwner() { + return owner; + } + + /** + * Returns the name of the field or method designated by this handle. + * + * @return the name of the field or method designated by this handle. + */ + public String getName() { + return name; + } + + /** + * Returns the descriptor of the field or method designated by this handle. + * + * @return the descriptor of the field or method designated by this handle. + */ + public String getDesc() { + return desc; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof Handle)) { + return false; + } + Handle h = (Handle) obj; + return tag == h.tag && owner.equals(h.owner) + && name.equals(h.name) && desc.equals(h.desc); + } + + @Override + public int hashCode() { + return tag + owner.hashCode() * name.hashCode() * desc.hashCode(); + } + + /** + * Returns the textual representation of this handle. The textual + * representation is:
    owner '.' name desc ' ' '(' tag ')'
    . As + * this format is unambiguous, it can be parsed if necessary. + */ + @Override + public String toString() { + return owner + '.' + name + desc + " (" + tag + ')'; + } +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Handler.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Handler.java new file mode 100644 index 00000000000..72211a3a93f --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Handler.java @@ -0,0 +1,147 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +/** + * Information about an exception handler block. + * + * @author Eric Bruneton + */ +class Handler { + + /** + * Beginning of the exception handler's scope (inclusive). + */ + Label start; + + /** + * End of the exception handler's scope (exclusive). + */ + Label end; + + /** + * Beginning of the exception handler's code. + */ + Label handler; + + /** + * Internal name of the type of exceptions handled by this handler, or + * null to catch any exceptions. + */ + String desc; + + /** + * Constant pool index of the internal name of the type of exceptions + * handled by this handler, or 0 to catch any exceptions. + */ + int type; + + /** + * Next exception handler block info. + */ + Handler next; + + /** + * Removes the range between start and end from the given exception + * handlers. + * + * @param h an exception handler list. + * @param start the start of the range to be removed. + * @param end the end of the range to be removed. Maybe null. + * @return the exception handler list with the start-end range removed. + */ + static Handler remove(Handler h, Label start, Label end) { + if (h == null) { + return null; + } else { + h.next = remove(h.next, start, end); + } + int hstart = h.start.position; + int hend = h.end.position; + int s = start.position; + int e = end == null ? Integer.MAX_VALUE : end.position; + // if [hstart,hend[ and [s,e[ intervals intersect... + if (s < hend && e > hstart) { + if (s <= hstart) { + if (e >= hend) { + // [hstart,hend[ fully included in [s,e[, h removed + h = h.next; + } else { + // [hstart,hend[ minus [s,e[ = [e,hend[ + h.start = end; + } + } else if (e >= hend) { + // [hstart,hend[ minus [s,e[ = [hstart,s[ + h.end = start; + } else { + // [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[ + Handler g = new Handler(); + g.start = end; + g.end = h.end; + g.handler = h.handler; + g.desc = h.desc; + g.type = h.type; + g.next = h.next; + h.end = start; + h.next = g; + } + } + return h; + } +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Item.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Item.java new file mode 100644 index 00000000000..97b56f766c6 --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Item.java @@ -0,0 +1,326 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +/** + * A constant pool item. Constant pool items can be created with the 'newXXX' + * methods in the {@link ClassWriter} class. + * + * @author Eric Bruneton + */ +final class Item { + + /** + * Index of this item in the constant pool. + */ + int index; + + /** + * Type of this constant pool item. A single class is used to represent all + * constant pool item types, in order to minimize the bytecode size of this + * package. The value of this field is one of {@link ClassWriter#INT}, + * {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT}, + * {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8}, + * {@link ClassWriter#STR}, {@link ClassWriter#CLASS}, + * {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD}, + * {@link ClassWriter#METH}, {@link ClassWriter#IMETH}, + * {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}. + * + * MethodHandle constant 9 variations are stored using a range + * of 9 values from {@link ClassWriter#HANDLE_BASE} + 1 to + * {@link ClassWriter#HANDLE_BASE} + 9. + * + * Special Item types are used for Items that are stored in the ClassWriter + * {@link ClassWriter#typeTable}, instead of the constant pool, in order to + * avoid clashes with normal constant pool items in the ClassWriter constant + * pool's hash table. These special item types are + * {@link ClassWriter#TYPE_NORMAL}, {@link ClassWriter#TYPE_UNINIT} and + * {@link ClassWriter#TYPE_MERGED}. + */ + int type; + + /** + * Value of this item, for an integer item. + */ + int intVal; + + /** + * Value of this item, for a long item. + */ + long longVal; + + /** + * First part of the value of this item, for items that do not hold a + * primitive value. + */ + String strVal1; + + /** + * Second part of the value of this item, for items that do not hold a + * primitive value. + */ + String strVal2; + + /** + * Third part of the value of this item, for items that do not hold a + * primitive value. + */ + String strVal3; + + /** + * The hash code value of this constant pool item. + */ + int hashCode; + + /** + * Link to another constant pool item, used for collision lists in the + * constant pool's hash table. + */ + Item next; + + /** + * Constructs an uninitialized {@link Item}. + */ + Item() { + } + + /** + * Constructs an uninitialized {@link Item} for constant pool element at + * given position. + * + * @param index index of the item to be constructed. + */ + Item(final int index) { + this.index = index; + } + + /** + * Constructs a copy of the given item. + * + * @param index index of the item to be constructed. + * @param i the item that must be copied into the item to be constructed. + */ + Item(final int index, final Item i) { + this.index = index; + type = i.type; + intVal = i.intVal; + longVal = i.longVal; + strVal1 = i.strVal1; + strVal2 = i.strVal2; + strVal3 = i.strVal3; + hashCode = i.hashCode; + } + + /** + * Sets this item to an integer item. + * + * @param intVal the value of this item. + */ + void set(final int intVal) { + this.type = ClassWriter.INT; + this.intVal = intVal; + this.hashCode = 0x7FFFFFFF & (type + intVal); + } + + /** + * Sets this item to a long item. + * + * @param longVal the value of this item. + */ + void set(final long longVal) { + this.type = ClassWriter.LONG; + this.longVal = longVal; + this.hashCode = 0x7FFFFFFF & (type + (int) longVal); + } + + /** + * Sets this item to a float item. + * + * @param floatVal the value of this item. + */ + void set(final float floatVal) { + this.type = ClassWriter.FLOAT; + this.intVal = Float.floatToRawIntBits(floatVal); + this.hashCode = 0x7FFFFFFF & (type + (int) floatVal); + } + + /** + * Sets this item to a double item. + * + * @param doubleVal the value of this item. + */ + void set(final double doubleVal) { + this.type = ClassWriter.DOUBLE; + this.longVal = Double.doubleToRawLongBits(doubleVal); + this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal); + } + + /** + * Sets this item to an item that do not hold a primitive value. + * + * @param type the type of this item. + * @param strVal1 first part of the value of this item. + * @param strVal2 second part of the value of this item. + * @param strVal3 third part of the value of this item. + */ + void set( + final int type, + final String strVal1, + final String strVal2, + final String strVal3) + { + this.type = type; + this.strVal1 = strVal1; + this.strVal2 = strVal2; + this.strVal3 = strVal3; + switch (type) { + case ClassWriter.UTF8: + case ClassWriter.STR: + case ClassWriter.CLASS: + case ClassWriter.MTYPE: + case ClassWriter.TYPE_NORMAL: + hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()); + return; + case ClassWriter.NAME_TYPE: + hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() + * strVal2.hashCode()); + return; + // ClassWriter.FIELD: + // ClassWriter.METH: + // ClassWriter.IMETH: + // ClassWriter.HANDLE_BASE + 1..9 + default: + hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() + * strVal2.hashCode() * strVal3.hashCode()); + } + } + + /** + * Sets the item to an InvokeDynamic item. + * + * @param name invokedynamic's name. + * @param desc invokedynamic's desc. + * @param bsmIndex zero based index into the class attribute BootrapMethods. + */ + void set(String name, String desc, int bsmIndex) { + this.type = ClassWriter.INDY; + this.longVal = bsmIndex; + this.strVal1 = name; + this.strVal2 = desc; + this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex + * strVal1.hashCode() * strVal2.hashCode()); + } + + /** + * Sets the item to a BootstrapMethod item. + * + * @param position position in byte in the class attribute BootrapMethods. + * @param hashCode hashcode of the item. This hashcode is processed from + * the hashcode of the bootstrap method and the hashcode of + * all bootstrap arguments. + */ + void set(int position, int hashCode) { + this.type = ClassWriter.BSM; + this.intVal = position; + this.hashCode = hashCode; + } + + /** + * Indicates if the given item is equal to this one. This method assumes + * that the two items have the same {@link #type}. + * + * @param i the item to be compared to this one. Both items must have the + * same {@link #type}. + * @return true if the given item if equal to this one, + * false otherwise. + */ + boolean isEqualTo(final Item i) { + switch (type) { + case ClassWriter.UTF8: + case ClassWriter.STR: + case ClassWriter.CLASS: + case ClassWriter.MTYPE: + case ClassWriter.TYPE_NORMAL: + return i.strVal1.equals(strVal1); + case ClassWriter.TYPE_MERGED: + case ClassWriter.LONG: + case ClassWriter.DOUBLE: + return i.longVal == longVal; + case ClassWriter.INT: + case ClassWriter.FLOAT: + return i.intVal == intVal; + case ClassWriter.TYPE_UNINIT: + return i.intVal == intVal && i.strVal1.equals(strVal1); + case ClassWriter.NAME_TYPE: + return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2); + case ClassWriter.INDY: + return i.longVal == longVal && i.strVal1.equals(strVal1) + && i.strVal2.equals(strVal2); + + // case ClassWriter.FIELD: + // case ClassWriter.METH: + // case ClassWriter.IMETH: + // case ClassWriter.HANDLE_BASE + 1..9 + default: + return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2) + && i.strVal3.equals(strVal3); + } + } + +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Label.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Label.java new file mode 100644 index 00000000000..220a6e38bd3 --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Label.java @@ -0,0 +1,584 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +/** + * A label represents a position in the bytecode of a method. Labels are used + * for jump, goto, and switch instructions, and for try catch blocks. A label + * designates the instruction that is just after. Note however that + * there can be other elements between a label and the instruction it + * designates (such as other labels, stack map frames, line numbers, etc.). + * + * @author Eric Bruneton + */ +public class Label { + + /** + * Indicates if this label is only used for debug attributes. Such a label + * is not the start of a basic block, the target of a jump instruction, or + * an exception handler. It can be safely ignored in control flow graph + * analysis algorithms (for optimization purposes). + */ + static final int DEBUG = 1; + + /** + * Indicates if the position of this label is known. + */ + static final int RESOLVED = 2; + + /** + * Indicates if this label has been updated, after instruction resizing. + */ + static final int RESIZED = 4; + + /** + * Indicates if this basic block has been pushed in the basic block stack. + * See {@link MethodWriter#visitMaxs visitMaxs}. + */ + static final int PUSHED = 8; + + /** + * Indicates if this label is the target of a jump instruction, or the start + * of an exception handler. + */ + static final int TARGET = 16; + + /** + * Indicates if a stack map frame must be stored for this label. + */ + static final int STORE = 32; + + /** + * Indicates if this label corresponds to a reachable basic block. + */ + static final int REACHABLE = 64; + + /** + * Indicates if this basic block ends with a JSR instruction. + */ + static final int JSR = 128; + + /** + * Indicates if this basic block ends with a RET instruction. + */ + static final int RET = 256; + + /** + * Indicates if this basic block is the start of a subroutine. + */ + static final int SUBROUTINE = 512; + + /** + * Indicates if this subroutine basic block has been visited by a + * visitSubroutine(null, ...) call. + */ + static final int VISITED = 1024; + + /** + * Indicates if this subroutine basic block has been visited by a + * visitSubroutine(!null, ...) call. + */ + static final int VISITED2 = 2048; + + /** + * Field used to associate user information to a label. Warning: this field + * is used by the ASM tree package. In order to use it with the ASM tree + * package you must override the {@link + * jdk.internal.org.objectweb.asm.tree.MethodNode#getLabelNode} method. + */ + public Object info; + + /** + * Flags that indicate the status of this label. + * + * @see #DEBUG + * @see #RESOLVED + * @see #RESIZED + * @see #PUSHED + * @see #TARGET + * @see #STORE + * @see #REACHABLE + * @see #JSR + * @see #RET + */ + int status; + + /** + * The line number corresponding to this label, if known. + */ + int line; + + /** + * The position of this label in the code, if known. + */ + int position; + + /** + * Number of forward references to this label, times two. + */ + private int referenceCount; + + /** + * Informations about forward references. Each forward reference is + * described by two consecutive integers in this array: the first one is the + * position of the first byte of the bytecode instruction that contains the + * forward reference, while the second is the position of the first byte of + * the forward reference itself. In fact the sign of the first integer + * indicates if this reference uses 2 or 4 bytes, and its absolute value + * gives the position of the bytecode instruction. This array is also used + * as a bitset to store the subroutines to which a basic block belongs. This + * information is needed in {@linked MethodWriter#visitMaxs}, after all + * forward references have been resolved. Hence the same array can be used + * for both purposes without problems. + */ + private int[] srcAndRefPositions; + + // ------------------------------------------------------------------------ + + /* + * Fields for the control flow and data flow graph analysis algorithms (used + * to compute the maximum stack size or the stack map frames). A control + * flow graph contains one node per "basic block", and one edge per "jump" + * from one basic block to another. Each node (i.e., each basic block) is + * represented by the Label object that corresponds to the first instruction + * of this basic block. Each node also stores the list of its successors in + * the graph, as a linked list of Edge objects. + * + * The control flow analysis algorithms used to compute the maximum stack + * size or the stack map frames are similar and use two steps. The first + * step, during the visit of each instruction, builds information about the + * state of the local variables and the operand stack at the end of each + * basic block, called the "output frame", relatively to the frame + * state at the beginning of the basic block, which is called the "input + * frame", and which is unknown during this step. The second step, + * in {@link MethodWriter#visitMaxs}, is a fix point algorithm that + * computes information about the input frame of each basic block, from the + * input state of the first basic block (known from the method signature), + * and by the using the previously computed relative output frames. + * + * The algorithm used to compute the maximum stack size only computes the + * relative output and absolute input stack heights, while the algorithm + * used to compute stack map frames computes relative output frames and + * absolute input frames. + */ + + /** + * Start of the output stack relatively to the input stack. The exact + * semantics of this field depends on the algorithm that is used. + * + * When only the maximum stack size is computed, this field is the number of + * elements in the input stack. + * + * When the stack map frames are completely computed, this field is the + * offset of the first output stack element relatively to the top of the + * input stack. This offset is always negative or null. A null offset means + * that the output stack must be appended to the input stack. A -n offset + * means that the first n output stack elements must replace the top n input + * stack elements, and that the other elements must be appended to the input + * stack. + */ + int inputStackTop; + + /** + * Maximum height reached by the output stack, relatively to the top of the + * input stack. This maximum is always positive or null. + */ + int outputStackMax; + + /** + * Information about the input and output stack map frames of this basic + * block. This field is only used when {@link ClassWriter#COMPUTE_FRAMES} + * option is used. + */ + Frame frame; + + /** + * The successor of this label, in the order they are visited. This linked + * list does not include labels used for debug info only. If + * {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it + * does not contain successive labels that denote the same bytecode position + * (in this case only the first label appears in this list). + */ + Label successor; + + /** + * The successors of this node in the control flow graph. These successors + * are stored in a linked list of {@link Edge Edge} objects, linked to each + * other by their {@link Edge#next} field. + */ + Edge successors; + + /** + * The next basic block in the basic block stack. This stack is used in the + * main loop of the fix point algorithm used in the second step of the + * control flow analysis algorithms. It is also used in + * {@link #visitSubroutine} to avoid using a recursive method. + * + * @see MethodWriter#visitMaxs + */ + Label next; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructs a new label. + */ + public Label() { + } + + // ------------------------------------------------------------------------ + // Methods to compute offsets and to manage forward references + // ------------------------------------------------------------------------ + + /** + * Returns the offset corresponding to this label. This offset is computed + * from the start of the method's bytecode. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class + * generators or adapters. + * + * @return the offset corresponding to this label. + * @throws IllegalStateException if this label is not resolved yet. + */ + public int getOffset() { + if ((status & RESOLVED) == 0) { + throw new IllegalStateException("Label offset position has not been resolved yet"); + } + return position; + } + + /** + * Puts a reference to this label in the bytecode of a method. If the + * position of the label is known, the offset is computed and written + * directly. Otherwise, a null offset is written and a new forward reference + * is declared for this label. + * + * @param owner the code writer that calls this method. + * @param out the bytecode of the method. + * @param source the position of first byte of the bytecode instruction that + * contains this label. + * @param wideOffset true if the reference must be stored in 4 + * bytes, or false if it must be stored with 2 bytes. + * @throws IllegalArgumentException if this label has not been created by + * the given code writer. + */ + void put( + final MethodWriter owner, + final ByteVector out, + final int source, + final boolean wideOffset) + { + if ((status & RESOLVED) == 0) { + if (wideOffset) { + addReference(-1 - source, out.length); + out.putInt(-1); + } else { + addReference(source, out.length); + out.putShort(-1); + } + } else { + if (wideOffset) { + out.putInt(position - source); + } else { + out.putShort(position - source); + } + } + } + + /** + * Adds a forward reference to this label. This method must be called only + * for a true forward reference, i.e. only if this label is not resolved + * yet. For backward references, the offset of the reference can be, and + * must be, computed and stored directly. + * + * @param sourcePosition the position of the referencing instruction. This + * position will be used to compute the offset of this forward + * reference. + * @param referencePosition the position where the offset for this forward + * reference must be stored. + */ + private void addReference( + final int sourcePosition, + final int referencePosition) + { + if (srcAndRefPositions == null) { + srcAndRefPositions = new int[6]; + } + if (referenceCount >= srcAndRefPositions.length) { + int[] a = new int[srcAndRefPositions.length + 6]; + System.arraycopy(srcAndRefPositions, + 0, + a, + 0, + srcAndRefPositions.length); + srcAndRefPositions = a; + } + srcAndRefPositions[referenceCount++] = sourcePosition; + srcAndRefPositions[referenceCount++] = referencePosition; + } + + /** + * Resolves all forward references to this label. This method must be called + * when this label is added to the bytecode of the method, i.e. when its + * position becomes known. This method fills in the blanks that where left + * in the bytecode by each forward reference previously added to this label. + * + * @param owner the code writer that calls this method. + * @param position the position of this label in the bytecode. + * @param data the bytecode of the method. + * @return true if a blank that was left for this label was to + * small to store the offset. In such a case the corresponding jump + * instruction is replaced with a pseudo instruction (using unused + * opcodes) using an unsigned two bytes offset. These pseudo + * instructions will need to be replaced with true instructions with + * wider offsets (4 bytes instead of 2). This is done in + * {@link MethodWriter#resizeInstructions}. + * @throws IllegalArgumentException if this label has already been resolved, + * or if it has not been created by the given code writer. + */ + boolean resolve( + final MethodWriter owner, + final int position, + final byte[] data) + { + boolean needUpdate = false; + this.status |= RESOLVED; + this.position = position; + int i = 0; + while (i < referenceCount) { + int source = srcAndRefPositions[i++]; + int reference = srcAndRefPositions[i++]; + int offset; + if (source >= 0) { + offset = position - source; + if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) { + /* + * changes the opcode of the jump instruction, in order to + * be able to find it later (see resizeInstructions in + * MethodWriter). These temporary opcodes are similar to + * jump instruction opcodes, except that the 2 bytes offset + * is unsigned (and can therefore represent values from 0 to + * 65535, which is sufficient since the size of a method is + * limited to 65535 bytes). + */ + int opcode = data[reference - 1] & 0xFF; + if (opcode <= Opcodes.JSR) { + // changes IFEQ ... JSR to opcodes 202 to 217 + data[reference - 1] = (byte) (opcode + 49); + } else { + // changes IFNULL and IFNONNULL to opcodes 218 and 219 + data[reference - 1] = (byte) (opcode + 20); + } + needUpdate = true; + } + data[reference++] = (byte) (offset >>> 8); + data[reference] = (byte) offset; + } else { + offset = position + source + 1; + data[reference++] = (byte) (offset >>> 24); + data[reference++] = (byte) (offset >>> 16); + data[reference++] = (byte) (offset >>> 8); + data[reference] = (byte) offset; + } + } + return needUpdate; + } + + /** + * Returns the first label of the series to which this label belongs. For an + * isolated label or for the first label in a series of successive labels, + * this method returns the label itself. For other labels it returns the + * first label of the series. + * + * @return the first label of the series to which this label belongs. + */ + Label getFirst() { + return !ClassReader.FRAMES || frame == null ? this : frame.owner; + } + + // ------------------------------------------------------------------------ + // Methods related to subroutines + // ------------------------------------------------------------------------ + + /** + * Returns true is this basic block belongs to the given subroutine. + * + * @param id a subroutine id. + * @return true is this basic block belongs to the given subroutine. + */ + boolean inSubroutine(final long id) { + if ((status & Label.VISITED) != 0) { + return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0; + } + return false; + } + + /** + * Returns true if this basic block and the given one belong to a common + * subroutine. + * + * @param block another basic block. + * @return true if this basic block and the given one belong to a common + * subroutine. + */ + boolean inSameSubroutine(final Label block) { + if ((status & VISITED) == 0 || (block.status & VISITED) == 0) { + return false; + } + for (int i = 0; i < srcAndRefPositions.length; ++i) { + if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) { + return true; + } + } + return false; + } + + /** + * Marks this basic block as belonging to the given subroutine. + * + * @param id a subroutine id. + * @param nbSubroutines the total number of subroutines in the method. + */ + void addToSubroutine(final long id, final int nbSubroutines) { + if ((status & VISITED) == 0) { + status |= VISITED; + srcAndRefPositions = new int[(nbSubroutines - 1) / 32 + 1]; + } + srcAndRefPositions[(int) (id >>> 32)] |= (int) id; + } + + /** + * Finds the basic blocks that belong to a given subroutine, and marks these + * blocks as belonging to this subroutine. This method follows the control + * flow graph to find all the blocks that are reachable from the current + * block WITHOUT following any JSR target. + * + * @param JSR a JSR block that jumps to this subroutine. If this JSR is not + * null it is added to the successor of the RET blocks found in the + * subroutine. + * @param id the id of this subroutine. + * @param nbSubroutines the total number of subroutines in the method. + */ + void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) + { + // user managed stack of labels, to avoid using a recursive method + // (recursivity can lead to stack overflow with very large methods) + Label stack = this; + while (stack != null) { + // removes a label l from the stack + Label l = stack; + stack = l.next; + l.next = null; + + if (JSR != null) { + if ((l.status & VISITED2) != 0) { + continue; + } + l.status |= VISITED2; + // adds JSR to the successors of l, if it is a RET block + if ((l.status & RET) != 0) { + if (!l.inSameSubroutine(JSR)) { + Edge e = new Edge(); + e.info = l.inputStackTop; + e.successor = JSR.successors.successor; + e.next = l.successors; + l.successors = e; + } + } + } else { + // if the l block already belongs to subroutine 'id', continue + if (l.inSubroutine(id)) { + continue; + } + // marks the l block as belonging to subroutine 'id' + l.addToSubroutine(id, nbSubroutines); + } + // pushes each successor of l on the stack, except JSR targets + Edge e = l.successors; + while (e != null) { + // if the l block is a JSR block, then 'l.successors.next' leads + // to the JSR target (see {@link #visitJumpInsn}) and must + // therefore not be followed + if ((l.status & Label.JSR) == 0 || e != l.successors.next) { + // pushes e.successor on the stack if it not already added + if (e.successor.next == null) { + e.successor.next = stack; + stack = e.successor; + } + } + e = e.next; + } + } + } + + // ------------------------------------------------------------------------ + // Overriden Object methods + // ------------------------------------------------------------------------ + + /** + * Returns a string representation of this label. + * + * @return a string representation of this label. + */ + @Override + public String toString() { + return "L" + System.identityHashCode(this); + } +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java new file mode 100644 index 00000000000..241f4fb89f9 --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java @@ -0,0 +1,617 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +/** + * A visitor to visit a Java method. The methods of this class must be + * called in the following order: [ visitAnnotationDefault ] ( + * visitAnnotation | visitParameterAnnotation | + * visitAttribute )* [ visitCode ( visitFrame | + * visitXInsn
    | visitLabel | visitTryCatchBlock | + * visitLocalVariable | visitLineNumber )* visitMaxs ] + * visitEnd. In addition, the visitXInsn
    + * and visitLabel methods must be called in the sequential order of + * the bytecode instructions of the visited code, visitTryCatchBlock + * must be called before the labels passed as arguments have been + * visited, and the visitLocalVariable and visitLineNumber + * methods must be called after the labels passed as arguments have been + * visited. + * + * @author Eric Bruneton + */ +public abstract class MethodVisitor { + + /** + * The ASM API version implemented by this visitor. The value of this field + * must be one of {@link Opcodes#ASM4}. + */ + protected final int api; + + /** + * The method visitor to which this visitor must delegate method calls. May + * be null. + */ + protected MethodVisitor mv; + + /** + * Constructs a new {@link MethodVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + */ + public MethodVisitor(final int api) { + this(api, null); + } + + /** + * Constructs a new {@link MethodVisitor}. + * + * @param api the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param mv the method visitor to which this visitor must delegate method + * calls. May be null. + */ + public MethodVisitor(final int api, final MethodVisitor mv) { + /*if (api != Opcodes.ASM4) { + throw new IllegalArgumentException(); + }*/ + this.api = api; + this.mv = mv; + } + + // ------------------------------------------------------------------------- + // Annotations and non standard attributes + // ------------------------------------------------------------------------- + + /** + * Visits the default value of this annotation interface method. + * + * @return a visitor to the visit the actual default value of this + * annotation interface method, or null if this visitor + * is not interested in visiting this default value. The 'name' + * parameters passed to the methods of this annotation visitor are + * ignored. Moreover, exacly one visit method must be called on this + * annotation visitor, followed by visitEnd. + */ + public AnnotationVisitor visitAnnotationDefault() { + if (mv != null) { + return mv.visitAnnotationDefault(); + } + return null; + } + + /** + * Visits an annotation of this method. + * + * @param desc the class descriptor of the annotation class. + * @param visible true if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or null if + * this visitor is not interested in visiting this annotation. + */ + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + if (mv != null) { + return mv.visitAnnotation(desc, visible); + } + return null; + } + + /** + * Visits an annotation of a parameter this method. + * + * @param parameter the parameter index. + * @param desc the class descriptor of the annotation class. + * @param visible true if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or null if + * this visitor is not interested in visiting this annotation. + */ + public AnnotationVisitor visitParameterAnnotation( + int parameter, + String desc, + boolean visible) + { + if (mv != null) { + return mv.visitParameterAnnotation(parameter, desc, visible); + } + return null; + } + + /** + * Visits a non standard attribute of this method. + * + * @param attr an attribute. + */ + public void visitAttribute(Attribute attr) { + if (mv != null) { + mv.visitAttribute(attr); + } + } + + /** + * Starts the visit of the method's code, if any (i.e. non abstract method). + */ + public void visitCode() { + if (mv != null) { + mv.visitCode(); + } + } + + /** + * Visits the current state of the local variables and operand stack + * elements. This method must(*) be called just before any + * instruction i that follows an unconditional branch instruction + * such as GOTO or THROW, that is the target of a jump instruction, or that + * starts an exception handler block. The visited types must describe the + * values of the local variables and of the operand stack elements just + * before i is executed.

    (*) this is mandatory only + * for classes whose version is greater than or equal to + * {@link Opcodes#V1_6 V1_6}.

    Packed frames are basically + * "deltas" from the state of the previous frame (very first frame is + * implicitly defined by the method's parameters and access flags):
      + *
    • {@link Opcodes#F_SAME} representing frame with exactly the same + * locals as the previous frame and with the empty stack.
    • {@link Opcodes#F_SAME1} + * representing frame with exactly the same locals as the previous frame and + * with single value on the stack (nStack is 1 and + * stack[0] contains value for the type of the stack item).
    • + *
    • {@link Opcodes#F_APPEND} representing frame with current locals are + * the same as the locals in the previous frame, except that additional + * locals are defined (nLocal is 1, 2 or 3 and + * local elements contains values representing added types).
    • + *
    • {@link Opcodes#F_CHOP} representing frame with current locals are + * the same as the locals in the previous frame, except that the last 1-3 + * locals are absent and with the empty stack (nLocals is 1, + * 2 or 3).
    • {@link Opcodes#F_FULL} representing complete frame + * data.
    + * + * @param type the type of this stack map frame. Must be + * {@link Opcodes#F_NEW} for expanded frames, or + * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, + * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or + * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed + * frames. + * @param nLocal the number of local variables in the visited frame. + * @param local the local variable types in this frame. This array must not + * be modified. Primitive types are represented by + * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, + * {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, + * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or + * {@link Opcodes#UNINITIALIZED_THIS} (long and double are + * represented by a single element). Reference types are represented + * by String objects (representing internal names), and uninitialized + * types by Label objects (this label designates the NEW instruction + * that created this uninitialized value). + * @param nStack the number of operand stack elements in the visited frame. + * @param stack the operand stack types in this frame. This array must not + * be modified. Its content has the same format as the "local" array. + * @throws IllegalStateException if a frame is visited just after another + * one, without any instruction between the two (unless this frame + * is a Opcodes#F_SAME frame, in which case it is silently ignored). + */ + public void visitFrame( + int type, + int nLocal, + Object[] local, + int nStack, + Object[] stack) + { + if (mv != null) { + mv.visitFrame(type, nLocal, local, nStack, stack); + } + } + + // ------------------------------------------------------------------------- + // Normal instructions + // ------------------------------------------------------------------------- + + /** + * Visits a zero operand instruction. + * + * @param opcode the opcode of the instruction to be visited. This opcode is + * either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, + * ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, FCONST_0, + * FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD, FALOAD, + * DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE, + * DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, + * DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP, IADD, LADD, FADD, + * DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, + * FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, + * LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, + * I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, + * I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, + * FRETURN, DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, + * MONITORENTER, or MONITOREXIT. + */ + public void visitInsn(int opcode) { + if (mv != null) { + mv.visitInsn(opcode); + } + } + + /** + * Visits an instruction with a single int operand. + * + * @param opcode the opcode of the instruction to be visited. This opcode is + * either BIPUSH, SIPUSH or NEWARRAY. + * @param operand the operand of the instruction to be visited.
    When + * opcode is BIPUSH, operand value should be between Byte.MIN_VALUE + * and Byte.MAX_VALUE.
    When opcode is SIPUSH, operand value + * should be between Short.MIN_VALUE and Short.MAX_VALUE.
    When + * opcode is NEWARRAY, operand value should be one of + * {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR}, + * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, + * {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT}, + * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}. + */ + public void visitIntInsn(int opcode, int operand) { + if (mv != null) { + mv.visitIntInsn(opcode, operand); + } + } + + /** + * Visits a local variable instruction. A local variable instruction is an + * instruction that loads or stores the value of a local variable. + * + * @param opcode the opcode of the local variable instruction to be visited. + * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, + * LSTORE, FSTORE, DSTORE, ASTORE or RET. + * @param var the operand of the instruction to be visited. This operand is + * the index of a local variable. + */ + public void visitVarInsn(int opcode, int var) { + if (mv != null) { + mv.visitVarInsn(opcode, var); + } + } + + /** + * Visits a type instruction. A type instruction is an instruction that + * takes the internal name of a class as parameter. + * + * @param opcode the opcode of the type instruction to be visited. This + * opcode is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. + * @param type the operand of the instruction to be visited. This operand + * must be the internal name of an object or array class (see {@link + * Type#getInternalName() getInternalName}). + */ + public void visitTypeInsn(int opcode, String type) { + if (mv != null) { + mv.visitTypeInsn(opcode, type); + } + } + + /** + * Visits a field instruction. A field instruction is an instruction that + * loads or stores the value of a field of an object. + * + * @param opcode the opcode of the type instruction to be visited. This + * opcode is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. + * @param owner the internal name of the field's owner class (see {@link + * Type#getInternalName() getInternalName}). + * @param name the field's name. + * @param desc the field's descriptor (see {@link Type Type}). + */ + public void visitFieldInsn(int opcode, String owner, String name, String desc) { + if (mv != null) { + mv.visitFieldInsn(opcode, owner, name, desc); + } + } + + /** + * Visits a method instruction. A method instruction is an instruction that + * invokes a method. + * + * @param opcode the opcode of the type instruction to be visited. This + * opcode is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC + * or INVOKEINTERFACE. + * @param owner the internal name of the method's owner class (see {@link + * Type#getInternalName() getInternalName}). + * @param name the method's name. + * @param desc the method's descriptor (see {@link Type Type}). + */ + public void visitMethodInsn(int opcode, String owner, String name, String desc) { + if (mv != null) { + mv.visitMethodInsn(opcode, owner, name, desc); + } + } + + /** + * Visits an invokedynamic instruction. + * + * @param name the method's name. + * @param desc the method's descriptor (see {@link Type Type}). + * @param bsm the bootstrap method. + * @param bsmArgs the bootstrap method constant arguments. Each argument + * must be an {@link Integer}, {@link Float}, {@link Long}, + * {@link Double}, {@link String}, {@link Type} or {@link Handle} + * value. This method is allowed to modify the content of the array + * so a caller should expect that this array may change. + */ + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { + if (mv != null) { + mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); + } + } + + /** + * Visits a jump instruction. A jump instruction is an instruction that may + * jump to another instruction. + * + * @param opcode the opcode of the type instruction to be visited. This + * opcode is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, + * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, + * IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL. + * @param label the operand of the instruction to be visited. This operand + * is a label that designates the instruction to which the jump + * instruction may jump. + */ + public void visitJumpInsn(int opcode, Label label) { + if (mv != null) { + mv.visitJumpInsn(opcode, label); + } + } + + /** + * Visits a label. A label designates the instruction that will be visited + * just after it. + * + * @param label a {@link Label Label} object. + */ + public void visitLabel(Label label) { + if (mv != null) { + mv.visitLabel(label); + } + } + + // ------------------------------------------------------------------------- + // Special instructions + // ------------------------------------------------------------------------- + + /** + * Visits a LDC instruction. Note that new constant types may be added in + * future versions of the Java Virtual Machine. To easily detect new + * constant types, implementations of this method should check for + * unexpected constant types, like this: + *
    +     * if (cst instanceof Integer) {
    +     *   // ...
    +     * } else if (cst instanceof Float) {
    +     *   // ...
    +     * } else if (cst instanceof Long) {
    +     *   // ...
    +     * } else if (cst instanceof Double) {
    +     *   // ...
    +     * } else if (cst instanceof String) {
    +     *   // ...
    +     * } else if (cst instanceof Type) {
    +     *   int sort = ((Type) cst).getSort();
    +     *   if (sort == Type.OBJECT) {
    +     *     // ...
    +     *   } else if (sort == Type.ARRAY) {
    +     *     // ...
    +     *   } else if (sort == Type.METHOD) {
    +     *     // ...
    +     *   } else {
    +     *     // throw an exception
    +     *   }
    +     * } else if (cst instanceof Handle) {
    +     *   // ...
    +     * } else {
    +     *   // throw an exception
    +     * }
    + * + * @param cst the constant to be loaded on the stack. This parameter must be + * a non null {@link Integer}, a {@link Float}, a {@link Long}, a + * {@link Double}, a {@link String}, a {@link Type} of OBJECT or ARRAY + * sort for .class constants, for classes whose version is + * 49.0, a {@link Type} of METHOD sort or a {@link Handle} for + * MethodType and MethodHandle constants, for classes whose version + * is 51.0. + */ + public void visitLdcInsn(Object cst) { + if (mv != null) { + mv.visitLdcInsn(cst); + } + } + + /** + * Visits an IINC instruction. + * + * @param var index of the local variable to be incremented. + * @param increment amount to increment the local variable by. + */ + public void visitIincInsn(int var, int increment) { + if (mv != null) { + mv.visitIincInsn(var, increment); + } + } + + /** + * Visits a TABLESWITCH instruction. + * + * @param min the minimum key value. + * @param max the maximum key value. + * @param dflt beginning of the default handler block. + * @param labels beginnings of the handler blocks. labels[i] is + * the beginning of the handler block for the min + i key. + */ + public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { + if (mv != null) { + mv.visitTableSwitchInsn(min, max, dflt, labels); + } + } + + /** + * Visits a LOOKUPSWITCH instruction. + * + * @param dflt beginning of the default handler block. + * @param keys the values of the keys. + * @param labels beginnings of the handler blocks. labels[i] is + * the beginning of the handler block for the keys[i] key. + */ + public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { + if (mv != null) { + mv.visitLookupSwitchInsn(dflt, keys, labels); + } + } + + /** + * Visits a MULTIANEWARRAY instruction. + * + * @param desc an array type descriptor (see {@link Type Type}). + * @param dims number of dimensions of the array to allocate. + */ + public void visitMultiANewArrayInsn(String desc, int dims) { + if (mv != null) { + mv.visitMultiANewArrayInsn(desc, dims); + } + } + + // ------------------------------------------------------------------------- + // Exceptions table entries, debug information, max stack and max locals + // ------------------------------------------------------------------------- + + /** + * Visits a try catch block. + * + * @param start beginning of the exception handler's scope (inclusive). + * @param end end of the exception handler's scope (exclusive). + * @param handler beginning of the exception handler's code. + * @param type internal name of the type of exceptions handled by the + * handler, or null to catch any exceptions (for "finally" + * blocks). + * @throws IllegalArgumentException if one of the labels has already been + * visited by this visitor (by the {@link #visitLabel visitLabel} + * method). + */ + public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { + if (mv != null) { + mv.visitTryCatchBlock(start, end, handler, type); + } + } + + /** + * Visits a local variable declaration. + * + * @param name the name of a local variable. + * @param desc the type descriptor of this local variable. + * @param signature the type signature of this local variable. May be + * null if the local variable type does not use generic + * types. + * @param start the first instruction corresponding to the scope of this + * local variable (inclusive). + * @param end the last instruction corresponding to the scope of this local + * variable (exclusive). + * @param index the local variable's index. + * @throws IllegalArgumentException if one of the labels has not already + * been visited by this visitor (by the + * {@link #visitLabel visitLabel} method). + */ + public void visitLocalVariable( + String name, + String desc, + String signature, + Label start, + Label end, + int index) + { + if (mv != null) { + mv.visitLocalVariable(name, desc, signature, start, end, index); + } + } + + /** + * Visits a line number declaration. + * + * @param line a line number. This number refers to the source file from + * which the class was compiled. + * @param start the first instruction corresponding to this line number. + * @throws IllegalArgumentException if start has not already been + * visited by this visitor (by the {@link #visitLabel visitLabel} + * method). + */ + public void visitLineNumber(int line, Label start) { + if (mv != null) { + mv.visitLineNumber(line, start); + } + } + + /** + * Visits the maximum stack size and the maximum number of local variables + * of the method. + * + * @param maxStack maximum stack size of the method. + * @param maxLocals maximum number of local variables for the method. + */ + public void visitMaxs(int maxStack, int maxLocals) { + if (mv != null) { + mv.visitMaxs(maxStack, maxLocals); + } + } + + /** + * Visits the end of the method. This method, which is the last one to be + * called, is used to inform the visitor that all the annotations and + * attributes of the method have been visited. + */ + public void visitEnd() { + if (mv != null) { + mv.visitEnd(); + } + } +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java new file mode 100644 index 00000000000..e43ecb1d072 --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java @@ -0,0 +1,2695 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +/** + * A {@link MethodVisitor} that generates methods in bytecode form. Each visit + * method of this class appends the bytecode corresponding to the visited + * instruction to a byte vector, in the order these methods are called. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +class MethodWriter extends MethodVisitor { + + /** + * Pseudo access flag used to denote constructors. + */ + static final int ACC_CONSTRUCTOR = 262144; + + /** + * Frame has exactly the same locals as the previous stack map frame and + * number of stack items is zero. + */ + static final int SAME_FRAME = 0; // to 63 (0-3f) + + /** + * Frame has exactly the same locals as the previous stack map frame and + * number of stack items is 1 + */ + static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f) + + /** + * Reserved for future use + */ + static final int RESERVED = 128; + + /** + * Frame has exactly the same locals as the previous stack map frame and + * number of stack items is 1. Offset is bigger then 63; + */ + static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7 + + /** + * Frame where current locals are the same as the locals in the previous + * frame, except that the k last locals are absent. The value of k is given + * by the formula 251-frame_type. + */ + static final int CHOP_FRAME = 248; // to 250 (f8-fA) + + /** + * Frame has exactly the same locals as the previous stack map frame and + * number of stack items is zero. Offset is bigger then 63; + */ + static final int SAME_FRAME_EXTENDED = 251; // fb + + /** + * Frame where current locals are the same as the locals in the previous + * frame, except that k additional locals are defined. The value of k is + * given by the formula frame_type-251. + */ + static final int APPEND_FRAME = 252; // to 254 // fc-fe + + /** + * Full frame + */ + static final int FULL_FRAME = 255; // ff + + /** + * Indicates that the stack map frames must be recomputed from scratch. In + * this case the maximum stack size and number of local variables is also + * recomputed from scratch. + * + * @see #compute + */ + private static final int FRAMES = 0; + + /** + * Indicates that the maximum stack size and number of local variables must + * be automatically computed. + * + * @see #compute + */ + private static final int MAXS = 1; + + /** + * Indicates that nothing must be automatically computed. + * + * @see #compute + */ + private static final int NOTHING = 2; + + /** + * The class writer to which this method must be added. + */ + final ClassWriter cw; + + /** + * Access flags of this method. + */ + private int access; + + /** + * The index of the constant pool item that contains the name of this + * method. + */ + private final int name; + + /** + * The index of the constant pool item that contains the descriptor of this + * method. + */ + private final int desc; + + /** + * The descriptor of this method. + */ + private final String descriptor; + + /** + * The signature of this method. + */ + String signature; + + /** + * If not zero, indicates that the code of this method must be copied from + * the ClassReader associated to this writer in cw.cr. More + * precisely, this field gives the index of the first byte to copied from + * cw.cr.b. + */ + int classReaderOffset; + + /** + * If not zero, indicates that the code of this method must be copied from + * the ClassReader associated to this writer in cw.cr. More + * precisely, this field gives the number of bytes to copied from + * cw.cr.b. + */ + int classReaderLength; + + /** + * Number of exceptions that can be thrown by this method. + */ + int exceptionCount; + + /** + * The exceptions that can be thrown by this method. More precisely, this + * array contains the indexes of the constant pool items that contain the + * internal names of these exception classes. + */ + int[] exceptions; + + /** + * The annotation default attribute of this method. May be null. + */ + private ByteVector annd; + + /** + * The runtime visible annotations of this method. May be null. + */ + private AnnotationWriter anns; + + /** + * The runtime invisible annotations of this method. May be null. + */ + private AnnotationWriter ianns; + + /** + * The runtime visible parameter annotations of this method. May be + * null. + */ + private AnnotationWriter[] panns; + + /** + * The runtime invisible parameter annotations of this method. May be + * null. + */ + private AnnotationWriter[] ipanns; + + /** + * The number of synthetic parameters of this method. + */ + private int synthetics; + + /** + * The non standard attributes of the method. + */ + private Attribute attrs; + + /** + * The bytecode of this method. + */ + private ByteVector code = new ByteVector(); + + /** + * Maximum stack size of this method. + */ + private int maxStack; + + /** + * Maximum number of local variables for this method. + */ + private int maxLocals; + + /** + * Number of local variables in the current stack map frame. + */ + private int currentLocals; + + /** + * Number of stack map frames in the StackMapTable attribute. + */ + private int frameCount; + + /** + * The StackMapTable attribute. + */ + private ByteVector stackMap; + + /** + * The offset of the last frame that was written in the StackMapTable + * attribute. + */ + private int previousFrameOffset; + + /** + * The last frame that was written in the StackMapTable attribute. + * + * @see #frame + */ + private int[] previousFrame; + + /** + * Index of the next element to be added in {@link #frame}. + */ + private int frameIndex; + + /** + * The current stack map frame. The first element contains the offset of the + * instruction to which the frame corresponds, the second element is the + * number of locals and the third one is the number of stack elements. The + * local variables start at index 3 and are followed by the operand stack + * values. In summary frame[0] = offset, frame[1] = nLocal, frame[2] = + * nStack, frame[3] = nLocal. All types are encoded as integers, with the + * same format as the one used in {@link Label}, but limited to BASE types. + */ + private int[] frame; + + /** + * Number of elements in the exception handler list. + */ + private int handlerCount; + + /** + * The first element in the exception handler list. + */ + private Handler firstHandler; + + /** + * The last element in the exception handler list. + */ + private Handler lastHandler; + + /** + * Number of entries in the LocalVariableTable attribute. + */ + private int localVarCount; + + /** + * The LocalVariableTable attribute. + */ + private ByteVector localVar; + + /** + * Number of entries in the LocalVariableTypeTable attribute. + */ + private int localVarTypeCount; + + /** + * The LocalVariableTypeTable attribute. + */ + private ByteVector localVarType; + + /** + * Number of entries in the LineNumberTable attribute. + */ + private int lineNumberCount; + + /** + * The LineNumberTable attribute. + */ + private ByteVector lineNumber; + + /** + * The non standard attributes of the method's code. + */ + private Attribute cattrs; + + /** + * Indicates if some jump instructions are too small and need to be resized. + */ + private boolean resize; + + /** + * The number of subroutines in this method. + */ + private int subroutines; + + // ------------------------------------------------------------------------ + + /* + * Fields for the control flow graph analysis algorithm (used to compute the + * maximum stack size). A control flow graph contains one node per "basic + * block", and one edge per "jump" from one basic block to another. Each + * node (i.e., each basic block) is represented by the Label object that + * corresponds to the first instruction of this basic block. Each node also + * stores the list of its successors in the graph, as a linked list of Edge + * objects. + */ + + /** + * Indicates what must be automatically computed. + * + * @see #FRAMES + * @see #MAXS + * @see #NOTHING + */ + private final int compute; + + /** + * A list of labels. This list is the list of basic blocks in the method, + * i.e. a list of Label objects linked to each other by their + * {@link Label#successor} field, in the order they are visited by + * {@link MethodVisitor#visitLabel}, and starting with the first basic block. + */ + private Label labels; + + /** + * The previous basic block. + */ + private Label previousBlock; + + /** + * The current basic block. + */ + private Label currentBlock; + + /** + * The (relative) stack size after the last visited instruction. This size + * is relative to the beginning of the current basic block, i.e., the true + * stack size after the last visited instruction is equal to the + * {@link Label#inputStackTop beginStackSize} of the current basic block + * plus stackSize. + */ + private int stackSize; + + /** + * The (relative) maximum stack size after the last visited instruction. + * This size is relative to the beginning of the current basic block, i.e., + * the true maximum stack size after the last visited instruction is equal + * to the {@link Label#inputStackTop beginStackSize} of the current basic + * block plus stackSize. + */ + private int maxStackSize; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructs a new {@link MethodWriter}. + * + * @param cw the class writer in which the method must be added. + * @param access the method's access flags (see {@link Opcodes}). + * @param name the method's name. + * @param desc the method's descriptor (see {@link Type}). + * @param signature the method's signature. May be null. + * @param exceptions the internal names of the method's exceptions. May be + * null. + * @param computeMaxs true if the maximum stack size and number + * of local variables must be automatically computed. + * @param computeFrames true if the stack map tables must be + * recomputed from scratch. + */ + MethodWriter( + final ClassWriter cw, + final int access, + final String name, + final String desc, + final String signature, + final String[] exceptions, + final boolean computeMaxs, + final boolean computeFrames) + { + super(Opcodes.ASM4); + if (cw.firstMethod == null) { + cw.firstMethod = this; + } else { + cw.lastMethod.mv = this; + } + cw.lastMethod = this; + this.cw = cw; + this.access = access; + this.name = cw.newUTF8(name); + this.desc = cw.newUTF8(desc); + this.descriptor = desc; + if (ClassReader.SIGNATURES) { + this.signature = signature; + } + if (exceptions != null && exceptions.length > 0) { + exceptionCount = exceptions.length; + this.exceptions = new int[exceptionCount]; + for (int i = 0; i < exceptionCount; ++i) { + this.exceptions[i] = cw.newClass(exceptions[i]); + } + } + this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING); + if (computeMaxs || computeFrames) { + if (computeFrames && "".equals(name)) { + this.access |= ACC_CONSTRUCTOR; + } + // updates maxLocals + int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2; + if ((access & Opcodes.ACC_STATIC) != 0) { + --size; + } + maxLocals = size; + currentLocals = size; + // creates and visits the label for the first basic block + labels = new Label(); + labels.status |= Label.PUSHED; + visitLabel(labels); + } + } + + // ------------------------------------------------------------------------ + // Implementation of the MethodVisitor abstract class + // ------------------------------------------------------------------------ + + @Override + public AnnotationVisitor visitAnnotationDefault() { + if (!ClassReader.ANNOTATIONS) { + return null; + } + annd = new ByteVector(); + return new AnnotationWriter(cw, false, annd, null, 0); + } + + @Override + public AnnotationVisitor visitAnnotation( + final String desc, + final boolean visible) + { + if (!ClassReader.ANNOTATIONS) { + return null; + } + ByteVector bv = new ByteVector(); + // write type, and reserve space for values count + bv.putShort(cw.newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); + if (visible) { + aw.next = anns; + anns = aw; + } else { + aw.next = ianns; + ianns = aw; + } + return aw; + } + + @Override + public AnnotationVisitor visitParameterAnnotation( + final int parameter, + final String desc, + final boolean visible) + { + if (!ClassReader.ANNOTATIONS) { + return null; + } + ByteVector bv = new ByteVector(); + if ("Ljava/lang/Synthetic;".equals(desc)) { + // workaround for a bug in javac with synthetic parameters + // see ClassReader.readParameterAnnotations + synthetics = Math.max(synthetics, parameter + 1); + return new AnnotationWriter(cw, false, bv, null, 0); + } + // write type, and reserve space for values count + bv.putShort(cw.newUTF8(desc)).putShort(0); + AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); + if (visible) { + if (panns == null) { + panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; + } + aw.next = panns[parameter]; + panns[parameter] = aw; + } else { + if (ipanns == null) { + ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; + } + aw.next = ipanns[parameter]; + ipanns[parameter] = aw; + } + return aw; + } + + @Override + public void visitAttribute(final Attribute attr) { + if (attr.isCodeAttribute()) { + attr.next = cattrs; + cattrs = attr; + } else { + attr.next = attrs; + attrs = attr; + } + } + + @Override + public void visitCode() { + } + + @Override + public void visitFrame( + final int type, + final int nLocal, + final Object[] local, + final int nStack, + final Object[] stack) + { + if (!ClassReader.FRAMES || compute == FRAMES) { + return; + } + + if (type == Opcodes.F_NEW) { + currentLocals = nLocal; + startFrame(code.length, nLocal, nStack); + for (int i = 0; i < nLocal; ++i) { + if (local[i] instanceof String) { + frame[frameIndex++] = Frame.OBJECT + | cw.addType((String) local[i]); + } else if (local[i] instanceof Integer) { + frame[frameIndex++] = ((Integer) local[i]).intValue(); + } else { + frame[frameIndex++] = Frame.UNINITIALIZED + | cw.addUninitializedType("", + ((Label) local[i]).position); + } + } + for (int i = 0; i < nStack; ++i) { + if (stack[i] instanceof String) { + frame[frameIndex++] = Frame.OBJECT + | cw.addType((String) stack[i]); + } else if (stack[i] instanceof Integer) { + frame[frameIndex++] = ((Integer) stack[i]).intValue(); + } else { + frame[frameIndex++] = Frame.UNINITIALIZED + | cw.addUninitializedType("", + ((Label) stack[i]).position); + } + } + endFrame(); + } else { + int delta; + if (stackMap == null) { + stackMap = new ByteVector(); + delta = code.length; + } else { + delta = code.length - previousFrameOffset - 1; + if (delta < 0) { + if (type == Opcodes.F_SAME) { + return; + } else { + throw new IllegalStateException(); + } + } + } + + switch (type) { + case Opcodes.F_FULL: + currentLocals = nLocal; + stackMap.putByte(FULL_FRAME) + .putShort(delta) + .putShort(nLocal); + for (int i = 0; i < nLocal; ++i) { + writeFrameType(local[i]); + } + stackMap.putShort(nStack); + for (int i = 0; i < nStack; ++i) { + writeFrameType(stack[i]); + } + break; + case Opcodes.F_APPEND: + currentLocals += nLocal; + stackMap.putByte(SAME_FRAME_EXTENDED + nLocal) + .putShort(delta); + for (int i = 0; i < nLocal; ++i) { + writeFrameType(local[i]); + } + break; + case Opcodes.F_CHOP: + currentLocals -= nLocal; + stackMap.putByte(SAME_FRAME_EXTENDED - nLocal) + .putShort(delta); + break; + case Opcodes.F_SAME: + if (delta < 64) { + stackMap.putByte(delta); + } else { + stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); + } + break; + case Opcodes.F_SAME1: + if (delta < 64) { + stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); + } else { + stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) + .putShort(delta); + } + writeFrameType(stack[0]); + break; + } + + previousFrameOffset = code.length; + ++frameCount; + } + + maxStack = Math.max(maxStack, nStack); + maxLocals = Math.max(maxLocals, currentLocals); + } + + @Override + public void visitInsn(final int opcode) { + // adds the instruction to the bytecode of the method + code.putByte(opcode); + // update currentBlock + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES) { + currentBlock.frame.execute(opcode, 0, null, null); + } else { + // updates current and max stack sizes + int size = stackSize + Frame.SIZE[opcode]; + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + // if opcode == ATHROW or xRETURN, ends current block (no successor) + if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) + || opcode == Opcodes.ATHROW) + { + noSuccessor(); + } + } + } + + @Override + public void visitIntInsn(final int opcode, final int operand) { + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES) { + currentBlock.frame.execute(opcode, operand, null, null); + } else if (opcode != Opcodes.NEWARRAY) { + // updates current and max stack sizes only for NEWARRAY + // (stack size variation = 0 for BIPUSH or SIPUSH) + int size = stackSize + 1; + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + } + // adds the instruction to the bytecode of the method + if (opcode == Opcodes.SIPUSH) { + code.put12(opcode, operand); + } else { // BIPUSH or NEWARRAY + code.put11(opcode, operand); + } + } + + @Override + public void visitVarInsn(final int opcode, final int var) { + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES) { + currentBlock.frame.execute(opcode, var, null, null); + } else { + // updates current and max stack sizes + if (opcode == Opcodes.RET) { + // no stack change, but end of current block (no successor) + currentBlock.status |= Label.RET; + // save 'stackSize' here for future use + // (see {@link #findSubroutineSuccessors}) + currentBlock.inputStackTop = stackSize; + noSuccessor(); + } else { // xLOAD or xSTORE + int size = stackSize + Frame.SIZE[opcode]; + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + } + } + if (compute != NOTHING) { + // updates max locals + int n; + if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD + || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) + { + n = var + 2; + } else { + n = var + 1; + } + if (n > maxLocals) { + maxLocals = n; + } + } + // adds the instruction to the bytecode of the method + if (var < 4 && opcode != Opcodes.RET) { + int opt; + if (opcode < Opcodes.ISTORE) { + /* ILOAD_0 */ + opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var; + } else { + /* ISTORE_0 */ + opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var; + } + code.putByte(opt); + } else if (var >= 256) { + code.putByte(196 /* WIDE */).put12(opcode, var); + } else { + code.put11(opcode, var); + } + if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) { + visitLabel(new Label()); + } + } + + @Override + public void visitTypeInsn(final int opcode, final String type) { + Item i = cw.newClassItem(type); + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES) { + currentBlock.frame.execute(opcode, code.length, cw, i); + } else if (opcode == Opcodes.NEW) { + // updates current and max stack sizes only if opcode == NEW + // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF) + int size = stackSize + 1; + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + } + // adds the instruction to the bytecode of the method + code.put12(opcode, i.index); + } + + @Override + public void visitFieldInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + Item i = cw.newFieldItem(owner, name, desc); + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES) { + currentBlock.frame.execute(opcode, 0, cw, i); + } else { + int size; + // computes the stack size variation + char c = desc.charAt(0); + switch (opcode) { + case Opcodes.GETSTATIC: + size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); + break; + case Opcodes.PUTSTATIC: + size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); + break; + case Opcodes.GETFIELD: + size = stackSize + (c == 'D' || c == 'J' ? 1 : 0); + break; + // case Constants.PUTFIELD: + default: + size = stackSize + (c == 'D' || c == 'J' ? -3 : -2); + break; + } + // updates current and max stack sizes + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + } + // adds the instruction to the bytecode of the method + code.put12(opcode, i.index); + } + + @Override + public void visitMethodInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + boolean itf = opcode == Opcodes.INVOKEINTERFACE; + Item i = cw.newMethodItem(owner, name, desc, itf); + int argSize = i.intVal; + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES) { + currentBlock.frame.execute(opcode, 0, cw, i); + } else { + /* + * computes the stack size variation. In order not to recompute + * several times this variation for the same Item, we use the + * intVal field of this item to store this variation, once it + * has been computed. More precisely this intVal field stores + * the sizes of the arguments and of the return value + * corresponding to desc. + */ + if (argSize == 0) { + // the above sizes have not been computed yet, + // so we compute them... + argSize = Type.getArgumentsAndReturnSizes(desc); + // ... and we save them in order + // not to recompute them in the future + i.intVal = argSize; + } + int size; + if (opcode == Opcodes.INVOKESTATIC) { + size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; + } else { + size = stackSize - (argSize >> 2) + (argSize & 0x03); + } + // updates current and max stack sizes + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + } + // adds the instruction to the bytecode of the method + if (itf) { + if (argSize == 0) { + argSize = Type.getArgumentsAndReturnSizes(desc); + i.intVal = argSize; + } + code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0); + } else { + code.put12(opcode, i.index); + } + } + + @Override + public void visitInvokeDynamicInsn( + final String name, + final String desc, + final Handle bsm, + final Object... bsmArgs) + { + Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs); + int argSize = i.intVal; + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES) { + currentBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, cw, i); + } else { + /* + * computes the stack size variation. In order not to recompute + * several times this variation for the same Item, we use the + * intVal field of this item to store this variation, once it + * has been computed. More precisely this intVal field stores + * the sizes of the arguments and of the return value + * corresponding to desc. + */ + if (argSize == 0) { + // the above sizes have not been computed yet, + // so we compute them... + argSize = Type.getArgumentsAndReturnSizes(desc); + // ... and we save them in order + // not to recompute them in the future + i.intVal = argSize; + } + int size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; + + // updates current and max stack sizes + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + } + // adds the instruction to the bytecode of the method + code.put12(Opcodes.INVOKEDYNAMIC, i.index); + code.putShort(0); + } + + @Override + public void visitJumpInsn(final int opcode, final Label label) { + Label nextInsn = null; + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES) { + currentBlock.frame.execute(opcode, 0, null, null); + // 'label' is the target of a jump instruction + label.getFirst().status |= Label.TARGET; + // adds 'label' as a successor of this basic block + addSuccessor(Edge.NORMAL, label); + if (opcode != Opcodes.GOTO) { + // creates a Label for the next basic block + nextInsn = new Label(); + } + } else { + if (opcode == Opcodes.JSR) { + if ((label.status & Label.SUBROUTINE) == 0) { + label.status |= Label.SUBROUTINE; + ++subroutines; + } + currentBlock.status |= Label.JSR; + addSuccessor(stackSize + 1, label); + // creates a Label for the next basic block + nextInsn = new Label(); + /* + * note that, by construction in this method, a JSR block + * has at least two successors in the control flow graph: + * the first one leads the next instruction after the JSR, + * while the second one leads to the JSR target. + */ + } else { + // updates current stack size (max stack size unchanged + // because stack size variation always negative in this + // case) + stackSize += Frame.SIZE[opcode]; + addSuccessor(stackSize, label); + } + } + } + // adds the instruction to the bytecode of the method + if ((label.status & Label.RESOLVED) != 0 + && label.position - code.length < Short.MIN_VALUE) + { + /* + * case of a backward jump with an offset < -32768. In this case we + * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx + * with IFNOTxxx GOTO_W , where IFNOTxxx is the + * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where + * designates the instruction just after the GOTO_W. + */ + if (opcode == Opcodes.GOTO) { + code.putByte(200); // GOTO_W + } else if (opcode == Opcodes.JSR) { + code.putByte(201); // JSR_W + } else { + // if the IF instruction is transformed into IFNOT GOTO_W the + // next instruction becomes the target of the IFNOT instruction + if (nextInsn != null) { + nextInsn.status |= Label.TARGET; + } + code.putByte(opcode <= 166 + ? ((opcode + 1) ^ 1) - 1 + : opcode ^ 1); + code.putShort(8); // jump offset + code.putByte(200); // GOTO_W + } + label.put(this, code, code.length - 1, true); + } else { + /* + * case of a backward jump with an offset >= -32768, or of a forward + * jump with, of course, an unknown offset. In these cases we store + * the offset in 2 bytes (which will be increased in + * resizeInstructions, if needed). + */ + code.putByte(opcode); + label.put(this, code, code.length - 1, false); + } + if (currentBlock != null) { + if (nextInsn != null) { + // if the jump instruction is not a GOTO, the next instruction + // is also a successor of this instruction. Calling visitLabel + // adds the label of this next instruction as a successor of the + // current block, and starts a new basic block + visitLabel(nextInsn); + } + if (opcode == Opcodes.GOTO) { + noSuccessor(); + } + } + } + + @Override + public void visitLabel(final Label label) { + // resolves previous forward references to label, if any + resize |= label.resolve(this, code.length, code.data); + // updates currentBlock + if ((label.status & Label.DEBUG) != 0) { + return; + } + if (compute == FRAMES) { + if (currentBlock != null) { + if (label.position == currentBlock.position) { + // successive labels, do not start a new basic block + currentBlock.status |= (label.status & Label.TARGET); + label.frame = currentBlock.frame; + return; + } + // ends current block (with one new successor) + addSuccessor(Edge.NORMAL, label); + } + // begins a new current block + currentBlock = label; + if (label.frame == null) { + label.frame = new Frame(); + label.frame.owner = label; + } + // updates the basic block list + if (previousBlock != null) { + if (label.position == previousBlock.position) { + previousBlock.status |= (label.status & Label.TARGET); + label.frame = previousBlock.frame; + currentBlock = previousBlock; + return; + } + previousBlock.successor = label; + } + previousBlock = label; + } else if (compute == MAXS) { + if (currentBlock != null) { + // ends current block (with one new successor) + currentBlock.outputStackMax = maxStackSize; + addSuccessor(stackSize, label); + } + // begins a new current block + currentBlock = label; + // resets the relative current and max stack sizes + stackSize = 0; + maxStackSize = 0; + // updates the basic block list + if (previousBlock != null) { + previousBlock.successor = label; + } + previousBlock = label; + } + } + + @Override + public void visitLdcInsn(final Object cst) { + Item i = cw.newConstItem(cst); + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES) { + currentBlock.frame.execute(Opcodes.LDC, 0, cw, i); + } else { + int size; + // computes the stack size variation + if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) + { + size = stackSize + 2; + } else { + size = stackSize + 1; + } + // updates current and max stack sizes + if (size > maxStackSize) { + maxStackSize = size; + } + stackSize = size; + } + } + // adds the instruction to the bytecode of the method + int index = i.index; + if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { + code.put12(20 /* LDC2_W */, index); + } else if (index >= 256) { + code.put12(19 /* LDC_W */, index); + } else { + code.put11(Opcodes.LDC, index); + } + } + + @Override + public void visitIincInsn(final int var, final int increment) { + if (currentBlock != null) { + if (compute == FRAMES) { + currentBlock.frame.execute(Opcodes.IINC, var, null, null); + } + } + if (compute != NOTHING) { + // updates max locals + int n = var + 1; + if (n > maxLocals) { + maxLocals = n; + } + } + // adds the instruction to the bytecode of the method + if ((var > 255) || (increment > 127) || (increment < -128)) { + code.putByte(196 /* WIDE */) + .put12(Opcodes.IINC, var) + .putShort(increment); + } else { + code.putByte(Opcodes.IINC).put11(var, increment); + } + } + + @Override + public void visitTableSwitchInsn( + final int min, + final int max, + final Label dflt, + final Label... labels) + { + // adds the instruction to the bytecode of the method + int source = code.length; + code.putByte(Opcodes.TABLESWITCH); + code.putByteArray(null, 0, (4 - code.length % 4) % 4); + dflt.put(this, code, source, true); + code.putInt(min).putInt(max); + for (int i = 0; i < labels.length; ++i) { + labels[i].put(this, code, source, true); + } + // updates currentBlock + visitSwitchInsn(dflt, labels); + } + + @Override + public void visitLookupSwitchInsn( + final Label dflt, + final int[] keys, + final Label[] labels) + { + // adds the instruction to the bytecode of the method + int source = code.length; + code.putByte(Opcodes.LOOKUPSWITCH); + code.putByteArray(null, 0, (4 - code.length % 4) % 4); + dflt.put(this, code, source, true); + code.putInt(labels.length); + for (int i = 0; i < labels.length; ++i) { + code.putInt(keys[i]); + labels[i].put(this, code, source, true); + } + // updates currentBlock + visitSwitchInsn(dflt, labels); + } + + private void visitSwitchInsn(final Label dflt, final Label[] labels) { + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES) { + currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null); + // adds current block successors + addSuccessor(Edge.NORMAL, dflt); + dflt.getFirst().status |= Label.TARGET; + for (int i = 0; i < labels.length; ++i) { + addSuccessor(Edge.NORMAL, labels[i]); + labels[i].getFirst().status |= Label.TARGET; + } + } else { + // updates current stack size (max stack size unchanged) + --stackSize; + // adds current block successors + addSuccessor(stackSize, dflt); + for (int i = 0; i < labels.length; ++i) { + addSuccessor(stackSize, labels[i]); + } + } + // ends current block + noSuccessor(); + } + } + + @Override + public void visitMultiANewArrayInsn(final String desc, final int dims) { + Item i = cw.newClassItem(desc); + // Label currentBlock = this.currentBlock; + if (currentBlock != null) { + if (compute == FRAMES) { + currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i); + } else { + // updates current stack size (max stack size unchanged because + // stack size variation always negative or null) + stackSize += 1 - dims; + } + } + // adds the instruction to the bytecode of the method + code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims); + } + + @Override + public void visitTryCatchBlock( + final Label start, + final Label end, + final Label handler, + final String type) + { + ++handlerCount; + Handler h = new Handler(); + h.start = start; + h.end = end; + h.handler = handler; + h.desc = type; + h.type = type != null ? cw.newClass(type) : 0; + if (lastHandler == null) { + firstHandler = h; + } else { + lastHandler.next = h; + } + lastHandler = h; + } + + @Override + public void visitLocalVariable( + final String name, + final String desc, + final String signature, + final Label start, + final Label end, + final int index) + { + if (signature != null) { + if (localVarType == null) { + localVarType = new ByteVector(); + } + ++localVarTypeCount; + localVarType.putShort(start.position) + .putShort(end.position - start.position) + .putShort(cw.newUTF8(name)) + .putShort(cw.newUTF8(signature)) + .putShort(index); + } + if (localVar == null) { + localVar = new ByteVector(); + } + ++localVarCount; + localVar.putShort(start.position) + .putShort(end.position - start.position) + .putShort(cw.newUTF8(name)) + .putShort(cw.newUTF8(desc)) + .putShort(index); + if (compute != NOTHING) { + // updates max locals + char c = desc.charAt(0); + int n = index + (c == 'J' || c == 'D' ? 2 : 1); + if (n > maxLocals) { + maxLocals = n; + } + } + } + + @Override + public void visitLineNumber(final int line, final Label start) { + if (lineNumber == null) { + lineNumber = new ByteVector(); + } + ++lineNumberCount; + lineNumber.putShort(start.position); + lineNumber.putShort(line); + } + + @Override + public void visitMaxs(final int maxStack, final int maxLocals) { + if (ClassReader.FRAMES && compute == FRAMES) { + // completes the control flow graph with exception handler blocks + Handler handler = firstHandler; + while (handler != null) { + Label l = handler.start.getFirst(); + Label h = handler.handler.getFirst(); + Label e = handler.end.getFirst(); + // computes the kind of the edges to 'h' + String t = handler.desc == null + ? "java/lang/Throwable" + : handler.desc; + int kind = Frame.OBJECT | cw.addType(t); + // h is an exception handler + h.status |= Label.TARGET; + // adds 'h' as a successor of labels between 'start' and 'end' + while (l != e) { + // creates an edge to 'h' + Edge b = new Edge(); + b.info = kind; + b.successor = h; + // adds it to the successors of 'l' + b.next = l.successors; + l.successors = b; + // goes to the next label + l = l.successor; + } + handler = handler.next; + } + + // creates and visits the first (implicit) frame + Frame f = labels.frame; + Type[] args = Type.getArgumentTypes(descriptor); + f.initInputFrame(cw, access, args, this.maxLocals); + visitFrame(f); + + /* + * fix point algorithm: mark the first basic block as 'changed' + * (i.e. put it in the 'changed' list) and, while there are changed + * basic blocks, choose one, mark it as unchanged, and update its + * successors (which can be changed in the process). + */ + int max = 0; + Label changed = labels; + while (changed != null) { + // removes a basic block from the list of changed basic blocks + Label l = changed; + changed = changed.next; + l.next = null; + f = l.frame; + // a reachable jump target must be stored in the stack map + if ((l.status & Label.TARGET) != 0) { + l.status |= Label.STORE; + } + // all visited labels are reachable, by definition + l.status |= Label.REACHABLE; + // updates the (absolute) maximum stack size + int blockMax = f.inputStack.length + l.outputStackMax; + if (blockMax > max) { + max = blockMax; + } + // updates the successors of the current basic block + Edge e = l.successors; + while (e != null) { + Label n = e.successor.getFirst(); + boolean change = f.merge(cw, n.frame, e.info); + if (change && n.next == null) { + // if n has changed and is not already in the 'changed' + // list, adds it to this list + n.next = changed; + changed = n; + } + e = e.next; + } + } + + // visits all the frames that must be stored in the stack map + Label l = labels; + while (l != null) { + f = l.frame; + if ((l.status & Label.STORE) != 0) { + visitFrame(f); + } + if ((l.status & Label.REACHABLE) == 0) { + // finds start and end of dead basic block + Label k = l.successor; + int start = l.position; + int end = (k == null ? code.length : k.position) - 1; + // if non empty basic block + if (end >= start) { + max = Math.max(max, 1); + // replaces instructions with NOP ... NOP ATHROW + for (int i = start; i < end; ++i) { + code.data[i] = Opcodes.NOP; + } + code.data[end] = (byte) Opcodes.ATHROW; + // emits a frame for this unreachable block + startFrame(start, 0, 1); + frame[frameIndex++] = Frame.OBJECT + | cw.addType("java/lang/Throwable"); + endFrame(); + // removes the start-end range from the exception handlers + firstHandler = Handler.remove(firstHandler, l, k); + } + } + l = l.successor; + } + + handler = firstHandler; + handlerCount = 0; + while (handler != null) { + handlerCount += 1; + handler = handler.next; + } + + this.maxStack = max; + } else if (compute == MAXS) { + // completes the control flow graph with exception handler blocks + Handler handler = firstHandler; + while (handler != null) { + Label l = handler.start; + Label h = handler.handler; + Label e = handler.end; + // adds 'h' as a successor of labels between 'start' and 'end' + while (l != e) { + // creates an edge to 'h' + Edge b = new Edge(); + b.info = Edge.EXCEPTION; + b.successor = h; + // adds it to the successors of 'l' + if ((l.status & Label.JSR) == 0) { + b.next = l.successors; + l.successors = b; + } else { + // if l is a JSR block, adds b after the first two edges + // to preserve the hypothesis about JSR block successors + // order (see {@link #visitJumpInsn}) + b.next = l.successors.next.next; + l.successors.next.next = b; + } + // goes to the next label + l = l.successor; + } + handler = handler.next; + } + + if (subroutines > 0) { + // completes the control flow graph with the RET successors + /* + * first step: finds the subroutines. This step determines, for + * each basic block, to which subroutine(s) it belongs. + */ + // finds the basic blocks that belong to the "main" subroutine + int id = 0; + labels.visitSubroutine(null, 1, subroutines); + // finds the basic blocks that belong to the real subroutines + Label l = labels; + while (l != null) { + if ((l.status & Label.JSR) != 0) { + // the subroutine is defined by l's TARGET, not by l + Label subroutine = l.successors.next.successor; + // if this subroutine has not been visited yet... + if ((subroutine.status & Label.VISITED) == 0) { + // ...assigns it a new id and finds its basic blocks + id += 1; + subroutine.visitSubroutine(null, (id / 32L) << 32 + | (1L << (id % 32)), subroutines); + } + } + l = l.successor; + } + // second step: finds the successors of RET blocks + l = labels; + while (l != null) { + if ((l.status & Label.JSR) != 0) { + Label L = labels; + while (L != null) { + L.status &= ~Label.VISITED2; + L = L.successor; + } + // the subroutine is defined by l's TARGET, not by l + Label subroutine = l.successors.next.successor; + subroutine.visitSubroutine(l, 0, subroutines); + } + l = l.successor; + } + } + + /* + * control flow analysis algorithm: while the block stack is not + * empty, pop a block from this stack, update the max stack size, + * compute the true (non relative) begin stack size of the + * successors of this block, and push these successors onto the + * stack (unless they have already been pushed onto the stack). + * Note: by hypothesis, the {@link Label#inputStackTop} of the + * blocks in the block stack are the true (non relative) beginning + * stack sizes of these blocks. + */ + int max = 0; + Label stack = labels; + while (stack != null) { + // pops a block from the stack + Label l = stack; + stack = stack.next; + // computes the true (non relative) max stack size of this block + int start = l.inputStackTop; + int blockMax = start + l.outputStackMax; + // updates the global max stack size + if (blockMax > max) { + max = blockMax; + } + // analyzes the successors of the block + Edge b = l.successors; + if ((l.status & Label.JSR) != 0) { + // ignores the first edge of JSR blocks (virtual successor) + b = b.next; + } + while (b != null) { + l = b.successor; + // if this successor has not already been pushed... + if ((l.status & Label.PUSHED) == 0) { + // computes its true beginning stack size... + l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start + + b.info; + // ...and pushes it onto the stack + l.status |= Label.PUSHED; + l.next = stack; + stack = l; + } + b = b.next; + } + } + this.maxStack = Math.max(maxStack, max); + } else { + this.maxStack = maxStack; + this.maxLocals = maxLocals; + } + } + + @Override + public void visitEnd() { + } + + // ------------------------------------------------------------------------ + // Utility methods: control flow analysis algorithm + // ------------------------------------------------------------------------ + + /** + * Adds a successor to the {@link #currentBlock currentBlock} block. + * + * @param info information about the control flow edge to be added. + * @param successor the successor block to be added to the current block. + */ + private void addSuccessor(final int info, final Label successor) { + // creates and initializes an Edge object... + Edge b = new Edge(); + b.info = info; + b.successor = successor; + // ...and adds it to the successor list of the currentBlock block + b.next = currentBlock.successors; + currentBlock.successors = b; + } + + /** + * Ends the current basic block. This method must be used in the case where + * the current basic block does not have any successor. + */ + private void noSuccessor() { + if (compute == FRAMES) { + Label l = new Label(); + l.frame = new Frame(); + l.frame.owner = l; + l.resolve(this, code.length, code.data); + previousBlock.successor = l; + previousBlock = l; + } else { + currentBlock.outputStackMax = maxStackSize; + } + currentBlock = null; + } + + // ------------------------------------------------------------------------ + // Utility methods: stack map frames + // ------------------------------------------------------------------------ + + /** + * Visits a frame that has been computed from scratch. + * + * @param f the frame that must be visited. + */ + private void visitFrame(final Frame f) { + int i, t; + int nTop = 0; + int nLocal = 0; + int nStack = 0; + int[] locals = f.inputLocals; + int[] stacks = f.inputStack; + // computes the number of locals (ignores TOP types that are just after + // a LONG or a DOUBLE, and all trailing TOP types) + for (i = 0; i < locals.length; ++i) { + t = locals[i]; + if (t == Frame.TOP) { + ++nTop; + } else { + nLocal += nTop + 1; + nTop = 0; + } + if (t == Frame.LONG || t == Frame.DOUBLE) { + ++i; + } + } + // computes the stack size (ignores TOP types that are just after + // a LONG or a DOUBLE) + for (i = 0; i < stacks.length; ++i) { + t = stacks[i]; + ++nStack; + if (t == Frame.LONG || t == Frame.DOUBLE) { + ++i; + } + } + // visits the frame and its content + startFrame(f.owner.position, nLocal, nStack); + for (i = 0; nLocal > 0; ++i, --nLocal) { + t = locals[i]; + frame[frameIndex++] = t; + if (t == Frame.LONG || t == Frame.DOUBLE) { + ++i; + } + } + for (i = 0; i < stacks.length; ++i) { + t = stacks[i]; + frame[frameIndex++] = t; + if (t == Frame.LONG || t == Frame.DOUBLE) { + ++i; + } + } + endFrame(); + } + + /** + * Starts the visit of a stack map frame. + * + * @param offset the offset of the instruction to which the frame + * corresponds. + * @param nLocal the number of local variables in the frame. + * @param nStack the number of stack elements in the frame. + */ + private void startFrame(final int offset, final int nLocal, final int nStack) + { + int n = 3 + nLocal + nStack; + if (frame == null || frame.length < n) { + frame = new int[n]; + } + frame[0] = offset; + frame[1] = nLocal; + frame[2] = nStack; + frameIndex = 3; + } + + /** + * Checks if the visit of the current frame {@link #frame} is finished, and + * if yes, write it in the StackMapTable attribute. + */ + private void endFrame() { + if (previousFrame != null) { // do not write the first frame + if (stackMap == null) { + stackMap = new ByteVector(); + } + writeFrame(); + ++frameCount; + } + previousFrame = frame; + frame = null; + } + + /** + * Compress and writes the current frame {@link #frame} in the StackMapTable + * attribute. + */ + private void writeFrame() { + int clocalsSize = frame[1]; + int cstackSize = frame[2]; + if ((cw.version & 0xFFFF) < Opcodes.V1_6) { + stackMap.putShort(frame[0]).putShort(clocalsSize); + writeFrameTypes(3, 3 + clocalsSize); + stackMap.putShort(cstackSize); + writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); + return; + } + int localsSize = previousFrame[1]; + int type = FULL_FRAME; + int k = 0; + int delta; + if (frameCount == 0) { + delta = frame[0]; + } else { + delta = frame[0] - previousFrame[0] - 1; + } + if (cstackSize == 0) { + k = clocalsSize - localsSize; + switch (k) { + case -3: + case -2: + case -1: + type = CHOP_FRAME; + localsSize = clocalsSize; + break; + case 0: + type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; + break; + case 1: + case 2: + case 3: + type = APPEND_FRAME; + break; + } + } else if (clocalsSize == localsSize && cstackSize == 1) { + type = delta < 63 + ? SAME_LOCALS_1_STACK_ITEM_FRAME + : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; + } + if (type != FULL_FRAME) { + // verify if locals are the same + int l = 3; + for (int j = 0; j < localsSize; j++) { + if (frame[l] != previousFrame[l]) { + type = FULL_FRAME; + break; + } + l++; + } + } + switch (type) { + case SAME_FRAME: + stackMap.putByte(delta); + break; + case SAME_LOCALS_1_STACK_ITEM_FRAME: + stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); + writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); + break; + case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: + stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) + .putShort(delta); + writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); + break; + case SAME_FRAME_EXTENDED: + stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); + break; + case CHOP_FRAME: + stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); + break; + case APPEND_FRAME: + stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); + writeFrameTypes(3 + localsSize, 3 + clocalsSize); + break; + // case FULL_FRAME: + default: + stackMap.putByte(FULL_FRAME) + .putShort(delta) + .putShort(clocalsSize); + writeFrameTypes(3, 3 + clocalsSize); + stackMap.putShort(cstackSize); + writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); + } + } + + /** + * Writes some types of the current frame {@link #frame} into the + * StackMapTableAttribute. This method converts types from the format used + * in {@link Label} to the format used in StackMapTable attributes. In + * particular, it converts type table indexes to constant pool indexes. + * + * @param start index of the first type in {@link #frame} to write. + * @param end index of last type in {@link #frame} to write (exclusive). + */ + private void writeFrameTypes(final int start, final int end) { + for (int i = start; i < end; ++i) { + int t = frame[i]; + int d = t & Frame.DIM; + if (d == 0) { + int v = t & Frame.BASE_VALUE; + switch (t & Frame.BASE_KIND) { + case Frame.OBJECT: + stackMap.putByte(7) + .putShort(cw.newClass(cw.typeTable[v].strVal1)); + break; + case Frame.UNINITIALIZED: + stackMap.putByte(8).putShort(cw.typeTable[v].intVal); + break; + default: + stackMap.putByte(v); + } + } else { + StringBuffer buf = new StringBuffer(); + d >>= 28; + while (d-- > 0) { + buf.append('['); + } + if ((t & Frame.BASE_KIND) == Frame.OBJECT) { + buf.append('L'); + buf.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1); + buf.append(';'); + } else { + switch (t & 0xF) { + case 1: + buf.append('I'); + break; + case 2: + buf.append('F'); + break; + case 3: + buf.append('D'); + break; + case 9: + buf.append('Z'); + break; + case 10: + buf.append('B'); + break; + case 11: + buf.append('C'); + break; + case 12: + buf.append('S'); + break; + default: + buf.append('J'); + } + } + stackMap.putByte(7).putShort(cw.newClass(buf.toString())); + } + } + } + + private void writeFrameType(final Object type) { + if (type instanceof String) { + stackMap.putByte(7).putShort(cw.newClass((String) type)); + } else if (type instanceof Integer) { + stackMap.putByte(((Integer) type).intValue()); + } else { + stackMap.putByte(8).putShort(((Label) type).position); + } + } + + // ------------------------------------------------------------------------ + // Utility methods: dump bytecode array + // ------------------------------------------------------------------------ + + /** + * Returns the size of the bytecode of this method. + * + * @return the size of the bytecode of this method. + */ + final int getSize() { + if (classReaderOffset != 0) { + return 6 + classReaderLength; + } + if (resize) { + // replaces the temporary jump opcodes introduced by Label.resolve. + if (ClassReader.RESIZE) { + resizeInstructions(); + } else { + throw new RuntimeException("Method code too large!"); + } + } + int size = 8; + if (code.length > 0) { + if (code.length > 65536) { + throw new RuntimeException("Method code too large!"); + } + cw.newUTF8("Code"); + size += 18 + code.length + 8 * handlerCount; + if (localVar != null) { + cw.newUTF8("LocalVariableTable"); + size += 8 + localVar.length; + } + if (localVarType != null) { + cw.newUTF8("LocalVariableTypeTable"); + size += 8 + localVarType.length; + } + if (lineNumber != null) { + cw.newUTF8("LineNumberTable"); + size += 8 + lineNumber.length; + } + if (stackMap != null) { + boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; + cw.newUTF8(zip ? "StackMapTable" : "StackMap"); + size += 8 + stackMap.length; + } + if (cattrs != null) { + size += cattrs.getSize(cw, + code.data, + code.length, + maxStack, + maxLocals); + } + } + if (exceptionCount > 0) { + cw.newUTF8("Exceptions"); + size += 8 + 2 * exceptionCount; + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0 + && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) + { + cw.newUTF8("Synthetic"); + size += 6; + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + cw.newUTF8("Deprecated"); + size += 6; + } + if (ClassReader.SIGNATURES && signature != null) { + cw.newUTF8("Signature"); + cw.newUTF8(signature); + size += 8; + } + if (ClassReader.ANNOTATIONS && annd != null) { + cw.newUTF8("AnnotationDefault"); + size += 6 + annd.length; + } + if (ClassReader.ANNOTATIONS && anns != null) { + cw.newUTF8("RuntimeVisibleAnnotations"); + size += 8 + anns.getSize(); + } + if (ClassReader.ANNOTATIONS && ianns != null) { + cw.newUTF8("RuntimeInvisibleAnnotations"); + size += 8 + ianns.getSize(); + } + if (ClassReader.ANNOTATIONS && panns != null) { + cw.newUTF8("RuntimeVisibleParameterAnnotations"); + size += 7 + 2 * (panns.length - synthetics); + for (int i = panns.length - 1; i >= synthetics; --i) { + size += panns[i] == null ? 0 : panns[i].getSize(); + } + } + if (ClassReader.ANNOTATIONS && ipanns != null) { + cw.newUTF8("RuntimeInvisibleParameterAnnotations"); + size += 7 + 2 * (ipanns.length - synthetics); + for (int i = ipanns.length - 1; i >= synthetics; --i) { + size += ipanns[i] == null ? 0 : ipanns[i].getSize(); + } + } + if (attrs != null) { + size += attrs.getSize(cw, null, 0, -1, -1); + } + return size; + } + + /** + * Puts the bytecode of this method in the given byte vector. + * + * @param out the byte vector into which the bytecode of this method must be + * copied. + */ + final void put(final ByteVector out) { + int mask = Opcodes.ACC_DEPRECATED + | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE + | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / (ClassWriter.ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC)); + out.putShort(access & ~mask).putShort(name).putShort(desc); + if (classReaderOffset != 0) { + out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength); + return; + } + int attributeCount = 0; + if (code.length > 0) { + ++attributeCount; + } + if (exceptionCount > 0) { + ++attributeCount; + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0 + && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) + { + ++attributeCount; + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + ++attributeCount; + } + if (ClassReader.SIGNATURES && signature != null) { + ++attributeCount; + } + if (ClassReader.ANNOTATIONS && annd != null) { + ++attributeCount; + } + if (ClassReader.ANNOTATIONS && anns != null) { + ++attributeCount; + } + if (ClassReader.ANNOTATIONS && ianns != null) { + ++attributeCount; + } + if (ClassReader.ANNOTATIONS && panns != null) { + ++attributeCount; + } + if (ClassReader.ANNOTATIONS && ipanns != null) { + ++attributeCount; + } + if (attrs != null) { + attributeCount += attrs.getCount(); + } + out.putShort(attributeCount); + if (code.length > 0) { + int size = 12 + code.length + 8 * handlerCount; + if (localVar != null) { + size += 8 + localVar.length; + } + if (localVarType != null) { + size += 8 + localVarType.length; + } + if (lineNumber != null) { + size += 8 + lineNumber.length; + } + if (stackMap != null) { + size += 8 + stackMap.length; + } + if (cattrs != null) { + size += cattrs.getSize(cw, + code.data, + code.length, + maxStack, + maxLocals); + } + out.putShort(cw.newUTF8("Code")).putInt(size); + out.putShort(maxStack).putShort(maxLocals); + out.putInt(code.length).putByteArray(code.data, 0, code.length); + out.putShort(handlerCount); + if (handlerCount > 0) { + Handler h = firstHandler; + while (h != null) { + out.putShort(h.start.position) + .putShort(h.end.position) + .putShort(h.handler.position) + .putShort(h.type); + h = h.next; + } + } + attributeCount = 0; + if (localVar != null) { + ++attributeCount; + } + if (localVarType != null) { + ++attributeCount; + } + if (lineNumber != null) { + ++attributeCount; + } + if (stackMap != null) { + ++attributeCount; + } + if (cattrs != null) { + attributeCount += cattrs.getCount(); + } + out.putShort(attributeCount); + if (localVar != null) { + out.putShort(cw.newUTF8("LocalVariableTable")); + out.putInt(localVar.length + 2).putShort(localVarCount); + out.putByteArray(localVar.data, 0, localVar.length); + } + if (localVarType != null) { + out.putShort(cw.newUTF8("LocalVariableTypeTable")); + out.putInt(localVarType.length + 2).putShort(localVarTypeCount); + out.putByteArray(localVarType.data, 0, localVarType.length); + } + if (lineNumber != null) { + out.putShort(cw.newUTF8("LineNumberTable")); + out.putInt(lineNumber.length + 2).putShort(lineNumberCount); + out.putByteArray(lineNumber.data, 0, lineNumber.length); + } + if (stackMap != null) { + boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; + out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap")); + out.putInt(stackMap.length + 2).putShort(frameCount); + out.putByteArray(stackMap.data, 0, stackMap.length); + } + if (cattrs != null) { + cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out); + } + } + if (exceptionCount > 0) { + out.putShort(cw.newUTF8("Exceptions")) + .putInt(2 * exceptionCount + 2); + out.putShort(exceptionCount); + for (int i = 0; i < exceptionCount; ++i) { + out.putShort(exceptions[i]); + } + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0 + && ((cw.version & 0xFFFF) < Opcodes.V1_5 || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0)) + { + out.putShort(cw.newUTF8("Synthetic")).putInt(0); + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + out.putShort(cw.newUTF8("Deprecated")).putInt(0); + } + if (ClassReader.SIGNATURES && signature != null) { + out.putShort(cw.newUTF8("Signature")) + .putInt(2) + .putShort(cw.newUTF8(signature)); + } + if (ClassReader.ANNOTATIONS && annd != null) { + out.putShort(cw.newUTF8("AnnotationDefault")); + out.putInt(annd.length); + out.putByteArray(annd.data, 0, annd.length); + } + if (ClassReader.ANNOTATIONS && anns != null) { + out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); + anns.put(out); + } + if (ClassReader.ANNOTATIONS && ianns != null) { + out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); + ianns.put(out); + } + if (ClassReader.ANNOTATIONS && panns != null) { + out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations")); + AnnotationWriter.put(panns, synthetics, out); + } + if (ClassReader.ANNOTATIONS && ipanns != null) { + out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations")); + AnnotationWriter.put(ipanns, synthetics, out); + } + if (attrs != null) { + attrs.put(cw, null, 0, -1, -1, out); + } + } + + // ------------------------------------------------------------------------ + // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W) + // ------------------------------------------------------------------------ + + /** + * Resizes and replaces the temporary instructions inserted by + * {@link Label#resolve} for wide forward jumps, while keeping jump offsets + * and instruction addresses consistent. This may require to resize other + * existing instructions, or even to introduce new instructions: for + * example, increasing the size of an instruction by 2 at the middle of a + * method can increases the offset of an IFEQ instruction from 32766 to + * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W + * 32765. This, in turn, may require to increase the size of another jump + * instruction, and so on... All these operations are handled automatically + * by this method.

    This method must be called after all the method + * that is being built has been visited. In particular, the + * {@link Label Label} objects used to construct the method are no longer + * valid after this method has been called. + */ + private void resizeInstructions() { + byte[] b = code.data; // bytecode of the method + int u, v, label; // indexes in b + int i, j; // loop indexes + /* + * 1st step: As explained above, resizing an instruction may require to + * resize another one, which may require to resize yet another one, and + * so on. The first step of the algorithm consists in finding all the + * instructions that need to be resized, without modifying the code. + * This is done by the following "fix point" algorithm: + * + * Parse the code to find the jump instructions whose offset will need + * more than 2 bytes to be stored (the future offset is computed from + * the current offset and from the number of bytes that will be inserted + * or removed between the source and target instructions). For each such + * instruction, adds an entry in (a copy of) the indexes and sizes + * arrays (if this has not already been done in a previous iteration!). + * + * If at least one entry has been added during the previous step, go + * back to the beginning, otherwise stop. + * + * In fact the real algorithm is complicated by the fact that the size + * of TABLESWITCH and LOOKUPSWITCH instructions depends on their + * position in the bytecode (because of padding). In order to ensure the + * convergence of the algorithm, the number of bytes to be added or + * removed from these instructions is over estimated during the previous + * loop, and computed exactly only after the loop is finished (this + * requires another pass to parse the bytecode of the method). + */ + int[] allIndexes = new int[0]; // copy of indexes + int[] allSizes = new int[0]; // copy of sizes + boolean[] resize; // instructions to be resized + int newOffset; // future offset of a jump instruction + + resize = new boolean[code.length]; + + // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done + int state = 3; + do { + if (state == 3) { + state = 2; + } + u = 0; + while (u < b.length) { + int opcode = b[u] & 0xFF; // opcode of current instruction + int insert = 0; // bytes to be added after this instruction + + switch (ClassWriter.TYPE[opcode]) { + case ClassWriter.NOARG_INSN: + case ClassWriter.IMPLVAR_INSN: + u += 1; + break; + case ClassWriter.LABEL_INSN: + if (opcode > 201) { + // converts temporary opcodes 202 to 217, 218 and + // 219 to IFEQ ... JSR (inclusive), IFNULL and + // IFNONNULL + opcode = opcode < 218 ? opcode - 49 : opcode - 20; + label = u + readUnsignedShort(b, u + 1); + } else { + label = u + readShort(b, u + 1); + } + newOffset = getNewOffset(allIndexes, allSizes, u, label); + if (newOffset < Short.MIN_VALUE + || newOffset > Short.MAX_VALUE) + { + if (!resize[u]) { + if (opcode == Opcodes.GOTO + || opcode == Opcodes.JSR) + { + // two additional bytes will be required to + // replace this GOTO or JSR instruction with + // a GOTO_W or a JSR_W + insert = 2; + } else { + // five additional bytes will be required to + // replace this IFxxx instruction with + // IFNOTxxx GOTO_W , where IFNOTxxx + // is the "opposite" opcode of IFxxx (i.e., + // IFNE for IFEQ) and where designates + // the instruction just after the GOTO_W. + insert = 5; + } + resize[u] = true; + } + } + u += 3; + break; + case ClassWriter.LABELW_INSN: + u += 5; + break; + case ClassWriter.TABL_INSN: + if (state == 1) { + // true number of bytes to be added (or removed) + // from this instruction = (future number of padding + // bytes - current number of padding byte) - + // previously over estimated variation = + // = ((3 - newOffset%4) - (3 - u%4)) - u%4 + // = (-newOffset%4 + u%4) - u%4 + // = -(newOffset & 3) + newOffset = getNewOffset(allIndexes, allSizes, 0, u); + insert = -(newOffset & 3); + } else if (!resize[u]) { + // over estimation of the number of bytes to be + // added to this instruction = 3 - current number + // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3 + insert = u & 3; + resize[u] = true; + } + // skips instruction + u = u + 4 - (u & 3); + u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12; + break; + case ClassWriter.LOOK_INSN: + if (state == 1) { + // like TABL_INSN + newOffset = getNewOffset(allIndexes, allSizes, 0, u); + insert = -(newOffset & 3); + } else if (!resize[u]) { + // like TABL_INSN + insert = u & 3; + resize[u] = true; + } + // skips instruction + u = u + 4 - (u & 3); + u += 8 * readInt(b, u + 4) + 8; + break; + case ClassWriter.WIDE_INSN: + opcode = b[u + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + u += 6; + } else { + u += 4; + } + break; + case ClassWriter.VAR_INSN: + case ClassWriter.SBYTE_INSN: + case ClassWriter.LDC_INSN: + u += 2; + break; + case ClassWriter.SHORT_INSN: + case ClassWriter.LDCW_INSN: + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.TYPE_INSN: + case ClassWriter.IINC_INSN: + u += 3; + break; + case ClassWriter.ITFMETH_INSN: + case ClassWriter.INDYMETH_INSN: + u += 5; + break; + // case ClassWriter.MANA_INSN: + default: + u += 4; + break; + } + if (insert != 0) { + // adds a new (u, insert) entry in the allIndexes and + // allSizes arrays + int[] newIndexes = new int[allIndexes.length + 1]; + int[] newSizes = new int[allSizes.length + 1]; + System.arraycopy(allIndexes, + 0, + newIndexes, + 0, + allIndexes.length); + System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length); + newIndexes[allIndexes.length] = u; + newSizes[allSizes.length] = insert; + allIndexes = newIndexes; + allSizes = newSizes; + if (insert > 0) { + state = 3; + } + } + } + if (state < 3) { + --state; + } + } while (state != 0); + + // 2nd step: + // copies the bytecode of the method into a new bytevector, updates the + // offsets, and inserts (or removes) bytes as requested. + + ByteVector newCode = new ByteVector(code.length); + + u = 0; + while (u < code.length) { + int opcode = b[u] & 0xFF; + switch (ClassWriter.TYPE[opcode]) { + case ClassWriter.NOARG_INSN: + case ClassWriter.IMPLVAR_INSN: + newCode.putByte(opcode); + u += 1; + break; + case ClassWriter.LABEL_INSN: + if (opcode > 201) { + // changes temporary opcodes 202 to 217 (inclusive), 218 + // and 219 to IFEQ ... JSR (inclusive), IFNULL and + // IFNONNULL + opcode = opcode < 218 ? opcode - 49 : opcode - 20; + label = u + readUnsignedShort(b, u + 1); + } else { + label = u + readShort(b, u + 1); + } + newOffset = getNewOffset(allIndexes, allSizes, u, label); + if (resize[u]) { + // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx + // with IFNOTxxx GOTO_W , where IFNOTxxx is + // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) + // and where designates the instruction just after + // the GOTO_W. + if (opcode == Opcodes.GOTO) { + newCode.putByte(200); // GOTO_W + } else if (opcode == Opcodes.JSR) { + newCode.putByte(201); // JSR_W + } else { + newCode.putByte(opcode <= 166 + ? ((opcode + 1) ^ 1) - 1 + : opcode ^ 1); + newCode.putShort(8); // jump offset + newCode.putByte(200); // GOTO_W + // newOffset now computed from start of GOTO_W + newOffset -= 3; + } + newCode.putInt(newOffset); + } else { + newCode.putByte(opcode); + newCode.putShort(newOffset); + } + u += 3; + break; + case ClassWriter.LABELW_INSN: + label = u + readInt(b, u + 1); + newOffset = getNewOffset(allIndexes, allSizes, u, label); + newCode.putByte(opcode); + newCode.putInt(newOffset); + u += 5; + break; + case ClassWriter.TABL_INSN: + // skips 0 to 3 padding bytes + v = u; + u = u + 4 - (v & 3); + // reads and copies instruction + newCode.putByte(Opcodes.TABLESWITCH); + newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); + label = v + readInt(b, u); + u += 4; + newOffset = getNewOffset(allIndexes, allSizes, v, label); + newCode.putInt(newOffset); + j = readInt(b, u); + u += 4; + newCode.putInt(j); + j = readInt(b, u) - j + 1; + u += 4; + newCode.putInt(readInt(b, u - 4)); + for (; j > 0; --j) { + label = v + readInt(b, u); + u += 4; + newOffset = getNewOffset(allIndexes, allSizes, v, label); + newCode.putInt(newOffset); + } + break; + case ClassWriter.LOOK_INSN: + // skips 0 to 3 padding bytes + v = u; + u = u + 4 - (v & 3); + // reads and copies instruction + newCode.putByte(Opcodes.LOOKUPSWITCH); + newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); + label = v + readInt(b, u); + u += 4; + newOffset = getNewOffset(allIndexes, allSizes, v, label); + newCode.putInt(newOffset); + j = readInt(b, u); + u += 4; + newCode.putInt(j); + for (; j > 0; --j) { + newCode.putInt(readInt(b, u)); + u += 4; + label = v + readInt(b, u); + u += 4; + newOffset = getNewOffset(allIndexes, allSizes, v, label); + newCode.putInt(newOffset); + } + break; + case ClassWriter.WIDE_INSN: + opcode = b[u + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + newCode.putByteArray(b, u, 6); + u += 6; + } else { + newCode.putByteArray(b, u, 4); + u += 4; + } + break; + case ClassWriter.VAR_INSN: + case ClassWriter.SBYTE_INSN: + case ClassWriter.LDC_INSN: + newCode.putByteArray(b, u, 2); + u += 2; + break; + case ClassWriter.SHORT_INSN: + case ClassWriter.LDCW_INSN: + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.TYPE_INSN: + case ClassWriter.IINC_INSN: + newCode.putByteArray(b, u, 3); + u += 3; + break; + case ClassWriter.ITFMETH_INSN: + case ClassWriter.INDYMETH_INSN: + newCode.putByteArray(b, u, 5); + u += 5; + break; + // case MANA_INSN: + default: + newCode.putByteArray(b, u, 4); + u += 4; + break; + } + } + + // recomputes the stack map frames + if (frameCount > 0) { + if (compute == FRAMES) { + frameCount = 0; + stackMap = null; + previousFrame = null; + frame = null; + Frame f = new Frame(); + f.owner = labels; + Type[] args = Type.getArgumentTypes(descriptor); + f.initInputFrame(cw, access, args, maxLocals); + visitFrame(f); + Label l = labels; + while (l != null) { + /* + * here we need the original label position. getNewOffset + * must therefore never have been called for this label. + */ + u = l.position - 3; + if ((l.status & Label.STORE) != 0 || (u >= 0 && resize[u])) + { + getNewOffset(allIndexes, allSizes, l); + // TODO update offsets in UNINITIALIZED values + visitFrame(l.frame); + } + l = l.successor; + } + } else { + /* + * Resizing an existing stack map frame table is really hard. + * Not only the table must be parsed to update the offets, but + * new frames may be needed for jump instructions that were + * inserted by this method. And updating the offsets or + * inserting frames can change the format of the following + * frames, in case of packed frames. In practice the whole table + * must be recomputed. For this the frames are marked as + * potentially invalid. This will cause the whole class to be + * reread and rewritten with the COMPUTE_FRAMES option (see the + * ClassWriter.toByteArray method). This is not very efficient + * but is much easier and requires much less code than any other + * method I can think of. + */ + cw.invalidFrames = true; + } + } + // updates the exception handler block labels + Handler h = firstHandler; + while (h != null) { + getNewOffset(allIndexes, allSizes, h.start); + getNewOffset(allIndexes, allSizes, h.end); + getNewOffset(allIndexes, allSizes, h.handler); + h = h.next; + } + // updates the instructions addresses in the + // local var and line number tables + for (i = 0; i < 2; ++i) { + ByteVector bv = i == 0 ? localVar : localVarType; + if (bv != null) { + b = bv.data; + u = 0; + while (u < bv.length) { + label = readUnsignedShort(b, u); + newOffset = getNewOffset(allIndexes, allSizes, 0, label); + writeShort(b, u, newOffset); + label += readUnsignedShort(b, u + 2); + newOffset = getNewOffset(allIndexes, allSizes, 0, label) + - newOffset; + writeShort(b, u + 2, newOffset); + u += 10; + } + } + } + if (lineNumber != null) { + b = lineNumber.data; + u = 0; + while (u < lineNumber.length) { + writeShort(b, u, getNewOffset(allIndexes, + allSizes, + 0, + readUnsignedShort(b, u))); + u += 4; + } + } + // updates the labels of the other attributes + Attribute attr = cattrs; + while (attr != null) { + Label[] labels = attr.getLabels(); + if (labels != null) { + for (i = labels.length - 1; i >= 0; --i) { + getNewOffset(allIndexes, allSizes, labels[i]); + } + } + attr = attr.next; + } + + // replaces old bytecodes with new ones + code = newCode; + } + + /** + * Reads an unsigned short value in the given byte array. + * + * @param b a byte array. + * @param index the start index of the value to be read. + * @return the read value. + */ + static int readUnsignedShort(final byte[] b, final int index) { + return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); + } + + /** + * Reads a signed short value in the given byte array. + * + * @param b a byte array. + * @param index the start index of the value to be read. + * @return the read value. + */ + static short readShort(final byte[] b, final int index) { + return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); + } + + /** + * Reads a signed int value in the given byte array. + * + * @param b a byte array. + * @param index the start index of the value to be read. + * @return the read value. + */ + static int readInt(final byte[] b, final int index) { + return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) + | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); + } + + /** + * Writes a short value in the given byte array. + * + * @param b a byte array. + * @param index where the first byte of the short value must be written. + * @param s the value to be written in the given byte array. + */ + static void writeShort(final byte[] b, final int index, final int s) { + b[index] = (byte) (s >>> 8); + b[index + 1] = (byte) s; + } + + /** + * Computes the future value of a bytecode offset.

    Note: it is possible + * to have several entries for the same instruction in the indexes + * and sizes: two entries (index=a,size=b) and (index=a,size=b') + * are equivalent to a single entry (index=a,size=b+b'). + * + * @param indexes current positions of the instructions to be resized. Each + * instruction must be designated by the index of its last + * byte, plus one (or, in other words, by the index of the first + * byte of the next instruction). + * @param sizes the number of bytes to be added to the above + * instructions. More precisely, for each i < len, + * sizes[i] bytes will be added at the end of the + * instruction designated by indexes[i] or, if + * sizes[i] is negative, the last |sizes[i]| + * bytes of the instruction will be removed (the instruction size + * must not become negative or null). + * @param begin index of the first byte of the source instruction. + * @param end index of the first byte of the target instruction. + * @return the future value of the given bytecode offset. + */ + static int getNewOffset( + final int[] indexes, + final int[] sizes, + final int begin, + final int end) + { + int offset = end - begin; + for (int i = 0; i < indexes.length; ++i) { + if (begin < indexes[i] && indexes[i] <= end) { + // forward jump + offset += sizes[i]; + } else if (end < indexes[i] && indexes[i] <= begin) { + // backward jump + offset -= sizes[i]; + } + } + return offset; + } + + /** + * Updates the offset of the given label. + * + * @param indexes current positions of the instructions to be resized. Each + * instruction must be designated by the index of its last + * byte, plus one (or, in other words, by the index of the first + * byte of the next instruction). + * @param sizes the number of bytes to be added to the above + * instructions. More precisely, for each i < len, + * sizes[i] bytes will be added at the end of the + * instruction designated by indexes[i] or, if + * sizes[i] is negative, the last |sizes[i]| + * bytes of the instruction will be removed (the instruction size + * must not become negative or null). + * @param label the label whose offset must be updated. + */ + static void getNewOffset( + final int[] indexes, + final int[] sizes, + final Label label) + { + if ((label.status & Label.RESIZED) == 0) { + label.position = getNewOffset(indexes, sizes, 0, label.position); + label.status |= Label.RESIZED; + } + } +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java new file mode 100644 index 00000000000..df3dcbcd749 --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java @@ -0,0 +1,387 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +/** + * Defines the JVM opcodes, access flags and array type codes. This interface + * does not define all the JVM opcodes because some opcodes are automatically + * handled. For example, the xLOAD and xSTORE opcodes are automatically replaced + * by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n + * opcodes are therefore not defined in this interface. Likewise for LDC, + * automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and + * JSR_W. + * + * @author Eric Bruneton + * @author Eugene Kuleshov + */ +public interface Opcodes { + + // ASM API versions + + int ASM4 = 4 << 16 | 0 << 8 | 0; + + // versions + + int V1_1 = 3 << 16 | 45; + int V1_2 = 0 << 16 | 46; + int V1_3 = 0 << 16 | 47; + int V1_4 = 0 << 16 | 48; + int V1_5 = 0 << 16 | 49; + int V1_6 = 0 << 16 | 50; + int V1_7 = 0 << 16 | 51; + + // access flags + + int ACC_PUBLIC = 0x0001; // class, field, method + int ACC_PRIVATE = 0x0002; // class, field, method + int ACC_PROTECTED = 0x0004; // class, field, method + int ACC_STATIC = 0x0008; // field, method + int ACC_FINAL = 0x0010; // class, field, method + int ACC_SUPER = 0x0020; // class + int ACC_SYNCHRONIZED = 0x0020; // method + int ACC_VOLATILE = 0x0040; // field + int ACC_BRIDGE = 0x0040; // method + int ACC_VARARGS = 0x0080; // method + int ACC_TRANSIENT = 0x0080; // field + int ACC_NATIVE = 0x0100; // method + int ACC_INTERFACE = 0x0200; // class + int ACC_ABSTRACT = 0x0400; // class, method + int ACC_STRICT = 0x0800; // method + int ACC_SYNTHETIC = 0x1000; // class, field, method + int ACC_ANNOTATION = 0x2000; // class + int ACC_ENUM = 0x4000; // class(?) field inner + + // ASM specific pseudo access flags + + int ACC_DEPRECATED = 0x20000; // class, field, method + + // types for NEWARRAY + + int T_BOOLEAN = 4; + int T_CHAR = 5; + int T_FLOAT = 6; + int T_DOUBLE = 7; + int T_BYTE = 8; + int T_SHORT = 9; + int T_INT = 10; + int T_LONG = 11; + + // tags for Handle + + int H_GETFIELD = 1; + int H_GETSTATIC = 2; + int H_PUTFIELD = 3; + int H_PUTSTATIC = 4; + int H_INVOKEVIRTUAL = 5; + int H_INVOKESTATIC = 6; + int H_INVOKESPECIAL = 7; + int H_NEWINVOKESPECIAL = 8; + int H_INVOKEINTERFACE = 9; + + // stack map frame types + + /** + * Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}. + */ + int F_NEW = -1; + + /** + * Represents a compressed frame with complete frame data. + */ + int F_FULL = 0; + + /** + * Represents a compressed frame where locals are the same as the locals in + * the previous frame, except that additional 1-3 locals are defined, and + * with an empty stack. + */ + int F_APPEND = 1; + + /** + * Represents a compressed frame where locals are the same as the locals in + * the previous frame, except that the last 1-3 locals are absent and with + * an empty stack. + */ + int F_CHOP = 2; + + /** + * Represents a compressed frame with exactly the same locals as the + * previous frame and with an empty stack. + */ + int F_SAME = 3; + + /** + * Represents a compressed frame with exactly the same locals as the + * previous frame and with a single value on the stack. + */ + int F_SAME1 = 4; + + Integer TOP = new Integer(0); + Integer INTEGER = new Integer(1); + Integer FLOAT = new Integer(2); + Integer DOUBLE = new Integer(3); + Integer LONG = new Integer(4); + Integer NULL = new Integer(5); + Integer UNINITIALIZED_THIS = new Integer(6); + + // opcodes // visit method (- = idem) + + int NOP = 0; // visitInsn + int ACONST_NULL = 1; // - + int ICONST_M1 = 2; // - + int ICONST_0 = 3; // - + int ICONST_1 = 4; // - + int ICONST_2 = 5; // - + int ICONST_3 = 6; // - + int ICONST_4 = 7; // - + int ICONST_5 = 8; // - + int LCONST_0 = 9; // - + int LCONST_1 = 10; // - + int FCONST_0 = 11; // - + int FCONST_1 = 12; // - + int FCONST_2 = 13; // - + int DCONST_0 = 14; // - + int DCONST_1 = 15; // - + int BIPUSH = 16; // visitIntInsn + int SIPUSH = 17; // - + int LDC = 18; // visitLdcInsn + // int LDC_W = 19; // - + // int LDC2_W = 20; // - + int ILOAD = 21; // visitVarInsn + int LLOAD = 22; // - + int FLOAD = 23; // - + int DLOAD = 24; // - + int ALOAD = 25; // - + // int ILOAD_0 = 26; // - + // int ILOAD_1 = 27; // - + // int ILOAD_2 = 28; // - + // int ILOAD_3 = 29; // - + // int LLOAD_0 = 30; // - + // int LLOAD_1 = 31; // - + // int LLOAD_2 = 32; // - + // int LLOAD_3 = 33; // - + // int FLOAD_0 = 34; // - + // int FLOAD_1 = 35; // - + // int FLOAD_2 = 36; // - + // int FLOAD_3 = 37; // - + // int DLOAD_0 = 38; // - + // int DLOAD_1 = 39; // - + // int DLOAD_2 = 40; // - + // int DLOAD_3 = 41; // - + // int ALOAD_0 = 42; // - + // int ALOAD_1 = 43; // - + // int ALOAD_2 = 44; // - + // int ALOAD_3 = 45; // - + int IALOAD = 46; // visitInsn + int LALOAD = 47; // - + int FALOAD = 48; // - + int DALOAD = 49; // - + int AALOAD = 50; // - + int BALOAD = 51; // - + int CALOAD = 52; // - + int SALOAD = 53; // - + int ISTORE = 54; // visitVarInsn + int LSTORE = 55; // - + int FSTORE = 56; // - + int DSTORE = 57; // - + int ASTORE = 58; // - + // int ISTORE_0 = 59; // - + // int ISTORE_1 = 60; // - + // int ISTORE_2 = 61; // - + // int ISTORE_3 = 62; // - + // int LSTORE_0 = 63; // - + // int LSTORE_1 = 64; // - + // int LSTORE_2 = 65; // - + // int LSTORE_3 = 66; // - + // int FSTORE_0 = 67; // - + // int FSTORE_1 = 68; // - + // int FSTORE_2 = 69; // - + // int FSTORE_3 = 70; // - + // int DSTORE_0 = 71; // - + // int DSTORE_1 = 72; // - + // int DSTORE_2 = 73; // - + // int DSTORE_3 = 74; // - + // int ASTORE_0 = 75; // - + // int ASTORE_1 = 76; // - + // int ASTORE_2 = 77; // - + // int ASTORE_3 = 78; // - + int IASTORE = 79; // visitInsn + int LASTORE = 80; // - + int FASTORE = 81; // - + int DASTORE = 82; // - + int AASTORE = 83; // - + int BASTORE = 84; // - + int CASTORE = 85; // - + int SASTORE = 86; // - + int POP = 87; // - + int POP2 = 88; // - + int DUP = 89; // - + int DUP_X1 = 90; // - + int DUP_X2 = 91; // - + int DUP2 = 92; // - + int DUP2_X1 = 93; // - + int DUP2_X2 = 94; // - + int SWAP = 95; // - + int IADD = 96; // - + int LADD = 97; // - + int FADD = 98; // - + int DADD = 99; // - + int ISUB = 100; // - + int LSUB = 101; // - + int FSUB = 102; // - + int DSUB = 103; // - + int IMUL = 104; // - + int LMUL = 105; // - + int FMUL = 106; // - + int DMUL = 107; // - + int IDIV = 108; // - + int LDIV = 109; // - + int FDIV = 110; // - + int DDIV = 111; // - + int IREM = 112; // - + int LREM = 113; // - + int FREM = 114; // - + int DREM = 115; // - + int INEG = 116; // - + int LNEG = 117; // - + int FNEG = 118; // - + int DNEG = 119; // - + int ISHL = 120; // - + int LSHL = 121; // - + int ISHR = 122; // - + int LSHR = 123; // - + int IUSHR = 124; // - + int LUSHR = 125; // - + int IAND = 126; // - + int LAND = 127; // - + int IOR = 128; // - + int LOR = 129; // - + int IXOR = 130; // - + int LXOR = 131; // - + int IINC = 132; // visitIincInsn + int I2L = 133; // visitInsn + int I2F = 134; // - + int I2D = 135; // - + int L2I = 136; // - + int L2F = 137; // - + int L2D = 138; // - + int F2I = 139; // - + int F2L = 140; // - + int F2D = 141; // - + int D2I = 142; // - + int D2L = 143; // - + int D2F = 144; // - + int I2B = 145; // - + int I2C = 146; // - + int I2S = 147; // - + int LCMP = 148; // - + int FCMPL = 149; // - + int FCMPG = 150; // - + int DCMPL = 151; // - + int DCMPG = 152; // - + int IFEQ = 153; // visitJumpInsn + int IFNE = 154; // - + int IFLT = 155; // - + int IFGE = 156; // - + int IFGT = 157; // - + int IFLE = 158; // - + int IF_ICMPEQ = 159; // - + int IF_ICMPNE = 160; // - + int IF_ICMPLT = 161; // - + int IF_ICMPGE = 162; // - + int IF_ICMPGT = 163; // - + int IF_ICMPLE = 164; // - + int IF_ACMPEQ = 165; // - + int IF_ACMPNE = 166; // - + int GOTO = 167; // - + int JSR = 168; // - + int RET = 169; // visitVarInsn + int TABLESWITCH = 170; // visiTableSwitchInsn + int LOOKUPSWITCH = 171; // visitLookupSwitch + int IRETURN = 172; // visitInsn + int LRETURN = 173; // - + int FRETURN = 174; // - + int DRETURN = 175; // - + int ARETURN = 176; // - + int RETURN = 177; // - + int GETSTATIC = 178; // visitFieldInsn + int PUTSTATIC = 179; // - + int GETFIELD = 180; // - + int PUTFIELD = 181; // - + int INVOKEVIRTUAL = 182; // visitMethodInsn + int INVOKESPECIAL = 183; // - + int INVOKESTATIC = 184; // - + int INVOKEINTERFACE = 185; // - + int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn + int NEW = 187; // visitTypeInsn + int NEWARRAY = 188; // visitIntInsn + int ANEWARRAY = 189; // visitTypeInsn + int ARRAYLENGTH = 190; // visitInsn + int ATHROW = 191; // - + int CHECKCAST = 192; // visitTypeInsn + int INSTANCEOF = 193; // - + int MONITORENTER = 194; // visitInsn + int MONITOREXIT = 195; // - + // int WIDE = 196; // NOT VISITED + int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn + int IFNULL = 198; // visitJumpInsn + int IFNONNULL = 199; // - + // int GOTO_W = 200; // - + // int JSR_W = 201; // - +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Type.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Type.java new file mode 100644 index 00000000000..b7c7a7cf7f7 --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/Type.java @@ -0,0 +1,894 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +/** + * A Java field or method type. This class can be used to make it easier to + * manipulate type and method descriptors. + * + * @author Eric Bruneton + * @author Chris Nokleberg + */ +public class Type { + + /** + * The sort of the void type. See {@link #getSort getSort}. + */ + public static final int VOID = 0; + + /** + * The sort of the boolean type. See {@link #getSort getSort}. + */ + public static final int BOOLEAN = 1; + + /** + * The sort of the char type. See {@link #getSort getSort}. + */ + public static final int CHAR = 2; + + /** + * The sort of the byte type. See {@link #getSort getSort}. + */ + public static final int BYTE = 3; + + /** + * The sort of the short type. See {@link #getSort getSort}. + */ + public static final int SHORT = 4; + + /** + * The sort of the int type. See {@link #getSort getSort}. + */ + public static final int INT = 5; + + /** + * The sort of the float type. See {@link #getSort getSort}. + */ + public static final int FLOAT = 6; + + /** + * The sort of the long type. See {@link #getSort getSort}. + */ + public static final int LONG = 7; + + /** + * The sort of the double type. See {@link #getSort getSort}. + */ + public static final int DOUBLE = 8; + + /** + * The sort of array reference types. See {@link #getSort getSort}. + */ + public static final int ARRAY = 9; + + /** + * The sort of object reference types. See {@link #getSort getSort}. + */ + public static final int OBJECT = 10; + + /** + * The sort of method types. See {@link #getSort getSort}. + */ + public static final int METHOD = 11; + + /** + * The void type. + */ + public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24) + | (5 << 16) | (0 << 8) | 0, 1); + + /** + * The boolean type. + */ + public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24) + | (0 << 16) | (5 << 8) | 1, 1); + + /** + * The char type. + */ + public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24) + | (0 << 16) | (6 << 8) | 1, 1); + + /** + * The byte type. + */ + public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24) + | (0 << 16) | (5 << 8) | 1, 1); + + /** + * The short type. + */ + public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24) + | (0 << 16) | (7 << 8) | 1, 1); + + /** + * The int type. + */ + public static final Type INT_TYPE = new Type(INT, null, ('I' << 24) + | (0 << 16) | (0 << 8) | 1, 1); + + /** + * The float type. + */ + public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24) + | (2 << 16) | (2 << 8) | 1, 1); + + /** + * The long type. + */ + public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24) + | (1 << 16) | (1 << 8) | 2, 1); + + /** + * The double type. + */ + public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24) + | (3 << 16) | (3 << 8) | 2, 1); + + // ------------------------------------------------------------------------ + // Fields + // ------------------------------------------------------------------------ + + /** + * The sort of this Java type. + */ + private final int sort; + + /** + * A buffer containing the internal name of this Java type. This field is + * only used for reference types. + */ + private final char[] buf; + + /** + * The offset of the internal name of this Java type in {@link #buf buf} or, + * for primitive types, the size, descriptor and getOpcode offsets for this + * type (byte 0 contains the size, byte 1 the descriptor, byte 2 the offset + * for IALOAD or IASTORE, byte 3 the offset for all other instructions). + */ + private final int off; + + /** + * The length of the internal name of this Java type. + */ + private final int len; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructs a reference type. + * + * @param sort the sort of the reference type to be constructed. + * @param buf a buffer containing the descriptor of the previous type. + * @param off the offset of this descriptor in the previous buffer. + * @param len the length of this descriptor. + */ + private Type(final int sort, final char[] buf, final int off, final int len) + { + this.sort = sort; + this.buf = buf; + this.off = off; + this.len = len; + } + + /** + * Returns the Java type corresponding to the given type descriptor. + * + * @param typeDescriptor a field or method type descriptor. + * @return the Java type corresponding to the given type descriptor. + */ + public static Type getType(final String typeDescriptor) { + return getType(typeDescriptor.toCharArray(), 0); + } + + /** + * Returns the Java type corresponding to the given internal name. + * + * @param internalName an internal name. + * @return the Java type corresponding to the given internal name. + */ + public static Type getObjectType(final String internalName) { + char[] buf = internalName.toCharArray(); + return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length); + } + + /** + * Returns the Java type corresponding to the given method descriptor. + * Equivalent to Type.getType(methodDescriptor). + * + * @param methodDescriptor a method descriptor. + * @return the Java type corresponding to the given method descriptor. + */ + public static Type getMethodType(final String methodDescriptor) { + return getType(methodDescriptor.toCharArray(), 0); + } + + /** + * Returns the Java method type corresponding to the given argument and + * return types. + * + * @param returnType the return type of the method. + * @param argumentTypes the argument types of the method. + * @return the Java type corresponding to the given argument and return types. + */ + public static Type getMethodType(final Type returnType, final Type... argumentTypes) { + return getType(getMethodDescriptor(returnType, argumentTypes)); + } + + /** + * Returns the Java type corresponding to the given class. + * + * @param c a class. + * @return the Java type corresponding to the given class. + */ + public static Type getType(final Class c) { + if (c.isPrimitive()) { + if (c == Integer.TYPE) { + return INT_TYPE; + } else if (c == Void.TYPE) { + return VOID_TYPE; + } else if (c == Boolean.TYPE) { + return BOOLEAN_TYPE; + } else if (c == Byte.TYPE) { + return BYTE_TYPE; + } else if (c == Character.TYPE) { + return CHAR_TYPE; + } else if (c == Short.TYPE) { + return SHORT_TYPE; + } else if (c == Double.TYPE) { + return DOUBLE_TYPE; + } else if (c == Float.TYPE) { + return FLOAT_TYPE; + } else /* if (c == Long.TYPE) */{ + return LONG_TYPE; + } + } else { + return getType(getDescriptor(c)); + } + } + + /** + * Returns the Java method type corresponding to the given constructor. + * + * @param c a {@link Constructor Constructor} object. + * @return the Java method type corresponding to the given constructor. + */ + public static Type getType(final Constructor c) { + return getType(getConstructorDescriptor(c)); + } + + /** + * Returns the Java method type corresponding to the given method. + * + * @param m a {@link Method Method} object. + * @return the Java method type corresponding to the given method. + */ + public static Type getType(final Method m) { + return getType(getMethodDescriptor(m)); + } + + /** + * Returns the Java types corresponding to the argument types of the given + * method descriptor. + * + * @param methodDescriptor a method descriptor. + * @return the Java types corresponding to the argument types of the given + * method descriptor. + */ + public static Type[] getArgumentTypes(final String methodDescriptor) { + char[] buf = methodDescriptor.toCharArray(); + int off = 1; + int size = 0; + while (true) { + char car = buf[off++]; + if (car == ')') { + break; + } else if (car == 'L') { + while (buf[off++] != ';') { + } + ++size; + } else if (car != '[') { + ++size; + } + } + Type[] args = new Type[size]; + off = 1; + size = 0; + while (buf[off] != ')') { + args[size] = getType(buf, off); + off += args[size].len + (args[size].sort == OBJECT ? 2 : 0); + size += 1; + } + return args; + } + + /** + * Returns the Java types corresponding to the argument types of the given + * method. + * + * @param method a method. + * @return the Java types corresponding to the argument types of the given + * method. + */ + public static Type[] getArgumentTypes(final Method method) { + Class[] classes = method.getParameterTypes(); + Type[] types = new Type[classes.length]; + for (int i = classes.length - 1; i >= 0; --i) { + types[i] = getType(classes[i]); + } + return types; + } + + /** + * Returns the Java type corresponding to the return type of the given + * method descriptor. + * + * @param methodDescriptor a method descriptor. + * @return the Java type corresponding to the return type of the given + * method descriptor. + */ + public static Type getReturnType(final String methodDescriptor) { + char[] buf = methodDescriptor.toCharArray(); + return getType(buf, methodDescriptor.indexOf(')') + 1); + } + + /** + * Returns the Java type corresponding to the return type of the given + * method. + * + * @param method a method. + * @return the Java type corresponding to the return type of the given + * method. + */ + public static Type getReturnType(final Method method) { + return getType(method.getReturnType()); + } + + /** + * Computes the size of the arguments and of the return value of a method. + * + * @param desc the descriptor of a method. + * @return the size of the arguments of the method (plus one for the + * implicit this argument), argSize, and the size of its return + * value, retSize, packed into a single int i = + * (argSize << 2) | retSize (argSize is therefore equal + * to i >> 2, and retSize to i & 0x03). + */ + public static int getArgumentsAndReturnSizes(final String desc) { + int n = 1; + int c = 1; + while (true) { + char car = desc.charAt(c++); + if (car == ')') { + car = desc.charAt(c); + return n << 2 + | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1)); + } else if (car == 'L') { + while (desc.charAt(c++) != ';') { + } + n += 1; + } else if (car == '[') { + while ((car = desc.charAt(c)) == '[') { + ++c; + } + if (car == 'D' || car == 'J') { + n -= 1; + } + } else if (car == 'D' || car == 'J') { + n += 2; + } else { + n += 1; + } + } + } + + /** + * Returns the Java type corresponding to the given type descriptor. For + * method descriptors, buf is supposed to contain nothing more than the + * descriptor itself. + * + * @param buf a buffer containing a type descriptor. + * @param off the offset of this descriptor in the previous buffer. + * @return the Java type corresponding to the given type descriptor. + */ + private static Type getType(final char[] buf, final int off) { + int len; + switch (buf[off]) { + case 'V': + return VOID_TYPE; + case 'Z': + return BOOLEAN_TYPE; + case 'C': + return CHAR_TYPE; + case 'B': + return BYTE_TYPE; + case 'S': + return SHORT_TYPE; + case 'I': + return INT_TYPE; + case 'F': + return FLOAT_TYPE; + case 'J': + return LONG_TYPE; + case 'D': + return DOUBLE_TYPE; + case '[': + len = 1; + while (buf[off + len] == '[') { + ++len; + } + if (buf[off + len] == 'L') { + ++len; + while (buf[off + len] != ';') { + ++len; + } + } + return new Type(ARRAY, buf, off, len + 1); + case 'L': + len = 1; + while (buf[off + len] != ';') { + ++len; + } + return new Type(OBJECT, buf, off + 1, len - 1); + // case '(': + default: + return new Type(METHOD, buf, 0, buf.length); + } + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + /** + * Returns the sort of this Java type. + * + * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, + * {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT SHORT}, + * {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG}, + * {@link #DOUBLE DOUBLE}, {@link #ARRAY ARRAY}, + * {@link #OBJECT OBJECT} or {@link #METHOD METHOD}. + */ + public int getSort() { + return sort; + } + + /** + * Returns the number of dimensions of this array type. This method should + * only be used for an array type. + * + * @return the number of dimensions of this array type. + */ + public int getDimensions() { + int i = 1; + while (buf[off + i] == '[') { + ++i; + } + return i; + } + + /** + * Returns the type of the elements of this array type. This method should + * only be used for an array type. + * + * @return Returns the type of the elements of this array type. + */ + public Type getElementType() { + return getType(buf, off + getDimensions()); + } + + /** + * Returns the binary name of the class corresponding to this type. This + * method must not be used on method types. + * + * @return the binary name of the class corresponding to this type. + */ + public String getClassName() { + switch (sort) { + case VOID: + return "void"; + case BOOLEAN: + return "boolean"; + case CHAR: + return "char"; + case BYTE: + return "byte"; + case SHORT: + return "short"; + case INT: + return "int"; + case FLOAT: + return "float"; + case LONG: + return "long"; + case DOUBLE: + return "double"; + case ARRAY: + StringBuffer b = new StringBuffer(getElementType().getClassName()); + for (int i = getDimensions(); i > 0; --i) { + b.append("[]"); + } + return b.toString(); + case OBJECT: + return new String(buf, off, len).replace('/', '.'); + default: + return null; + } + } + + /** + * Returns the internal name of the class corresponding to this object or + * array type. The internal name of a class is its fully qualified name (as + * returned by Class.getName(), where '.' are replaced by '/'. This method + * should only be used for an object or array type. + * + * @return the internal name of the class corresponding to this object type. + */ + public String getInternalName() { + return new String(buf, off, len); + } + + /** + * Returns the argument types of methods of this type. This method should + * only be used for method types. + * + * @return the argument types of methods of this type. + */ + public Type[] getArgumentTypes() { + return getArgumentTypes(getDescriptor()); + } + + /** + * Returns the return type of methods of this type. This method should only + * be used for method types. + * + * @return the return type of methods of this type. + */ + public Type getReturnType() { + return getReturnType(getDescriptor()); + } + + /** + * Returns the size of the arguments and of the return value of methods of + * this type. This method should only be used for method types. + * + * @return the size of the arguments (plus one for the implicit this + * argument), argSize, and the size of the return value, retSize, + * packed into a single int i = (argSize << 2) | retSize + * (argSize is therefore equal to i >> 2, and retSize to + * i & 0x03). + */ + public int getArgumentsAndReturnSizes() { + return getArgumentsAndReturnSizes(getDescriptor()); + } + + // ------------------------------------------------------------------------ + // Conversion to type descriptors + // ------------------------------------------------------------------------ + + /** + * Returns the descriptor corresponding to this Java type. + * + * @return the descriptor corresponding to this Java type. + */ + public String getDescriptor() { + StringBuffer buf = new StringBuffer(); + getDescriptor(buf); + return buf.toString(); + } + + /** + * Returns the descriptor corresponding to the given argument and return + * types. + * + * @param returnType the return type of the method. + * @param argumentTypes the argument types of the method. + * @return the descriptor corresponding to the given argument and return + * types. + */ + public static String getMethodDescriptor( + final Type returnType, + final Type... argumentTypes) + { + StringBuffer buf = new StringBuffer(); + buf.append('('); + for (int i = 0; i < argumentTypes.length; ++i) { + argumentTypes[i].getDescriptor(buf); + } + buf.append(')'); + returnType.getDescriptor(buf); + return buf.toString(); + } + + /** + * Appends the descriptor corresponding to this Java type to the given + * string buffer. + * + * @param buf the string buffer to which the descriptor must be appended. + */ + private void getDescriptor(final StringBuffer buf) { + if (this.buf == null) { + // descriptor is in byte 3 of 'off' for primitive types (buf == null) + buf.append((char) ((off & 0xFF000000) >>> 24)); + } else if (sort == OBJECT) { + buf.append('L'); + buf.append(this.buf, off, len); + buf.append(';'); + } else { // sort == ARRAY || sort == METHOD + buf.append(this.buf, off, len); + } + } + + // ------------------------------------------------------------------------ + // Direct conversion from classes to type descriptors, + // without intermediate Type objects + // ------------------------------------------------------------------------ + + /** + * Returns the internal name of the given class. The internal name of a + * class is its fully qualified name, as returned by Class.getName(), where + * '.' are replaced by '/'. + * + * @param c an object or array class. + * @return the internal name of the given class. + */ + public static String getInternalName(final Class c) { + return c.getName().replace('.', '/'); + } + + /** + * Returns the descriptor corresponding to the given Java type. + * + * @param c an object class, a primitive class or an array class. + * @return the descriptor corresponding to the given class. + */ + public static String getDescriptor(final Class c) { + StringBuffer buf = new StringBuffer(); + getDescriptor(buf, c); + return buf.toString(); + } + + /** + * Returns the descriptor corresponding to the given constructor. + * + * @param c a {@link Constructor Constructor} object. + * @return the descriptor of the given constructor. + */ + public static String getConstructorDescriptor(final Constructor c) { + Class[] parameters = c.getParameterTypes(); + StringBuffer buf = new StringBuffer(); + buf.append('('); + for (int i = 0; i < parameters.length; ++i) { + getDescriptor(buf, parameters[i]); + } + return buf.append(")V").toString(); + } + + /** + * Returns the descriptor corresponding to the given method. + * + * @param m a {@link Method Method} object. + * @return the descriptor of the given method. + */ + public static String getMethodDescriptor(final Method m) { + Class[] parameters = m.getParameterTypes(); + StringBuffer buf = new StringBuffer(); + buf.append('('); + for (int i = 0; i < parameters.length; ++i) { + getDescriptor(buf, parameters[i]); + } + buf.append(')'); + getDescriptor(buf, m.getReturnType()); + return buf.toString(); + } + + /** + * Appends the descriptor of the given class to the given string buffer. + * + * @param buf the string buffer to which the descriptor must be appended. + * @param c the class whose descriptor must be computed. + */ + private static void getDescriptor(final StringBuffer buf, final Class c) { + Class d = c; + while (true) { + if (d.isPrimitive()) { + char car; + if (d == Integer.TYPE) { + car = 'I'; + } else if (d == Void.TYPE) { + car = 'V'; + } else if (d == Boolean.TYPE) { + car = 'Z'; + } else if (d == Byte.TYPE) { + car = 'B'; + } else if (d == Character.TYPE) { + car = 'C'; + } else if (d == Short.TYPE) { + car = 'S'; + } else if (d == Double.TYPE) { + car = 'D'; + } else if (d == Float.TYPE) { + car = 'F'; + } else /* if (d == Long.TYPE) */{ + car = 'J'; + } + buf.append(car); + return; + } else if (d.isArray()) { + buf.append('['); + d = d.getComponentType(); + } else { + buf.append('L'); + String name = d.getName(); + int len = name.length(); + for (int i = 0; i < len; ++i) { + char car = name.charAt(i); + buf.append(car == '.' ? '/' : car); + } + buf.append(';'); + return; + } + } + } + + // ------------------------------------------------------------------------ + // Corresponding size and opcodes + // ------------------------------------------------------------------------ + + /** + * Returns the size of values of this type. This method must not be used for + * method types. + * + * @return the size of values of this type, i.e., 2 for long and + * double, 0 for void and 1 otherwise. + */ + public int getSize() { + // the size is in byte 0 of 'off' for primitive types (buf == null) + return buf == null ? (off & 0xFF) : 1; + } + + /** + * Returns a JVM instruction opcode adapted to this Java type. This method + * must not be used for method types. + * + * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, + * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL, + * ISHR, IUSHR, IAND, IOR, IXOR and IRETURN. + * @return an opcode that is similar to the given opcode, but adapted to + * this Java type. For example, if this type is float and + * opcode is IRETURN, this method returns FRETURN. + */ + public int getOpcode(final int opcode) { + if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { + // the offset for IALOAD or IASTORE is in byte 1 of 'off' for + // primitive types (buf == null) + return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4); + } else { + // the offset for other instructions is in byte 2 of 'off' for + // primitive types (buf == null) + return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4); + } + } + + // ------------------------------------------------------------------------ + // Equals, hashCode and toString + // ------------------------------------------------------------------------ + + /** + * Tests if the given object is equal to this type. + * + * @param o the object to be compared to this type. + * @return true if the given object is equal to this type. + */ + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Type)) { + return false; + } + Type t = (Type) o; + if (sort != t.sort) { + return false; + } + if (sort >= ARRAY) { + if (len != t.len) { + return false; + } + for (int i = off, j = t.off, end = i + len; i < end; i++, j++) { + if (buf[i] != t.buf[j]) { + return false; + } + } + } + return true; + } + + /** + * Returns a hash code value for this type. + * + * @return a hash code value for this type. + */ + @Override + public int hashCode() { + int hc = 13 * sort; + if (sort >= ARRAY) { + for (int i = off, end = i + len; i < end; i++) { + hc = 17 * (hc + buf[i]); + } + } + return hc; + } + + /** + * Returns a string representation of this type. + * + * @return the descriptor of this type. + */ + @Override + public String toString() { + return getDescriptor(); + } +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java new file mode 100644 index 00000000000..dd6f26035f9 --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java @@ -0,0 +1,694 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * Copyright (c) 2011 Google + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm.commons; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.Type; + +/** + * A {@link jdk.internal.org.objectweb.asm.MethodVisitor} to insert before, after and around + * advices in methods and constructors.

    The behavior for constructors is + * like this:

      + * + *
    1. as long as the INVOKESPECIAL for the object initialization has not been + * reached, every bytecode instruction is dispatched in the ctor code visitor
    2. + * + *
    3. when this one is reached, it is only added in the ctor code visitor and + * a JP invoke is added
    4. + * + *
    5. after that, only the other code visitor receives the instructions
    6. + * + *
    + * + * @author Eugene Kuleshov + * @author Eric Bruneton + */ +public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes +{ + + private static final Object THIS = new Object(); + + private static final Object OTHER = new Object(); + + protected int methodAccess; + + protected String methodDesc; + + private boolean constructor; + + private boolean superInitialized; + + private List stackFrame; + + private Map> branches; + + /** + * Creates a new {@link AdviceAdapter}. + * + * @param api the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param mv the method visitor to which this adapter delegates calls. + * @param access the method's access flags (see {@link Opcodes}). + * @param name the method's name. + * @param desc the method's descriptor (see {@link Type Type}). + */ + protected AdviceAdapter( + final int api, + final MethodVisitor mv, + final int access, + final String name, + final String desc) + { + super(api, mv, access, name, desc); + methodAccess = access; + methodDesc = desc; + constructor = "".equals(name); + } + + @Override + public void visitCode() { + mv.visitCode(); + if (constructor) { + stackFrame = new ArrayList(); + branches = new HashMap>(); + } else { + superInitialized = true; + onMethodEnter(); + } + } + + @Override + public void visitLabel(final Label label) { + mv.visitLabel(label); + if (constructor && branches != null) { + List frame = branches.get(label); + if (frame != null) { + stackFrame = frame; + branches.remove(label); + } + } + } + + @Override + public void visitInsn(final int opcode) { + if (constructor) { + int s; + switch (opcode) { + case RETURN: // empty stack + onMethodExit(opcode); + break; + + case IRETURN: // 1 before n/a after + case FRETURN: // 1 before n/a after + case ARETURN: // 1 before n/a after + case ATHROW: // 1 before n/a after + popValue(); + onMethodExit(opcode); + break; + + case LRETURN: // 2 before n/a after + case DRETURN: // 2 before n/a after + popValue(); + popValue(); + onMethodExit(opcode); + break; + + case NOP: + case LALOAD: // remove 2 add 2 + case DALOAD: // remove 2 add 2 + case LNEG: + case DNEG: + case FNEG: + case INEG: + case L2D: + case D2L: + case F2I: + case I2B: + case I2C: + case I2S: + case I2F: + case ARRAYLENGTH: + break; + + case ACONST_NULL: + case ICONST_M1: + case ICONST_0: + case ICONST_1: + case ICONST_2: + case ICONST_3: + case ICONST_4: + case ICONST_5: + case FCONST_0: + case FCONST_1: + case FCONST_2: + case F2L: // 1 before 2 after + case F2D: + case I2L: + case I2D: + pushValue(OTHER); + break; + + case LCONST_0: + case LCONST_1: + case DCONST_0: + case DCONST_1: + pushValue(OTHER); + pushValue(OTHER); + break; + + case IALOAD: // remove 2 add 1 + case FALOAD: // remove 2 add 1 + case AALOAD: // remove 2 add 1 + case BALOAD: // remove 2 add 1 + case CALOAD: // remove 2 add 1 + case SALOAD: // remove 2 add 1 + case POP: + case IADD: + case FADD: + case ISUB: + case LSHL: // 3 before 2 after + case LSHR: // 3 before 2 after + case LUSHR: // 3 before 2 after + case L2I: // 2 before 1 after + case L2F: // 2 before 1 after + case D2I: // 2 before 1 after + case D2F: // 2 before 1 after + case FSUB: + case FMUL: + case FDIV: + case FREM: + case FCMPL: // 2 before 1 after + case FCMPG: // 2 before 1 after + case IMUL: + case IDIV: + case IREM: + case ISHL: + case ISHR: + case IUSHR: + case IAND: + case IOR: + case IXOR: + case MONITORENTER: + case MONITOREXIT: + popValue(); + break; + + case POP2: + case LSUB: + case LMUL: + case LDIV: + case LREM: + case LADD: + case LAND: + case LOR: + case LXOR: + case DADD: + case DMUL: + case DSUB: + case DDIV: + case DREM: + popValue(); + popValue(); + break; + + case IASTORE: + case FASTORE: + case AASTORE: + case BASTORE: + case CASTORE: + case SASTORE: + case LCMP: // 4 before 1 after + case DCMPL: + case DCMPG: + popValue(); + popValue(); + popValue(); + break; + + case LASTORE: + case DASTORE: + popValue(); + popValue(); + popValue(); + popValue(); + break; + + case DUP: + pushValue(peekValue()); + break; + + case DUP_X1: + s = stackFrame.size(); + stackFrame.add(s - 2, stackFrame.get(s - 1)); + break; + + case DUP_X2: + s = stackFrame.size(); + stackFrame.add(s - 3, stackFrame.get(s - 1)); + break; + + case DUP2: + s = stackFrame.size(); + stackFrame.add(s - 2, stackFrame.get(s - 1)); + stackFrame.add(s - 2, stackFrame.get(s - 1)); + break; + + case DUP2_X1: + s = stackFrame.size(); + stackFrame.add(s - 3, stackFrame.get(s - 1)); + stackFrame.add(s - 3, stackFrame.get(s - 1)); + break; + + case DUP2_X2: + s = stackFrame.size(); + stackFrame.add(s - 4, stackFrame.get(s - 1)); + stackFrame.add(s - 4, stackFrame.get(s - 1)); + break; + + case SWAP: + s = stackFrame.size(); + stackFrame.add(s - 2, stackFrame.get(s - 1)); + stackFrame.remove(s); + break; + } + } else { + switch (opcode) { + case RETURN: + case IRETURN: + case FRETURN: + case ARETURN: + case LRETURN: + case DRETURN: + case ATHROW: + onMethodExit(opcode); + break; + } + } + mv.visitInsn(opcode); + } + + @Override + public void visitVarInsn(final int opcode, final int var) { + super.visitVarInsn(opcode, var); + if (constructor) { + switch (opcode) { + case ILOAD: + case FLOAD: + pushValue(OTHER); + break; + case LLOAD: + case DLOAD: + pushValue(OTHER); + pushValue(OTHER); + break; + case ALOAD: + pushValue(var == 0 ? THIS : OTHER); + break; + case ASTORE: + case ISTORE: + case FSTORE: + popValue(); + break; + case LSTORE: + case DSTORE: + popValue(); + popValue(); + break; + } + } + } + + @Override + public void visitFieldInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + mv.visitFieldInsn(opcode, owner, name, desc); + if (constructor) { + char c = desc.charAt(0); + boolean longOrDouble = c == 'J' || c == 'D'; + switch (opcode) { + case GETSTATIC: + pushValue(OTHER); + if (longOrDouble) { + pushValue(OTHER); + } + break; + case PUTSTATIC: + popValue(); + if (longOrDouble) { + popValue(); + } + break; + case PUTFIELD: + popValue(); + if (longOrDouble) { + popValue(); + popValue(); + } + break; + // case GETFIELD: + default: + if (longOrDouble) { + pushValue(OTHER); + } + } + } + } + + @Override + public void visitIntInsn(final int opcode, final int operand) { + mv.visitIntInsn(opcode, operand); + if (constructor && opcode != NEWARRAY) { + pushValue(OTHER); + } + } + + @Override + public void visitLdcInsn(final Object cst) { + mv.visitLdcInsn(cst); + if (constructor) { + pushValue(OTHER); + if (cst instanceof Double || cst instanceof Long) { + pushValue(OTHER); + } + } + } + + @Override + public void visitMultiANewArrayInsn(final String desc, final int dims) { + mv.visitMultiANewArrayInsn(desc, dims); + if (constructor) { + for (int i = 0; i < dims; i++) { + popValue(); + } + pushValue(OTHER); + } + } + + @Override + public void visitTypeInsn(final int opcode, final String type) { + mv.visitTypeInsn(opcode, type); + // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack + if (constructor && opcode == NEW) { + pushValue(OTHER); + } + } + + @Override + public void visitMethodInsn( + final int opcode, + final String owner, + final String name, + final String desc) + { + mv.visitMethodInsn(opcode, owner, name, desc); + if (constructor) { + Type[] types = Type.getArgumentTypes(desc); + for (int i = 0; i < types.length; i++) { + popValue(); + if (types[i].getSize() == 2) { + popValue(); + } + } + switch (opcode) { + // case INVOKESTATIC: + // break; + + case INVOKEINTERFACE: + case INVOKEVIRTUAL: + popValue(); // objectref + break; + + case INVOKESPECIAL: + Object type = popValue(); // objectref + if (type == THIS && !superInitialized) { + onMethodEnter(); + superInitialized = true; + // once super has been initialized it is no longer + // necessary to keep track of stack state + constructor = false; + } + break; + } + + Type returnType = Type.getReturnType(desc); + if (returnType != Type.VOID_TYPE) { + pushValue(OTHER); + if (returnType.getSize() == 2) { + pushValue(OTHER); + } + } + } + } + + @Override + public void visitInvokeDynamicInsn( + String name, + String desc, + Handle bsm, + Object... bsmArgs) + { + mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); + if (constructor) { + Type[] types = Type.getArgumentTypes(desc); + for (int i = 0; i < types.length; i++) { + popValue(); + if (types[i].getSize() == 2) { + popValue(); + } + } + + Type returnType = Type.getReturnType(desc); + if (returnType != Type.VOID_TYPE) { + pushValue(OTHER); + if (returnType.getSize() == 2) { + pushValue(OTHER); + } + } + } + } + + @Override + public void visitJumpInsn(final int opcode, final Label label) { + mv.visitJumpInsn(opcode, label); + if (constructor) { + switch (opcode) { + case IFEQ: + case IFNE: + case IFLT: + case IFGE: + case IFGT: + case IFLE: + case IFNULL: + case IFNONNULL: + popValue(); + break; + + case IF_ICMPEQ: + case IF_ICMPNE: + case IF_ICMPLT: + case IF_ICMPGE: + case IF_ICMPGT: + case IF_ICMPLE: + case IF_ACMPEQ: + case IF_ACMPNE: + popValue(); + popValue(); + break; + + case JSR: + pushValue(OTHER); + break; + } + addBranch(label); + } + } + + @Override + public void visitLookupSwitchInsn( + final Label dflt, + final int[] keys, + final Label[] labels) + { + mv.visitLookupSwitchInsn(dflt, keys, labels); + if (constructor) { + popValue(); + addBranches(dflt, labels); + } + } + + @Override + public void visitTableSwitchInsn( + final int min, + final int max, + final Label dflt, + final Label... labels) + { + mv.visitTableSwitchInsn(min, max, dflt, labels); + if (constructor) { + popValue(); + addBranches(dflt, labels); + } + } + + @Override + public void visitTryCatchBlock( + Label start, + Label end, + Label handler, + String type) + { + super.visitTryCatchBlock(start, end, handler, type); + if (constructor && !branches.containsKey(handler)) { + List stackFrame = new ArrayList(); + stackFrame.add(OTHER); + branches.put(handler, stackFrame); + } + } + + private void addBranches(final Label dflt, final Label[] labels) { + addBranch(dflt); + for (int i = 0; i < labels.length; i++) { + addBranch(labels[i]); + } + } + + private void addBranch(final Label label) { + if (branches.containsKey(label)) { + return; + } + branches.put(label, new ArrayList(stackFrame)); + } + + private Object popValue() { + return stackFrame.remove(stackFrame.size() - 1); + } + + private Object peekValue() { + return stackFrame.get(stackFrame.size() - 1); + } + + private void pushValue(final Object o) { + stackFrame.add(o); + } + + /** + * Called at the beginning of the method or after super class class call in + * the constructor.

    + * + * Custom code can use or change all the local variables, but should not + * change state of the stack. + */ + protected void onMethodEnter() { + } + + /** + * Called before explicit exit from the method using either return or throw. + * Top element on the stack contains the return value or exception instance. + * For example: + * + *
    +     *   public void onMethodExit(int opcode) {
    +     *     if(opcode==RETURN) {
    +     *         visitInsn(ACONST_NULL);
    +     *     } else if(opcode==ARETURN || opcode==ATHROW) {
    +     *         dup();
    +     *     } else {
    +     *         if(opcode==LRETURN || opcode==DRETURN) {
    +     *             dup2();
    +     *         } else {
    +     *             dup();
    +     *         }
    +     *         box(Type.getReturnType(this.methodDesc));
    +     *     }
    +     *     visitIntInsn(SIPUSH, opcode);
    +     *     visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
    +     *   }
    +     *
    +     *   // an actual call back method
    +     *   public static void onExit(Object param, int opcode) {
    +     *     ...
    +     * 
    + * + *

    + * + * Custom code can use or change all the local variables, but should not + * change state of the stack. + * + * @param opcode one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, + * DRETURN or ATHROW + * + */ + protected void onMethodExit(int opcode) { + } + + // TODO onException, onMethodCall +} diff --git a/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.java b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.java new file mode 100644 index 00000000000..c6861410bf1 --- /dev/null +++ b/jdk/src/share/classes/jdk/internal/org/objectweb/asm/commons/AnalyzerAdapter.java @@ -0,0 +1,975 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the copyright holders 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. + */ +package jdk.internal.org.objectweb.asm.commons; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.Type; + +/** + * A {@link MethodVisitor} that keeps track of stack map frame changes between + * {@link #visitFrame(int, int, Object[], int, Object[]) visitFrame} calls. This + * adapter must be used with the + * {@link jdk.internal.org.objectweb.asm.ClassReader#EXPAND_FRAMES} option. Each visitX + * instruction delegates to the next visitor in the chain, if any, and then + * simulates the effect of this instruction on the stack map frame, represented + * by {@link #locals} and {@link #stack}. The next visitor in the chain can get + * the state of the stack map frame before each instruction by reading + * the value of these fields in its visitX methods (this requires a + * reference to the AnalyzerAdapter that is before it in the chain). + * If this adapter is used with a class that does not contain stack map table + * attributes (i.e., pre Java 6 classes) then this adapter may not be able to + * compute the stack map frame for each instruction. In this case no exception + * is thrown but the {@link #locals} and {@link #stack} fields will be null for + * these instructions. + * + * @author Eric Bruneton + */ +public class AnalyzerAdapter extends MethodVisitor { + + /** + * List of the local variable slots for current execution + * frame. Primitive types are represented by {@link Opcodes#TOP}, + * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, + * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or + * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a + * two elements, the second one being TOP). Reference types are represented + * by String objects (representing internal names), and uninitialized types + * by Label objects (this label designates the NEW instruction that created + * this uninitialized value). This field is null for unreacheable + * instructions. + */ + public List locals; + + /** + * List of the operand stack slots for current execution + * frame. Primitive types are represented by {@link Opcodes#TOP}, + * {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, + * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or + * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a + * two elements, the second one being TOP). Reference types are represented + * by String objects (representing internal names), and uninitialized types + * by Label objects (this label designates the NEW instruction that created + * this uninitialized value). This field is null for unreacheable + * instructions. + */ + public List stack; + + /** + * The labels that designate the next instruction to be visited. May be + * null. + */ + private List